Skip to content

Escape referenced names in BCELFactory Java output#501

Merged
garydgregory merged 2 commits into
apache:masterfrom
rootvector2:bcelfactory-escape-names
Jun 15, 2026
Merged

Escape referenced names in BCELFactory Java output#501
garydgregory merged 2 commits into
apache:masterfrom
rootvector2:bcelfactory-escape-names

Conversation

@rootvector2

Copy link
Copy Markdown
Contributor

comparing createConstant (which escapes string LDC operands via Utility.convertString) against the sibling createNew/createFieldAccess/createInvoke emitters shows those write referenced class, field and method names raw, so a crafted constant-pool name such as foo"); exec(...); il.append(" breaks out of the generated string literal and injects code into the BCELifier output, which the same helper now prevents.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR hardens the BCELifier Java-source output against code injection by escaping constant-pool-derived names before embedding them into generated Java string literals.

Changes:

  • Escape ObjectType class names when emitting PUSH constants in BCELFactory.
  • Escape referenced class/field/method names when emitting createNew, createFieldAccess, and createInvoke statements in BCELFactory.
  • Add a regression test that constructs a class with a hostile constant-pool method name and verifies the generated BCELifier output contains the escaped form (and not the raw injected form).

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
src/main/java/org/apache/bcel/util/BCELFactory.java Escapes class/field/method names before embedding them into generated Java string literals.
src/test/java/org/apache/bcel/util/BCELifierTest.java Adds a regression test to ensure hostile constant-pool method names are escaped in BCELifier output.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +311 to +312
assertTrue(source.contains(Utility.convertString(evilName)), source);
assertFalse(source.contains('"' + evilName + '"'), source);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rootvector2
WDYT?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

makes sense. tightened it to assert the escaped name appears as the quoted createInvoke argument instead of just anywhere in the output.

Comment on lines +292 to +306
void testCreateInvokeEscapesConstantPoolName() throws Exception {
// A hostile constant pool can hold any UTF-8 as a referenced method name.
final String evilName = "evil\"); System.exit(1); il.append(\"";
final ClassGen cg = new ClassGen("Example", "java.lang.Object", "Example.java", Const.ACC_PUBLIC | Const.ACC_SUPER, new String[] {});
final ConstantPoolGen cp = cg.getConstantPool();
final InstructionFactory factory = new InstructionFactory(cg, cp);
final InstructionList il = new InstructionList();
il.append(InstructionConst.ALOAD_0);
il.append(factory.createInvoke("java.lang.Object", evilName, Type.VOID, Type.NO_ARGS, Const.INVOKEVIRTUAL));
il.append(InstructionConst.RETURN);
final MethodGen mg = new MethodGen(Const.ACC_PUBLIC, Type.VOID, Type.NO_ARGS, new String[] {}, "m", "Example", il, cp);
mg.setMaxStack();
mg.setMaxLocals();
cg.addMethod(mg.getMethod());

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rootvector2
WDYT?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep, real gap. same root cause as the createInvoke case: BCELifier writes constant-pool-derived names straight into the generated string literals. pushed a follow-up that routes the class/superclass/source-file/interface names, the MethodGen method and class names, exception names, argument names and the stackmap names through Utility.convertString too. added tests for the method declaration name and the class/source-file cases.

@garydgregory garydgregory changed the title escape referenced names in BCELFactory java output Escape referenced names in BCELFactory java output Jun 15, 2026
@garydgregory garydgregory merged commit 63df9b9 into apache:master Jun 15, 2026
19 checks passed
@garydgregory garydgregory changed the title Escape referenced names in BCELFactory java output Escape referenced names in BCELFactory Java output Jun 15, 2026
@Test
void testCreateInvokeEscapesConstantPoolName() throws Exception {
// A hostile constant pool can hold any UTF-8 as a referenced method name.
final String evilName = "evil\"); System.exit(1); il.append(\"";

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rootvector2
In the future, please avoid the FUD and use meaningful named like "content" or "escapeExpected".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants