Skip to content

Commit 53e4f70

Browse files
Fix verify error when ctor params are used after a call site (#9083)
* Fix verify error when ctor params are used after a call site * Keep tests separated
1 parent 1ff2148 commit 53e4f70

File tree

7 files changed

+71
-7
lines changed

7 files changed

+71
-7
lines changed

dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/csi/Advices.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,8 @@ void onConstantPool(
370370
@Nonnull TypeDescription type, @Nonnull ConstantPool pool, final byte[] classFile);
371371
}
372372

373-
private interface TypedAdvice {
373+
// Kept public only for testing
374+
public interface TypedAdvice {
374375
byte getType();
375376

376377
static CallSiteAdvice withType(final CallSiteAdvice advice, final byte type) {

dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/csi/CallSiteTransformer.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -360,10 +360,12 @@ public void visitMethodInsn(
360360
@Override
361361
public void advice(final String owner, final String name, final String descriptor) {
362362
if (isSuperCall) {
363-
// append this to the stack after super call
364-
mv.visitIntInsn(Opcodes.ALOAD, 0);
363+
mv.visitIntInsn(Opcodes.ALOAD, 0); // append this to the stack after super call
364+
mv.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, descriptor, false);
365+
mv.visitInsn(Opcodes.POP); // pop the result of the advice call
366+
} else {
367+
mv.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, descriptor, false);
365368
}
366-
mv.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, descriptor, false);
367369
}
368370

369371
@Override

dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/csi/BaseCallSiteTest.groovy

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ class BaseCallSiteTest extends DDSpecification {
5454
advices
5555
.computeIfAbsent(owner, t -> [:])
5656
.computeIfAbsent(method, m -> [:])
57-
.put(descriptor, advice)
57+
.put(descriptor, Advices.TypedAdvice.withType(advice, type))
5858
}
5959
addHelpers(_ as String[]) >> {
6060
Collections.addAll(helpers, it[0] as String[])
@@ -83,6 +83,9 @@ class BaseCallSiteTest extends DDSpecification {
8383
getHelpers() >> {
8484
helpers as String[]
8585
}
86+
typeOf(_ as CallSiteAdvice) >> {
87+
((Advices.TypedAdvice) it[0]).type
88+
}
8689
}
8790
}
8891

dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/csi/CallSiteInstrumentationTest.groovy

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ class CallSiteInstrumentationTest extends BaseCallSiteTest {
6868
0 * builder.visit(_ as AsmVisitorWrapper) >> builder
6969
}
7070

71-
void 'test call site transformer with super call in ctor'() {
71+
void 'test call site transformer with super call in ctor (#test)'() {
7272
setup:
7373
SuperInCtorExampleAdvice.CALLS.set(0)
7474
final source = Type.getType(SuperInCtorExample)
@@ -91,11 +91,16 @@ class CallSiteInstrumentationTest extends BaseCallSiteTest {
9191
when:
9292
final transformedClass = transformType(source, target, callSiteTransformer)
9393
final transformed = loadClass(target, transformedClass)
94-
final reader = transformed.newInstance("test")
94+
final reader = transformed.newInstance(param)
9595
9696
then:
9797
reader != null
9898
SuperInCtorExampleAdvice.CALLS.get() > 0
99+
100+
where:
101+
param | test
102+
"test" | "Operand stack underflow"
103+
new StringBuilder("test") | "Inconsistent stackmap frames"
99104
}
100105
101106
static class StringCallSites implements CallSites, TestCallSites {

dd-java-agent/agent-tooling/src/test/java/datadog/trace/agent/tooling/csi/SuperInCtorExample.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,15 @@
55
public class SuperInCtorExample extends StringReader {
66

77
public SuperInCtorExample(String s) {
8+
// triggers APPSEC-55918
89
super(s + new StringReader(s + "Test" + new StringBuilder("another test")));
910
}
11+
12+
public SuperInCtorExample(StringBuilder s) {
13+
super(s.toString());
14+
// triggers APPSEC-58131
15+
if (s.length() == 0) {
16+
throw new IllegalArgumentException();
17+
}
18+
}
1019
}

dd-java-agent/instrumentation/java-io/src/test/groovy/datadog/trace/instrumentation/java/io/InputStreamReaderCallSiteTest.groovy

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package datadog.trace.instrumentation.java.io
22

33
import datadog.trace.api.iast.InstrumentationBridge
44
import datadog.trace.api.iast.propagation.PropagationModule
5+
import foo.bar.TestCustomInputStreamReader
56
import foo.bar.TestInputStreamReaderSuite
67

78
import java.nio.charset.Charset
@@ -27,4 +28,21 @@ class InputStreamReaderCallSiteTest extends BaseIoCallSiteTest{
2728
[new ByteArrayInputStream("test".getBytes())]// Reader input
2829
]
2930
}
31+
32+
void 'test InputStreamReader.<init> with super call and parameter'(){
33+
// XXX: Do not modify the constructor call here. Regression test for APPSEC-58131.
34+
given:
35+
PropagationModule iastModule = Mock(PropagationModule)
36+
InstrumentationBridge.registerIastModule(iastModule)
37+
38+
when:
39+
new TestCustomInputStreamReader(*args)
40+
41+
then:
42+
1 * iastModule.taintObjectIfTainted(_ as InputStreamReader, _ as InputStream)
43+
0 * _
44+
45+
where:
46+
args << [[new ByteArrayInputStream("test".getBytes()), Charset.defaultCharset()],]
47+
}
3048
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package foo.bar;
2+
3+
import java.io.IOException;
4+
import java.io.InputStream;
5+
import java.io.InputStreamReader;
6+
import java.nio.charset.Charset;
7+
8+
public class TestCustomInputStreamReader extends InputStreamReader {
9+
10+
public TestCustomInputStreamReader(final InputStream in) throws IOException {
11+
super(in);
12+
}
13+
14+
public TestCustomInputStreamReader(final InputStream in, final Charset charset)
15+
throws IOException {
16+
// XXX: DO NOT MODIFY THIS CODE. This is testing a very specific error (APPSEC-58131).
17+
// This caused the following error:
18+
// VerifyError: Inconsistent stackmap frames at branch target \d
19+
// Reason: urrent frame's stack size doesn't match stackmap.
20+
// To trigger this, it is necessary to consume an argument after the super call.
21+
super(in, charset);
22+
if (charset != null) {
23+
System.out.println("Using charset: " + charset.name());
24+
}
25+
}
26+
}

0 commit comments

Comments
 (0)