From 8ea7e5dea4f102cefd0828a3415115a460de6f51 Mon Sep 17 00:00:00 2001 From: Alejandro Gonzalez Date: Wed, 11 Oct 2023 13:59:40 +0200 Subject: [PATCH 01/18] First gson deserialization propagation version, tested for 1.1 --- .../bytebuddy/matcher/ignored_class_name.trie | 3 + .../instrumentation/gson/build.gradle | 23 ++++++ .../gson/JsonParserInstrumentation.java | 63 +++++++++++++++ .../gson/JsonParserInstrumentationTest.groovy | 81 +++++++++++++++++++ .../iastinstrumenter/iast_exclusion.trie | 2 + .../java/lang/StringReaderCallSite.java | 25 ++++++ .../java/io/StringReaderCallSiteTest.groovy | 21 +++++ .../java/foo/bar/TestStringReaderSuite.java | 10 +++ dd-smoke-tests/iast-util/build.gradle | 1 + .../controller/IastWebController.java | 8 ++ dd-smoke-tests/springboot/build.gradle | 1 + .../smoketest/IastSpringBootSmokeTest.groovy | 18 +++++ settings.gradle | 3 +- 13 files changed, 258 insertions(+), 1 deletion(-) create mode 100644 dd-java-agent/instrumentation/gson/build.gradle create mode 100644 dd-java-agent/instrumentation/gson/src/main/java/datadog/trace/instrumentation/gson/JsonParserInstrumentation.java create mode 100644 dd-java-agent/instrumentation/gson/src/test/groovy/datadog/trace/instrumentation/gson/JsonParserInstrumentationTest.groovy create mode 100644 dd-java-agent/instrumentation/java-io/src/main/java/datadog/trace/instrumentation/java/lang/StringReaderCallSite.java create mode 100644 dd-java-agent/instrumentation/java-io/src/test/groovy/datadog/trace/instrumentation/java/io/StringReaderCallSiteTest.groovy create mode 100644 dd-java-agent/instrumentation/java-io/src/test/java/foo/bar/TestStringReaderSuite.java diff --git a/dd-java-agent/agent-tooling/src/main/resources/datadog/trace/agent/tooling/bytebuddy/matcher/ignored_class_name.trie b/dd-java-agent/agent-tooling/src/main/resources/datadog/trace/agent/tooling/bytebuddy/matcher/ignored_class_name.trie index fd259e3cd80..856b73039e1 100644 --- a/dd-java-agent/agent-tooling/src/main/resources/datadog/trace/agent/tooling/bytebuddy/matcher/ignored_class_name.trie +++ b/dd-java-agent/agent-tooling/src/main/resources/datadog/trace/agent/tooling/bytebuddy/matcher/ignored_class_name.trie @@ -192,6 +192,9 @@ 0 com.google.common.base.internal.Finalizer 0 com.google.common.util.concurrent.* 2 com.google.gson.* +# Need for IAST: we instrument this class +0 com.google.gson.Gson +0 com.google.gson.JsonParser 2 com.google.inject.* # We instrument Runnable there 0 com.google.inject.internal.AbstractBindingProcessor$* diff --git a/dd-java-agent/instrumentation/gson/build.gradle b/dd-java-agent/instrumentation/gson/build.gradle new file mode 100644 index 00000000000..ec0a785c6e7 --- /dev/null +++ b/dd-java-agent/instrumentation/gson/build.gradle @@ -0,0 +1,23 @@ +muzzle { + pass { + group = 'com.google.code.gson' + module = 'gson' + versions = '[1.1,]' + assertInverse = true + } +} + +apply from: "$rootDir/gradle/java.gradle" +apply plugin: 'call-site-instrumentation' + +addTestSuiteForDir('latestDepTest', 'test') + +dependencies { + compileOnly group: 'com.google.code.gson', name: 'gson', version: '1.1' + + testImplementation group: 'com.google.code.gson', name: 'gson', version: '1.1' + + testRuntimeOnly project(':dd-java-agent:instrumentation:iast-instrumenter') + + latestDepTestImplementation group: 'com.google.code.gson', name: 'gson', version: '+' +} diff --git a/dd-java-agent/instrumentation/gson/src/main/java/datadog/trace/instrumentation/gson/JsonParserInstrumentation.java b/dd-java-agent/instrumentation/gson/src/main/java/datadog/trace/instrumentation/gson/JsonParserInstrumentation.java new file mode 100644 index 00000000000..0bdbe7dd167 --- /dev/null +++ b/dd-java-agent/instrumentation/gson/src/main/java/datadog/trace/instrumentation/gson/JsonParserInstrumentation.java @@ -0,0 +1,63 @@ +package datadog.trace.instrumentation.gson; + +import static datadog.trace.agent.tooling.bytebuddy.matcher.NameMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.isConstructor; +import static net.bytebuddy.matcher.ElementMatchers.isMethod; +import static net.bytebuddy.matcher.ElementMatchers.takesArgument; +import static net.bytebuddy.matcher.ElementMatchers.takesArguments; + +import com.google.auto.service.AutoService; +import com.google.gson.JsonPrimitive; +import datadog.trace.agent.tooling.Instrumenter; +import datadog.trace.api.iast.InstrumentationBridge; +import datadog.trace.api.iast.Propagation; +import datadog.trace.api.iast.propagation.PropagationModule; +import net.bytebuddy.asm.Advice; + +@AutoService(Instrumenter.class) +public class JsonParserInstrumentation extends Instrumenter.Iast + implements Instrumenter.ForSingleType { + + public JsonParserInstrumentation() { + super("gson"); + } + + @Override + public String instrumentedType() { + return "com.google.gson.JsonParser"; + } + + @Override + public void adviceTransformations(AdviceTransformation transformation) { + transformation.applyAdvice( + isConstructor().and(takesArguments(1)).and(takesArgument(0, named("java.io.Reader"))), + getClass().getName() + "$ConstructAdvice"); + transformation.applyAdvice( + isMethod().and(takesArguments(0).and(named("JsonString"))), + getClass().getName() + "$ParseAdvice"); + } + + public static class ConstructAdvice { + @Advice.OnMethodExit(suppress = Throwable.class) + @Propagation + public static void afterInit( + @Advice.This Object self, @Advice.Argument(0) final java.io.Reader input) { + final PropagationModule iastModule = InstrumentationBridge.PROPAGATION; + if (iastModule != null && input != null) { + iastModule.taintIfInputIsTainted(self, input); + } + } + } + + public static class ParseAdvice { + @Advice.OnMethodExit(suppress = Throwable.class) + @Propagation + public static void afterParse( + @Advice.This Object self, @Advice.Return final JsonPrimitive result) { + final PropagationModule iastModule = InstrumentationBridge.PROPAGATION; + if (iastModule != null && result != null) { + iastModule.taintIfInputIsTainted(result.getAsString(), self); + } + } + } +} diff --git a/dd-java-agent/instrumentation/gson/src/test/groovy/datadog/trace/instrumentation/gson/JsonParserInstrumentationTest.groovy b/dd-java-agent/instrumentation/gson/src/test/groovy/datadog/trace/instrumentation/gson/JsonParserInstrumentationTest.groovy new file mode 100644 index 00000000000..e6297f9330c --- /dev/null +++ b/dd-java-agent/instrumentation/gson/src/test/groovy/datadog/trace/instrumentation/gson/JsonParserInstrumentationTest.groovy @@ -0,0 +1,81 @@ +package datadog.trace.instrumentation.gson + +import com.google.gson.Gson +import com.google.gson.JsonParser +import datadog.trace.agent.test.AgentTestRunner +import datadog.trace.api.iast.InstrumentationBridge +import datadog.trace.api.iast.propagation.PropagationModule + +class JsonParserInstrumentationTest extends AgentTestRunner { + + @Override + protected void configurePreAgent() { + injectSysConfig("dd.iast.enabled", "true") + } + + void 'Test Gson instrumented'(){ + given: + final gson = new Gson() + + when: + final result = gson.fromJson('{"name": "nameTest", "value" : "valueTest"}', TestBean) + + then: + result instanceof TestBean + result.getName() == 'nameTest' + result.getValue() == 'valueTest' + } + + + void 'test'() { + given: + final module = Mock(PropagationModule) + InstrumentationBridge.registerIastModule(module) + + when: + final parser = new JsonParser(new StringReader(json)) + + then: + 1 * module.taintIfInputIsTainted(_ as JsonParser, _ as StringReader) + 0 * _ + + when: + parser.parse() + + then: + callsAfterParse * module.taintIfInputIsTainted(_ as String, _ as JsonParser) + 0 * _ + + where: + json | callsAfterParse + '"Test"' | 1 + '1' | 0 + '{"name": "nameTest", "value" : "valueTest"}' | 4 + '[{"name": "nameTest", "value" : "valueTest"}]' | 4 + '[{"name": "nameTest", "value" : "valueTest"}, {"name": "nameTest2", "value" : "valueTest2"}]' | 8 + } + + + static final class TestBean { + + private String name + + private String value + + String getName() { + return name + } + + void setName(String name) { + this.name = name + } + + String getValue() { + return value + } + + void setValue(String value) { + this.value = value + } + } +} diff --git a/dd-java-agent/instrumentation/iast-instrumenter/src/main/resources/datadog/trace/instrumentation/iastinstrumenter/iast_exclusion.trie b/dd-java-agent/instrumentation/iast-instrumenter/src/main/resources/datadog/trace/instrumentation/iastinstrumenter/iast_exclusion.trie index 46b10db7876..05e3234670b 100644 --- a/dd-java-agent/instrumentation/iast-instrumenter/src/main/resources/datadog/trace/instrumentation/iastinstrumenter/iast_exclusion.trie +++ b/dd-java-agent/instrumentation/iast-instrumenter/src/main/resources/datadog/trace/instrumentation/iastinstrumenter/iast_exclusion.trie @@ -75,6 +75,8 @@ 1 com.github.benmanes.caffeine.* 1 com.github.jknack.handlebars.* 1 com.google.* +#Need for gson propagation +2 com.google.gson.Gson 1 com.googlecode.* 1 com.hazelcast.* 1 com.hdivsecurity.* diff --git a/dd-java-agent/instrumentation/java-io/src/main/java/datadog/trace/instrumentation/java/lang/StringReaderCallSite.java b/dd-java-agent/instrumentation/java-io/src/main/java/datadog/trace/instrumentation/java/lang/StringReaderCallSite.java new file mode 100644 index 00000000000..7b034ad6259 --- /dev/null +++ b/dd-java-agent/instrumentation/java-io/src/main/java/datadog/trace/instrumentation/java/lang/StringReaderCallSite.java @@ -0,0 +1,25 @@ +package datadog.trace.instrumentation.java.lang; + +import datadog.trace.agent.tooling.csi.CallSite; +import datadog.trace.api.iast.IastCallSites; +import datadog.trace.api.iast.InstrumentationBridge; +import datadog.trace.api.iast.Propagation; +import datadog.trace.api.iast.propagation.PropagationModule; +import java.io.StringReader; +import javax.annotation.Nonnull; + +@Propagation +@CallSite(spi = IastCallSites.class) +public class StringReaderCallSite { + + @CallSite.After("void java.io.StringReader.(java.lang.String)") + public static StringReader afterInit( + @CallSite.AllArguments @Nonnull final Object[] params, + @CallSite.Return @Nonnull final StringReader result) { + final PropagationModule propagationModule = InstrumentationBridge.PROPAGATION; + if (propagationModule != null) { + propagationModule.taintIfInputIsTainted(result, params[0]); + } + return result; + } +} diff --git a/dd-java-agent/instrumentation/java-io/src/test/groovy/datadog/trace/instrumentation/java/io/StringReaderCallSiteTest.groovy b/dd-java-agent/instrumentation/java-io/src/test/groovy/datadog/trace/instrumentation/java/io/StringReaderCallSiteTest.groovy new file mode 100644 index 00000000000..2c6e2549e74 --- /dev/null +++ b/dd-java-agent/instrumentation/java-io/src/test/groovy/datadog/trace/instrumentation/java/io/StringReaderCallSiteTest.groovy @@ -0,0 +1,21 @@ +package datadog.trace.instrumentation.java.io + +import datadog.trace.api.iast.InstrumentationBridge +import datadog.trace.api.iast.propagation.PropagationModule +import foo.bar.TestStringReaderSuite + +class StringReaderCallSiteTest extends BaseIoCallSiteTest{ + + void 'test StringReader.'(){ + given: + PropagationModule iastModule = Mock(PropagationModule) + InstrumentationBridge.registerIastModule(iastModule) + final input = 'Test input' + + when: + TestStringReaderSuite.init(input) + + then: + 1 * iastModule.taintIfInputIsTainted(_ as StringReader, input) + } +} diff --git a/dd-java-agent/instrumentation/java-io/src/test/java/foo/bar/TestStringReaderSuite.java b/dd-java-agent/instrumentation/java-io/src/test/java/foo/bar/TestStringReaderSuite.java new file mode 100644 index 00000000000..36d5e9b330a --- /dev/null +++ b/dd-java-agent/instrumentation/java-io/src/test/java/foo/bar/TestStringReaderSuite.java @@ -0,0 +1,10 @@ +package foo.bar; + +import java.io.StringReader; + +public class TestStringReaderSuite { + + public static void init(String input) { + new StringReader(input); + } +} diff --git a/dd-smoke-tests/iast-util/build.gradle b/dd-smoke-tests/iast-util/build.gradle index 7b41b040a19..ee76274e07b 100644 --- a/dd-smoke-tests/iast-util/build.gradle +++ b/dd-smoke-tests/iast-util/build.gradle @@ -9,4 +9,5 @@ description = 'iast-smoke-tests-utils' dependencies { api project(':dd-smoke-tests') compileOnly group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '1.5.18.RELEASE' + compileOnly group: 'com.google.code.gson', name: 'gson', version: '1.1' } diff --git a/dd-smoke-tests/iast-util/src/main/java/datadog/smoketest/springboot/controller/IastWebController.java b/dd-smoke-tests/iast-util/src/main/java/datadog/smoketest/springboot/controller/IastWebController.java index ac3f5ebafe7..30336a3d0ee 100644 --- a/dd-smoke-tests/iast-util/src/main/java/datadog/smoketest/springboot/controller/IastWebController.java +++ b/dd-smoke-tests/iast-util/src/main/java/datadog/smoketest/springboot/controller/IastWebController.java @@ -1,5 +1,6 @@ package datadog.smoketest.springboot.controller; +import com.google.gson.Gson; import datadog.smoketest.springboot.TestBean; import ddtest.client.sources.Hasher; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; @@ -343,6 +344,13 @@ String pathInfo(HttpServletRequest request) { return String.format("Request.getRequestURI returns %s", pathInfo); } + @GetMapping("/gson_deserialization") + String gson(@RequestParam("json") String json) { + Gson gson = new Gson(); + TestBean testBean = gson.fromJson(json, TestBean.class); + return "Test bean -> name: " + testBean.getName() + ", value: " + testBean.getValue(); + } + private void withProcess(final Operation op) { Process process = null; try { diff --git a/dd-smoke-tests/springboot/build.gradle b/dd-smoke-tests/springboot/build.gradle index de5cc97237c..6ce2ddd21e2 100644 --- a/dd-smoke-tests/springboot/build.gradle +++ b/dd-smoke-tests/springboot/build.gradle @@ -24,6 +24,7 @@ dependencies { implementation group: 'com.auth0', name: 'java-jwt', version: '4.0.0-beta.0' implementation group: 'com.auth0', name: 'jwks-rsa', version: '0.21.1' implementation group: 'com.nimbusds', name: 'nimbus-jose-jwt', version: '9.22' + implementation group: 'com.google.code.gson', name: 'gson', version: '1.1' implementation group: 'org.springframework', name: 'spring-web', version: '1.5.18.RELEASE' diff --git a/dd-smoke-tests/springboot/src/test/groovy/datadog/smoketest/IastSpringBootSmokeTest.groovy b/dd-smoke-tests/springboot/src/test/groovy/datadog/smoketest/IastSpringBootSmokeTest.groovy index 628ed6901e3..a55887cd555 100644 --- a/dd-smoke-tests/springboot/src/test/groovy/datadog/smoketest/IastSpringBootSmokeTest.groovy +++ b/dd-smoke-tests/springboot/src/test/groovy/datadog/smoketest/IastSpringBootSmokeTest.groovy @@ -25,4 +25,22 @@ class IastSpringBootSmokeTest extends AbstractIastSpringBootTest { it.ranges[0].source.origin == 'http.request.header' } } + + + void 'gson deserialization'() { + + given: + final url = "http://localhost:${httpPort}/gson_deserialization?json=%7B%22name%22%3A%20%22gsonTest%22%2C%20%22value%22%20%3A%20%22valueTest%22%7D" + final request = new Request.Builder().url(url).get().build() + + when: + client.newCall(request).execute() + + then: + hasTainted { tainted -> + tainted.value == 'gsonTest' && + tainted.ranges[0].source.name == 'json' && + tainted.ranges[0].source.origin == 'http.request.parameter' + } + } } diff --git a/settings.gradle b/settings.gradle index 2f888b2ac42..0d66382a497 100644 --- a/settings.gradle +++ b/settings.gradle @@ -211,6 +211,7 @@ include ':dd-java-agent:instrumentation:grizzly-2' include ':dd-java-agent:instrumentation:grizzly-client-1.9' include ':dd-java-agent:instrumentation:grizzly-http-2.3.20' include ':dd-java-agent:instrumentation:grpc-1.5' +include ':dd-java-agent:instrumentation:gson' include ':dd-java-agent:instrumentation:guava-10' include ':dd-java-agent:instrumentation:hazelcast-3.6' include ':dd-java-agent:instrumentation:hazelcast-3.9' @@ -422,4 +423,4 @@ include ':dd-java-agent:instrumentation:zio:zio-2.0' include ':dd-java-agent:benchmark' include ':dd-java-agent:benchmark-integration' include ':dd-java-agent:benchmark-integration:jetty-perftest' -include ':dd-java-agent:benchmark-integration:play-perftest' \ No newline at end of file +include ':dd-java-agent:benchmark-integration:play-perftest' From 73e7f2389da092bbb8f24e4aa07182a0442d6a29 Mon Sep 17 00:00:00 2001 From: Alejandro Gonzalez Date: Fri, 13 Oct 2023 13:18:21 +0200 Subject: [PATCH 02/18] Refactor, current instrumentation only works for v1.1 --- dd-java-agent/instrumentation/{gson => gson-1.1}/build.gradle | 4 ++-- .../trace/instrumentation/gson/JsonParserInstrumentation.java | 0 .../instrumentation/gson/JsonParserInstrumentationTest.groovy | 0 settings.gradle | 2 +- 4 files changed, 3 insertions(+), 3 deletions(-) rename dd-java-agent/instrumentation/{gson => gson-1.1}/build.gradle (91%) rename dd-java-agent/instrumentation/{gson => gson-1.1}/src/main/java/datadog/trace/instrumentation/gson/JsonParserInstrumentation.java (100%) rename dd-java-agent/instrumentation/{gson => gson-1.1}/src/test/groovy/datadog/trace/instrumentation/gson/JsonParserInstrumentationTest.groovy (100%) diff --git a/dd-java-agent/instrumentation/gson/build.gradle b/dd-java-agent/instrumentation/gson-1.1/build.gradle similarity index 91% rename from dd-java-agent/instrumentation/gson/build.gradle rename to dd-java-agent/instrumentation/gson-1.1/build.gradle index ec0a785c6e7..724d38cf2d9 100644 --- a/dd-java-agent/instrumentation/gson/build.gradle +++ b/dd-java-agent/instrumentation/gson-1.1/build.gradle @@ -2,7 +2,7 @@ muzzle { pass { group = 'com.google.code.gson' module = 'gson' - versions = '[1.1,]' + versions = '[1.1]' assertInverse = true } } @@ -19,5 +19,5 @@ dependencies { testRuntimeOnly project(':dd-java-agent:instrumentation:iast-instrumenter') - latestDepTestImplementation group: 'com.google.code.gson', name: 'gson', version: '+' + latestDepTestImplementation group: 'com.google.code.gson', name: 'gson', version: '1.1' } diff --git a/dd-java-agent/instrumentation/gson/src/main/java/datadog/trace/instrumentation/gson/JsonParserInstrumentation.java b/dd-java-agent/instrumentation/gson-1.1/src/main/java/datadog/trace/instrumentation/gson/JsonParserInstrumentation.java similarity index 100% rename from dd-java-agent/instrumentation/gson/src/main/java/datadog/trace/instrumentation/gson/JsonParserInstrumentation.java rename to dd-java-agent/instrumentation/gson-1.1/src/main/java/datadog/trace/instrumentation/gson/JsonParserInstrumentation.java diff --git a/dd-java-agent/instrumentation/gson/src/test/groovy/datadog/trace/instrumentation/gson/JsonParserInstrumentationTest.groovy b/dd-java-agent/instrumentation/gson-1.1/src/test/groovy/datadog/trace/instrumentation/gson/JsonParserInstrumentationTest.groovy similarity index 100% rename from dd-java-agent/instrumentation/gson/src/test/groovy/datadog/trace/instrumentation/gson/JsonParserInstrumentationTest.groovy rename to dd-java-agent/instrumentation/gson-1.1/src/test/groovy/datadog/trace/instrumentation/gson/JsonParserInstrumentationTest.groovy diff --git a/settings.gradle b/settings.gradle index 0d66382a497..975690fb895 100644 --- a/settings.gradle +++ b/settings.gradle @@ -211,7 +211,7 @@ include ':dd-java-agent:instrumentation:grizzly-2' include ':dd-java-agent:instrumentation:grizzly-client-1.9' include ':dd-java-agent:instrumentation:grizzly-http-2.3.20' include ':dd-java-agent:instrumentation:grpc-1.5' -include ':dd-java-agent:instrumentation:gson' +include ':dd-java-agent:instrumentation:gson-1.1' include ':dd-java-agent:instrumentation:guava-10' include ':dd-java-agent:instrumentation:hazelcast-3.6' include ':dd-java-agent:instrumentation:hazelcast-3.9' From dde6d7a87116f24e08facfe98b60fca77c0ffa63 Mon Sep 17 00:00:00 2001 From: Alejandro Gonzalez Date: Tue, 17 Oct 2023 07:57:35 +0200 Subject: [PATCH 03/18] Gson instrumentation for 1.4 and 1.5 --- .../bytebuddy/matcher/ignored_class_name.trie | 1 + .../instrumentation/gson-1.4/build.gradle | 23 ++++++ .../gson/JsonParserJavaccInstrumentation.java | 63 +++++++++++++++ ...JsonParserJavaccInstrumentationTest.groovy | 76 +++++++++++++++++++ .../iastinstrumenter/iast_exclusion.trie | 1 + settings.gradle | 1 + 6 files changed, 165 insertions(+) create mode 100644 dd-java-agent/instrumentation/gson-1.4/build.gradle create mode 100644 dd-java-agent/instrumentation/gson-1.4/src/main/java/datadog/trace/instrumentation/gson/JsonParserJavaccInstrumentation.java create mode 100644 dd-java-agent/instrumentation/gson-1.4/src/test/groovy/datadog/trace/instrumentation/gson/JsonParserJavaccInstrumentationTest.groovy diff --git a/dd-java-agent/agent-tooling/src/main/resources/datadog/trace/agent/tooling/bytebuddy/matcher/ignored_class_name.trie b/dd-java-agent/agent-tooling/src/main/resources/datadog/trace/agent/tooling/bytebuddy/matcher/ignored_class_name.trie index 856b73039e1..af02530aa59 100644 --- a/dd-java-agent/agent-tooling/src/main/resources/datadog/trace/agent/tooling/bytebuddy/matcher/ignored_class_name.trie +++ b/dd-java-agent/agent-tooling/src/main/resources/datadog/trace/agent/tooling/bytebuddy/matcher/ignored_class_name.trie @@ -195,6 +195,7 @@ # Need for IAST: we instrument this class 0 com.google.gson.Gson 0 com.google.gson.JsonParser +0 com.google.gson.JsonParserJavacc 2 com.google.inject.* # We instrument Runnable there 0 com.google.inject.internal.AbstractBindingProcessor$* diff --git a/dd-java-agent/instrumentation/gson-1.4/build.gradle b/dd-java-agent/instrumentation/gson-1.4/build.gradle new file mode 100644 index 00000000000..a0423594b23 --- /dev/null +++ b/dd-java-agent/instrumentation/gson-1.4/build.gradle @@ -0,0 +1,23 @@ +muzzle { + pass { + group = 'com.google.code.gson' + module = 'gson' + versions = '[1.4]' + assertInverse = true + } +} + +apply from: "$rootDir/gradle/java.gradle" +apply plugin: 'call-site-instrumentation' + +addTestSuiteForDir('latestDepTest', 'test') + +dependencies { + compileOnly group: 'com.google.code.gson', name: 'gson', version: '1.4' + + testImplementation group: 'com.google.code.gson', name: 'gson', version: '1.4' + + testRuntimeOnly project(':dd-java-agent:instrumentation:iast-instrumenter') + + latestDepTestImplementation group: 'com.google.code.gson', name: 'gson', version: '1.5' +} diff --git a/dd-java-agent/instrumentation/gson-1.4/src/main/java/datadog/trace/instrumentation/gson/JsonParserJavaccInstrumentation.java b/dd-java-agent/instrumentation/gson-1.4/src/main/java/datadog/trace/instrumentation/gson/JsonParserJavaccInstrumentation.java new file mode 100644 index 00000000000..a92a5bef6c7 --- /dev/null +++ b/dd-java-agent/instrumentation/gson-1.4/src/main/java/datadog/trace/instrumentation/gson/JsonParserJavaccInstrumentation.java @@ -0,0 +1,63 @@ +package datadog.trace.instrumentation.gson; + +import static datadog.trace.agent.tooling.bytebuddy.matcher.NameMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.isConstructor; +import static net.bytebuddy.matcher.ElementMatchers.isMethod; +import static net.bytebuddy.matcher.ElementMatchers.takesArgument; +import static net.bytebuddy.matcher.ElementMatchers.takesArguments; + +import com.google.auto.service.AutoService; +import com.google.gson.JsonPrimitive; +import datadog.trace.agent.tooling.Instrumenter; +import datadog.trace.api.iast.InstrumentationBridge; +import datadog.trace.api.iast.Propagation; +import datadog.trace.api.iast.propagation.PropagationModule; +import net.bytebuddy.asm.Advice; + +@AutoService(Instrumenter.class) +public class JsonParserJavaccInstrumentation extends Instrumenter.Iast + implements Instrumenter.ForSingleType { + + public JsonParserJavaccInstrumentation() { + super("gson"); + } + + @Override + public String instrumentedType() { + return "com.google.gson.JsonParserJavacc"; + } + + @Override + public void adviceTransformations(AdviceTransformation transformation) { + transformation.applyAdvice( + isConstructor().and(takesArguments(1)).and(takesArgument(0, named("java.io.Reader"))), + getClass().getName() + "$ConstructAdvice"); + transformation.applyAdvice( + isMethod().and(takesArguments(0).and(named("JsonString"))), + getClass().getName() + "$ParseAdvice"); + } + + public static class ConstructAdvice { + @Advice.OnMethodExit(suppress = Throwable.class) + @Propagation + public static void afterInit( + @Advice.This Object self, @Advice.Argument(0) final java.io.Reader input) { + final PropagationModule iastModule = InstrumentationBridge.PROPAGATION; + if (iastModule != null && input != null) { + iastModule.taintIfInputIsTainted(self, input); + } + } + } + + public static class ParseAdvice { + @Advice.OnMethodExit(suppress = Throwable.class) + @Propagation + public static void afterParse( + @Advice.This Object self, @Advice.Return final JsonPrimitive result) { + final PropagationModule iastModule = InstrumentationBridge.PROPAGATION; + if (iastModule != null && result != null) { + iastModule.taintIfInputIsTainted(result.getAsString(), self); + } + } + } +} diff --git a/dd-java-agent/instrumentation/gson-1.4/src/test/groovy/datadog/trace/instrumentation/gson/JsonParserJavaccInstrumentationTest.groovy b/dd-java-agent/instrumentation/gson-1.4/src/test/groovy/datadog/trace/instrumentation/gson/JsonParserJavaccInstrumentationTest.groovy new file mode 100644 index 00000000000..0db5084387c --- /dev/null +++ b/dd-java-agent/instrumentation/gson-1.4/src/test/groovy/datadog/trace/instrumentation/gson/JsonParserJavaccInstrumentationTest.groovy @@ -0,0 +1,76 @@ +package datadog.trace.instrumentation.gson + +import com.google.gson.Gson +import com.google.gson.JsonParser +import com.google.gson.JsonParserJavacc +import datadog.trace.agent.test.AgentTestRunner +import datadog.trace.api.iast.InstrumentationBridge +import datadog.trace.api.iast.propagation.PropagationModule + +class JsonParserJavaccInstrumentationTest extends AgentTestRunner { + + @Override + protected void configurePreAgent() { + injectSysConfig("dd.iast.enabled", "true") + } + + void 'Test Gson instrumented'(){ + given: + final gson = new Gson() + + when: + final result = gson.fromJson('{"name": "nameTest", "value" : "valueTest"}', TestBean) + + then: + result instanceof TestBean + result.getName() == 'nameTest' + result.getValue() == 'valueTest' + } + + + void 'test'() { + given: + final module = Mock(PropagationModule) + InstrumentationBridge.registerIastModule(module) + + when: + new JsonParser().parse(new StringReader(json)) + + then: + 1 * module.taintIfInputIsTainted(_ as JsonParserJavacc, _ as StringReader) + callsAfterParse * module.taintIfInputIsTainted(_ as String, _ as JsonParserJavacc) + 0 * _ + + where: + json | callsAfterParse + '"Test"' | 1 + '1' | 0 + '{"name": "nameTest", "value" : "valueTest"}' | 4 + '[{"name": "nameTest", "value" : "valueTest"}]' | 4 + '[{"name": "nameTest", "value" : "valueTest"}, {"name": "nameTest2", "value" : "valueTest2"}]' | 8 + } + + + static final class TestBean { + + private String name + + private String value + + String getName() { + return name + } + + void setName(String name) { + this.name = name + } + + String getValue() { + return value + } + + void setValue(String value) { + this.value = value + } + } +} diff --git a/dd-java-agent/instrumentation/iast-instrumenter/src/main/resources/datadog/trace/instrumentation/iastinstrumenter/iast_exclusion.trie b/dd-java-agent/instrumentation/iast-instrumenter/src/main/resources/datadog/trace/instrumentation/iastinstrumenter/iast_exclusion.trie index 05e3234670b..3ba7bc0674c 100644 --- a/dd-java-agent/instrumentation/iast-instrumenter/src/main/resources/datadog/trace/instrumentation/iastinstrumenter/iast_exclusion.trie +++ b/dd-java-agent/instrumentation/iast-instrumenter/src/main/resources/datadog/trace/instrumentation/iastinstrumenter/iast_exclusion.trie @@ -77,6 +77,7 @@ 1 com.google.* #Need for gson propagation 2 com.google.gson.Gson +2 com.google.gson.JsonParser 1 com.googlecode.* 1 com.hazelcast.* 1 com.hdivsecurity.* diff --git a/settings.gradle b/settings.gradle index 975690fb895..fac56e7a694 100644 --- a/settings.gradle +++ b/settings.gradle @@ -212,6 +212,7 @@ include ':dd-java-agent:instrumentation:grizzly-client-1.9' include ':dd-java-agent:instrumentation:grizzly-http-2.3.20' include ':dd-java-agent:instrumentation:grpc-1.5' include ':dd-java-agent:instrumentation:gson-1.1' +include ':dd-java-agent:instrumentation:gson-1.4' include ':dd-java-agent:instrumentation:guava-10' include ':dd-java-agent:instrumentation:hazelcast-3.6' include ':dd-java-agent:instrumentation:hazelcast-3.9' From 8c62450d7b1c886f8aef80338eb27c2ac6501d98 Mon Sep 17 00:00:00 2001 From: Alejandro Gonzalez Date: Wed, 18 Oct 2023 08:16:20 +0200 Subject: [PATCH 04/18] Gson instrumentation from 1.6 --- .../bytebuddy/matcher/ignored_class_name.trie | 1 + .../instrumentation/gson-1.6/build.gradle | 23 ++++++ .../gson/JsonReaderInstrumentation.java | 67 ++++++++++++++++ .../gson/JsonReaderInstrumentationTest.groovy | 79 +++++++++++++++++++ .../iastinstrumenter/iast_exclusion.trie | 1 + settings.gradle | 1 + 6 files changed, 172 insertions(+) create mode 100644 dd-java-agent/instrumentation/gson-1.6/build.gradle create mode 100644 dd-java-agent/instrumentation/gson-1.6/src/main/java/datadog/trace/instrumentation/gson/JsonReaderInstrumentation.java create mode 100644 dd-java-agent/instrumentation/gson-1.6/src/test/groovy/datadog/trace/instrumentation/gson/JsonReaderInstrumentationTest.groovy diff --git a/dd-java-agent/agent-tooling/src/main/resources/datadog/trace/agent/tooling/bytebuddy/matcher/ignored_class_name.trie b/dd-java-agent/agent-tooling/src/main/resources/datadog/trace/agent/tooling/bytebuddy/matcher/ignored_class_name.trie index af02530aa59..08d0b9a5a71 100644 --- a/dd-java-agent/agent-tooling/src/main/resources/datadog/trace/agent/tooling/bytebuddy/matcher/ignored_class_name.trie +++ b/dd-java-agent/agent-tooling/src/main/resources/datadog/trace/agent/tooling/bytebuddy/matcher/ignored_class_name.trie @@ -196,6 +196,7 @@ 0 com.google.gson.Gson 0 com.google.gson.JsonParser 0 com.google.gson.JsonParserJavacc +0 com.google.gson.stream.JsonReader 2 com.google.inject.* # We instrument Runnable there 0 com.google.inject.internal.AbstractBindingProcessor$* diff --git a/dd-java-agent/instrumentation/gson-1.6/build.gradle b/dd-java-agent/instrumentation/gson-1.6/build.gradle new file mode 100644 index 00000000000..11cef1ee648 --- /dev/null +++ b/dd-java-agent/instrumentation/gson-1.6/build.gradle @@ -0,0 +1,23 @@ +muzzle { + pass { + group = 'com.google.code.gson' + module = 'gson' + versions = '[1.6, ]' + assertInverse = true + } +} + +apply from: "$rootDir/gradle/java.gradle" +apply plugin: 'call-site-instrumentation' + +addTestSuiteForDir('latestDepTest', 'test') + +dependencies { + compileOnly group: 'com.google.code.gson', name: 'gson', version: '1.6' + + testImplementation group: 'com.google.code.gson', name: 'gson', version: '1.6' + + testRuntimeOnly project(':dd-java-agent:instrumentation:iast-instrumenter') + + latestDepTestImplementation group: 'com.google.code.gson', name: 'gson', version: '+' +} diff --git a/dd-java-agent/instrumentation/gson-1.6/src/main/java/datadog/trace/instrumentation/gson/JsonReaderInstrumentation.java b/dd-java-agent/instrumentation/gson-1.6/src/main/java/datadog/trace/instrumentation/gson/JsonReaderInstrumentation.java new file mode 100644 index 00000000000..f14f39370e1 --- /dev/null +++ b/dd-java-agent/instrumentation/gson-1.6/src/main/java/datadog/trace/instrumentation/gson/JsonReaderInstrumentation.java @@ -0,0 +1,67 @@ +package datadog.trace.instrumentation.gson; + +import static datadog.trace.agent.tooling.bytebuddy.matcher.NameMatchers.named; +import static datadog.trace.agent.tooling.bytebuddy.matcher.NameMatchers.namedOneOf; +import static net.bytebuddy.matcher.ElementMatchers.isConstructor; +import static net.bytebuddy.matcher.ElementMatchers.isMethod; +import static net.bytebuddy.matcher.ElementMatchers.isPublic; +import static net.bytebuddy.matcher.ElementMatchers.returns; +import static net.bytebuddy.matcher.ElementMatchers.takesArgument; +import static net.bytebuddy.matcher.ElementMatchers.takesArguments; + +import com.google.auto.service.AutoService; +import datadog.trace.agent.tooling.Instrumenter; +import datadog.trace.api.iast.InstrumentationBridge; +import datadog.trace.api.iast.Propagation; +import datadog.trace.api.iast.propagation.PropagationModule; +import net.bytebuddy.asm.Advice; + +@AutoService(Instrumenter.class) +public class JsonReaderInstrumentation extends Instrumenter.Iast + implements Instrumenter.ForSingleType { + + public JsonReaderInstrumentation() { + super("gson"); + } + + @Override + public String instrumentedType() { + return "com.google.gson.stream.JsonReader"; + } + + @Override + public void adviceTransformations(AdviceTransformation transformation) { + transformation.applyAdvice( + isConstructor().and(takesArguments(1)).and(takesArgument(0, named("java.io.Reader"))), + getClass().getName() + "$ConstructAdvice"); + transformation.applyAdvice( + isMethod() + .and(isPublic()) + .and(returns(String.class)) + .and(namedOneOf("nextName", "nextString")), + getClass().getName() + "$MethodAdvice"); + } + + public static class ConstructAdvice { + @Advice.OnMethodExit(suppress = Throwable.class) + @Propagation + public static void afterInit( + @Advice.This Object self, @Advice.Argument(0) final java.io.Reader input) { + final PropagationModule iastModule = InstrumentationBridge.PROPAGATION; + if (iastModule != null && input != null) { + iastModule.taintIfInputIsTainted(self, input); + } + } + } + + public static class MethodAdvice { + @Advice.OnMethodExit(suppress = Throwable.class) + @Propagation + public static void afterMethod(@Advice.This Object self, @Advice.Return final String result) { + final PropagationModule iastModule = InstrumentationBridge.PROPAGATION; + if (iastModule != null && result != null) { + iastModule.taintIfInputIsTainted(result, self); + } + } + } +} diff --git a/dd-java-agent/instrumentation/gson-1.6/src/test/groovy/datadog/trace/instrumentation/gson/JsonReaderInstrumentationTest.groovy b/dd-java-agent/instrumentation/gson-1.6/src/test/groovy/datadog/trace/instrumentation/gson/JsonReaderInstrumentationTest.groovy new file mode 100644 index 00000000000..84b03668ca0 --- /dev/null +++ b/dd-java-agent/instrumentation/gson-1.6/src/test/groovy/datadog/trace/instrumentation/gson/JsonReaderInstrumentationTest.groovy @@ -0,0 +1,79 @@ +package datadog.trace.instrumentation.gson + +import com.google.gson.Gson +import com.google.gson.stream.JsonReader +import datadog.trace.agent.test.AgentTestRunner +import datadog.trace.api.iast.InstrumentationBridge +import datadog.trace.api.iast.propagation.PropagationModule + +class JsonReaderInstrumentationTest extends AgentTestRunner { + + @Override + protected void configurePreAgent() { + injectSysConfig("dd.iast.enabled", "true") + } + + void 'Test Gson instrumented'(){ + given: + final gson = new Gson() + + when: + final result = gson.fromJson('{"name": "nameTest", "value" : "valueTest"}', TestBean) + + then: + result instanceof TestBean + result.getName() == 'nameTest' + result.getValue() == 'valueTest' + } + + void 'test'() { + given: + final module = Mock(PropagationModule) + InstrumentationBridge.registerIastModule(module) + final gson = new Gson() + + when: + final reader = new JsonReader(new StringReader(json)) + + then: + 1 * module.taintIfInputIsTainted(_ as JsonReader, _ as StringReader) + + when: + gson.fromJson(reader, clazz) + + then: + calls * module.taintIfInputIsTainted(_ as String, _ as JsonReader) + 0 * _ + + where: + json | clazz | calls + '"Test"' | String | 1 + '{"name": "nameTest", "value" : "valueTest"}' | TestBean | 4 + '[{"name": "nameTest", "value" : "valueTest"}]' | TestBean[] | 4 + '[{"name": "nameTest", "value" : "valueTest"}, {"name": "nameTest2", "value" : "valueTest2"}]' | TestBean[].class | 8 + } + + + static final class TestBean { + + private String name + + private String value + + String getName() { + return name + } + + void setName(String name) { + this.name = name + } + + String getValue() { + return value + } + + void setValue(String value) { + this.value = value + } + } +} diff --git a/dd-java-agent/instrumentation/iast-instrumenter/src/main/resources/datadog/trace/instrumentation/iastinstrumenter/iast_exclusion.trie b/dd-java-agent/instrumentation/iast-instrumenter/src/main/resources/datadog/trace/instrumentation/iastinstrumenter/iast_exclusion.trie index 3ba7bc0674c..4e7d4c9a409 100644 --- a/dd-java-agent/instrumentation/iast-instrumenter/src/main/resources/datadog/trace/instrumentation/iastinstrumenter/iast_exclusion.trie +++ b/dd-java-agent/instrumentation/iast-instrumenter/src/main/resources/datadog/trace/instrumentation/iastinstrumenter/iast_exclusion.trie @@ -78,6 +78,7 @@ #Need for gson propagation 2 com.google.gson.Gson 2 com.google.gson.JsonParser +2 com.google.gson.stream.JsonReader 1 com.googlecode.* 1 com.hazelcast.* 1 com.hdivsecurity.* diff --git a/settings.gradle b/settings.gradle index fac56e7a694..3aae9144226 100644 --- a/settings.gradle +++ b/settings.gradle @@ -213,6 +213,7 @@ include ':dd-java-agent:instrumentation:grizzly-http-2.3.20' include ':dd-java-agent:instrumentation:grpc-1.5' include ':dd-java-agent:instrumentation:gson-1.1' include ':dd-java-agent:instrumentation:gson-1.4' +include ':dd-java-agent:instrumentation:gson-1.6' include ':dd-java-agent:instrumentation:guava-10' include ':dd-java-agent:instrumentation:hazelcast-3.6' include ':dd-java-agent:instrumentation:hazelcast-3.9' From 52e583dd4fafab56b964ed660a46fa0bad9b8a57 Mon Sep 17 00:00:00 2001 From: Alejandro Gonzalez Date: Wed, 18 Oct 2023 08:27:44 +0200 Subject: [PATCH 05/18] Fix gradle --- dd-java-agent/instrumentation/gson-1.1/build.gradle | 2 -- dd-java-agent/instrumentation/gson-1.4/build.gradle | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/dd-java-agent/instrumentation/gson-1.1/build.gradle b/dd-java-agent/instrumentation/gson-1.1/build.gradle index 724d38cf2d9..4dfd013664b 100644 --- a/dd-java-agent/instrumentation/gson-1.1/build.gradle +++ b/dd-java-agent/instrumentation/gson-1.1/build.gradle @@ -10,7 +10,6 @@ muzzle { apply from: "$rootDir/gradle/java.gradle" apply plugin: 'call-site-instrumentation' -addTestSuiteForDir('latestDepTest', 'test') dependencies { compileOnly group: 'com.google.code.gson', name: 'gson', version: '1.1' @@ -19,5 +18,4 @@ dependencies { testRuntimeOnly project(':dd-java-agent:instrumentation:iast-instrumenter') - latestDepTestImplementation group: 'com.google.code.gson', name: 'gson', version: '1.1' } diff --git a/dd-java-agent/instrumentation/gson-1.4/build.gradle b/dd-java-agent/instrumentation/gson-1.4/build.gradle index a0423594b23..5a5e9dc40ea 100644 --- a/dd-java-agent/instrumentation/gson-1.4/build.gradle +++ b/dd-java-agent/instrumentation/gson-1.4/build.gradle @@ -2,7 +2,7 @@ muzzle { pass { group = 'com.google.code.gson' module = 'gson' - versions = '[1.4]' + versions = '[1.4, 1.5]' assertInverse = true } } From c5e84cbf847b25fa667bdba5a24717aa0efa27bc Mon Sep 17 00:00:00 2001 From: Alejandro Gonzalez Date: Wed, 18 Oct 2023 08:44:23 +0200 Subject: [PATCH 06/18] Update smoke test --- dd-smoke-tests/springboot/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dd-smoke-tests/springboot/build.gradle b/dd-smoke-tests/springboot/build.gradle index 6ce2ddd21e2..40e4a7acb68 100644 --- a/dd-smoke-tests/springboot/build.gradle +++ b/dd-smoke-tests/springboot/build.gradle @@ -24,7 +24,7 @@ dependencies { implementation group: 'com.auth0', name: 'java-jwt', version: '4.0.0-beta.0' implementation group: 'com.auth0', name: 'jwks-rsa', version: '0.21.1' implementation group: 'com.nimbusds', name: 'nimbus-jose-jwt', version: '9.22' - implementation group: 'com.google.code.gson', name: 'gson', version: '1.1' + implementation group: 'com.google.code.gson', name: 'gson', version: '2.10' implementation group: 'org.springframework', name: 'spring-web', version: '1.5.18.RELEASE' From f98d8b86146a385a31a0c12725366c436d751e03 Mon Sep 17 00:00:00 2001 From: Alejandro Gonzalez Date: Wed, 18 Oct 2023 09:10:00 +0200 Subject: [PATCH 07/18] fix spotless --- dd-java-agent/instrumentation/gson-1.1/build.gradle | 1 - 1 file changed, 1 deletion(-) diff --git a/dd-java-agent/instrumentation/gson-1.1/build.gradle b/dd-java-agent/instrumentation/gson-1.1/build.gradle index 4dfd013664b..da7f5a667f9 100644 --- a/dd-java-agent/instrumentation/gson-1.1/build.gradle +++ b/dd-java-agent/instrumentation/gson-1.1/build.gradle @@ -17,5 +17,4 @@ dependencies { testImplementation group: 'com.google.code.gson', name: 'gson', version: '1.1' testRuntimeOnly project(':dd-java-agent:instrumentation:iast-instrumenter') - } From daeaeaaac97635518f05906309cef466574e420b Mon Sep 17 00:00:00 2001 From: Alejandro Gonzalez Date: Wed, 18 Oct 2023 15:23:05 +0200 Subject: [PATCH 08/18] fix muzzle --- dd-java-agent/instrumentation/gson-1.1/build.gradle | 2 +- .../gson/JsonParserInstrumentation.java | 10 ++++++++++ .../gson/JsonParserJavaccInstrumentation.java | 6 ++++++ dd-java-agent/instrumentation/gson-1.6/build.gradle | 1 + .../gson/JsonReaderInstrumentation.java | 6 ++++++ 5 files changed, 24 insertions(+), 1 deletion(-) diff --git a/dd-java-agent/instrumentation/gson-1.1/build.gradle b/dd-java-agent/instrumentation/gson-1.1/build.gradle index da7f5a667f9..abe3d391867 100644 --- a/dd-java-agent/instrumentation/gson-1.1/build.gradle +++ b/dd-java-agent/instrumentation/gson-1.1/build.gradle @@ -2,7 +2,7 @@ muzzle { pass { group = 'com.google.code.gson' module = 'gson' - versions = '[1.1]' + versions = '[1.1,1.4)' assertInverse = true } } diff --git a/dd-java-agent/instrumentation/gson-1.1/src/main/java/datadog/trace/instrumentation/gson/JsonParserInstrumentation.java b/dd-java-agent/instrumentation/gson-1.1/src/main/java/datadog/trace/instrumentation/gson/JsonParserInstrumentation.java index 0bdbe7dd167..0141bc5fed4 100644 --- a/dd-java-agent/instrumentation/gson-1.1/src/main/java/datadog/trace/instrumentation/gson/JsonParserInstrumentation.java +++ b/dd-java-agent/instrumentation/gson-1.1/src/main/java/datadog/trace/instrumentation/gson/JsonParserInstrumentation.java @@ -9,6 +9,7 @@ import com.google.auto.service.AutoService; import com.google.gson.JsonPrimitive; import datadog.trace.agent.tooling.Instrumenter; +import datadog.trace.agent.tooling.muzzle.Reference; import datadog.trace.api.iast.InstrumentationBridge; import datadog.trace.api.iast.Propagation; import datadog.trace.api.iast.propagation.PropagationModule; @@ -18,6 +19,15 @@ public class JsonParserInstrumentation extends Instrumenter.Iast implements Instrumenter.ForSingleType { + @Override + public Reference[] additionalMuzzleReferences() { + return new Reference[] { + new Reference.Builder("com.google.gson.JsonParser") + .withMethod(new String[0], Reference.EXPECTS_PUBLIC, "", "V", "Ljava/io/Reader;") + .build() + }; + } + public JsonParserInstrumentation() { super("gson"); } diff --git a/dd-java-agent/instrumentation/gson-1.4/src/main/java/datadog/trace/instrumentation/gson/JsonParserJavaccInstrumentation.java b/dd-java-agent/instrumentation/gson-1.4/src/main/java/datadog/trace/instrumentation/gson/JsonParserJavaccInstrumentation.java index a92a5bef6c7..81676d62ae7 100644 --- a/dd-java-agent/instrumentation/gson-1.4/src/main/java/datadog/trace/instrumentation/gson/JsonParserJavaccInstrumentation.java +++ b/dd-java-agent/instrumentation/gson-1.4/src/main/java/datadog/trace/instrumentation/gson/JsonParserJavaccInstrumentation.java @@ -9,6 +9,7 @@ import com.google.auto.service.AutoService; import com.google.gson.JsonPrimitive; import datadog.trace.agent.tooling.Instrumenter; +import datadog.trace.agent.tooling.muzzle.Reference; import datadog.trace.api.iast.InstrumentationBridge; import datadog.trace.api.iast.Propagation; import datadog.trace.api.iast.propagation.PropagationModule; @@ -27,6 +28,11 @@ public String instrumentedType() { return "com.google.gson.JsonParserJavacc"; } + @Override + public Reference[] additionalMuzzleReferences() { + return new Reference[] {new Reference.Builder("com.google.gson.JsonParserJavacc").build()}; + } + @Override public void adviceTransformations(AdviceTransformation transformation) { transformation.applyAdvice( diff --git a/dd-java-agent/instrumentation/gson-1.6/build.gradle b/dd-java-agent/instrumentation/gson-1.6/build.gradle index 11cef1ee648..92ae4ba9947 100644 --- a/dd-java-agent/instrumentation/gson-1.6/build.gradle +++ b/dd-java-agent/instrumentation/gson-1.6/build.gradle @@ -3,6 +3,7 @@ muzzle { group = 'com.google.code.gson' module = 'gson' versions = '[1.6, ]' + skipVersions = ['1.7'] //only has html assertInverse = true } } diff --git a/dd-java-agent/instrumentation/gson-1.6/src/main/java/datadog/trace/instrumentation/gson/JsonReaderInstrumentation.java b/dd-java-agent/instrumentation/gson-1.6/src/main/java/datadog/trace/instrumentation/gson/JsonReaderInstrumentation.java index f14f39370e1..f59ac0d4cb8 100644 --- a/dd-java-agent/instrumentation/gson-1.6/src/main/java/datadog/trace/instrumentation/gson/JsonReaderInstrumentation.java +++ b/dd-java-agent/instrumentation/gson-1.6/src/main/java/datadog/trace/instrumentation/gson/JsonReaderInstrumentation.java @@ -11,6 +11,7 @@ import com.google.auto.service.AutoService; import datadog.trace.agent.tooling.Instrumenter; +import datadog.trace.agent.tooling.muzzle.Reference; import datadog.trace.api.iast.InstrumentationBridge; import datadog.trace.api.iast.Propagation; import datadog.trace.api.iast.propagation.PropagationModule; @@ -29,6 +30,11 @@ public String instrumentedType() { return "com.google.gson.stream.JsonReader"; } + @Override + public Reference[] additionalMuzzleReferences() { + return new Reference[] {new Reference.Builder("com.google.gson.stream.JsonReader").build()}; + } + @Override public void adviceTransformations(AdviceTransformation transformation) { transformation.applyAdvice( From 50813e8eeee27bb9cb544805af65e81523f4ca42 Mon Sep 17 00:00:00 2001 From: Alejandro Gonzalez Date: Thu, 19 Oct 2023 09:13:48 +0200 Subject: [PATCH 09/18] remove unnecessary exclusions --- .../trace/instrumentation/iastinstrumenter/iast_exclusion.trie | 2 -- 1 file changed, 2 deletions(-) diff --git a/dd-java-agent/instrumentation/iast-instrumenter/src/main/resources/datadog/trace/instrumentation/iastinstrumenter/iast_exclusion.trie b/dd-java-agent/instrumentation/iast-instrumenter/src/main/resources/datadog/trace/instrumentation/iastinstrumenter/iast_exclusion.trie index 4e7d4c9a409..05e3234670b 100644 --- a/dd-java-agent/instrumentation/iast-instrumenter/src/main/resources/datadog/trace/instrumentation/iastinstrumenter/iast_exclusion.trie +++ b/dd-java-agent/instrumentation/iast-instrumenter/src/main/resources/datadog/trace/instrumentation/iastinstrumenter/iast_exclusion.trie @@ -77,8 +77,6 @@ 1 com.google.* #Need for gson propagation 2 com.google.gson.Gson -2 com.google.gson.JsonParser -2 com.google.gson.stream.JsonReader 1 com.googlecode.* 1 com.hazelcast.* 1 com.hdivsecurity.* From c65ffa2dcf3f14588dcb1d1b69db8d22a74199e6 Mon Sep 17 00:00:00 2001 From: Alejandro Gonzalez Date: Wed, 11 Oct 2023 13:59:40 +0200 Subject: [PATCH 10/18] First gson deserialization propagation version, tested for 1.1 --- .../instrumentation/gson/build.gradle | 23 ++++++ .../gson/JsonParserInstrumentation.java | 63 +++++++++++++++ .../gson/JsonParserInstrumentationTest.groovy | 81 +++++++++++++++++++ 3 files changed, 167 insertions(+) create mode 100644 dd-java-agent/instrumentation/gson/build.gradle create mode 100644 dd-java-agent/instrumentation/gson/src/main/java/datadog/trace/instrumentation/gson/JsonParserInstrumentation.java create mode 100644 dd-java-agent/instrumentation/gson/src/test/groovy/datadog/trace/instrumentation/gson/JsonParserInstrumentationTest.groovy diff --git a/dd-java-agent/instrumentation/gson/build.gradle b/dd-java-agent/instrumentation/gson/build.gradle new file mode 100644 index 00000000000..ec0a785c6e7 --- /dev/null +++ b/dd-java-agent/instrumentation/gson/build.gradle @@ -0,0 +1,23 @@ +muzzle { + pass { + group = 'com.google.code.gson' + module = 'gson' + versions = '[1.1,]' + assertInverse = true + } +} + +apply from: "$rootDir/gradle/java.gradle" +apply plugin: 'call-site-instrumentation' + +addTestSuiteForDir('latestDepTest', 'test') + +dependencies { + compileOnly group: 'com.google.code.gson', name: 'gson', version: '1.1' + + testImplementation group: 'com.google.code.gson', name: 'gson', version: '1.1' + + testRuntimeOnly project(':dd-java-agent:instrumentation:iast-instrumenter') + + latestDepTestImplementation group: 'com.google.code.gson', name: 'gson', version: '+' +} diff --git a/dd-java-agent/instrumentation/gson/src/main/java/datadog/trace/instrumentation/gson/JsonParserInstrumentation.java b/dd-java-agent/instrumentation/gson/src/main/java/datadog/trace/instrumentation/gson/JsonParserInstrumentation.java new file mode 100644 index 00000000000..0bdbe7dd167 --- /dev/null +++ b/dd-java-agent/instrumentation/gson/src/main/java/datadog/trace/instrumentation/gson/JsonParserInstrumentation.java @@ -0,0 +1,63 @@ +package datadog.trace.instrumentation.gson; + +import static datadog.trace.agent.tooling.bytebuddy.matcher.NameMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.isConstructor; +import static net.bytebuddy.matcher.ElementMatchers.isMethod; +import static net.bytebuddy.matcher.ElementMatchers.takesArgument; +import static net.bytebuddy.matcher.ElementMatchers.takesArguments; + +import com.google.auto.service.AutoService; +import com.google.gson.JsonPrimitive; +import datadog.trace.agent.tooling.Instrumenter; +import datadog.trace.api.iast.InstrumentationBridge; +import datadog.trace.api.iast.Propagation; +import datadog.trace.api.iast.propagation.PropagationModule; +import net.bytebuddy.asm.Advice; + +@AutoService(Instrumenter.class) +public class JsonParserInstrumentation extends Instrumenter.Iast + implements Instrumenter.ForSingleType { + + public JsonParserInstrumentation() { + super("gson"); + } + + @Override + public String instrumentedType() { + return "com.google.gson.JsonParser"; + } + + @Override + public void adviceTransformations(AdviceTransformation transformation) { + transformation.applyAdvice( + isConstructor().and(takesArguments(1)).and(takesArgument(0, named("java.io.Reader"))), + getClass().getName() + "$ConstructAdvice"); + transformation.applyAdvice( + isMethod().and(takesArguments(0).and(named("JsonString"))), + getClass().getName() + "$ParseAdvice"); + } + + public static class ConstructAdvice { + @Advice.OnMethodExit(suppress = Throwable.class) + @Propagation + public static void afterInit( + @Advice.This Object self, @Advice.Argument(0) final java.io.Reader input) { + final PropagationModule iastModule = InstrumentationBridge.PROPAGATION; + if (iastModule != null && input != null) { + iastModule.taintIfInputIsTainted(self, input); + } + } + } + + public static class ParseAdvice { + @Advice.OnMethodExit(suppress = Throwable.class) + @Propagation + public static void afterParse( + @Advice.This Object self, @Advice.Return final JsonPrimitive result) { + final PropagationModule iastModule = InstrumentationBridge.PROPAGATION; + if (iastModule != null && result != null) { + iastModule.taintIfInputIsTainted(result.getAsString(), self); + } + } + } +} diff --git a/dd-java-agent/instrumentation/gson/src/test/groovy/datadog/trace/instrumentation/gson/JsonParserInstrumentationTest.groovy b/dd-java-agent/instrumentation/gson/src/test/groovy/datadog/trace/instrumentation/gson/JsonParserInstrumentationTest.groovy new file mode 100644 index 00000000000..e6297f9330c --- /dev/null +++ b/dd-java-agent/instrumentation/gson/src/test/groovy/datadog/trace/instrumentation/gson/JsonParserInstrumentationTest.groovy @@ -0,0 +1,81 @@ +package datadog.trace.instrumentation.gson + +import com.google.gson.Gson +import com.google.gson.JsonParser +import datadog.trace.agent.test.AgentTestRunner +import datadog.trace.api.iast.InstrumentationBridge +import datadog.trace.api.iast.propagation.PropagationModule + +class JsonParserInstrumentationTest extends AgentTestRunner { + + @Override + protected void configurePreAgent() { + injectSysConfig("dd.iast.enabled", "true") + } + + void 'Test Gson instrumented'(){ + given: + final gson = new Gson() + + when: + final result = gson.fromJson('{"name": "nameTest", "value" : "valueTest"}', TestBean) + + then: + result instanceof TestBean + result.getName() == 'nameTest' + result.getValue() == 'valueTest' + } + + + void 'test'() { + given: + final module = Mock(PropagationModule) + InstrumentationBridge.registerIastModule(module) + + when: + final parser = new JsonParser(new StringReader(json)) + + then: + 1 * module.taintIfInputIsTainted(_ as JsonParser, _ as StringReader) + 0 * _ + + when: + parser.parse() + + then: + callsAfterParse * module.taintIfInputIsTainted(_ as String, _ as JsonParser) + 0 * _ + + where: + json | callsAfterParse + '"Test"' | 1 + '1' | 0 + '{"name": "nameTest", "value" : "valueTest"}' | 4 + '[{"name": "nameTest", "value" : "valueTest"}]' | 4 + '[{"name": "nameTest", "value" : "valueTest"}, {"name": "nameTest2", "value" : "valueTest2"}]' | 8 + } + + + static final class TestBean { + + private String name + + private String value + + String getName() { + return name + } + + void setName(String name) { + this.name = name + } + + String getValue() { + return value + } + + void setValue(String value) { + this.value = value + } + } +} From 8144934715f294c34484c068bdfe484d69cf3bef Mon Sep 17 00:00:00 2001 From: Alejandro Gonzalez Date: Fri, 13 Oct 2023 13:18:21 +0200 Subject: [PATCH 11/18] Refactor, current instrumentation only works for v1.1 --- .../instrumentation/gson/build.gradle | 23 ------ .../gson/JsonParserInstrumentation.java | 63 --------------- .../gson/JsonParserInstrumentationTest.groovy | 81 ------------------- 3 files changed, 167 deletions(-) delete mode 100644 dd-java-agent/instrumentation/gson/build.gradle delete mode 100644 dd-java-agent/instrumentation/gson/src/main/java/datadog/trace/instrumentation/gson/JsonParserInstrumentation.java delete mode 100644 dd-java-agent/instrumentation/gson/src/test/groovy/datadog/trace/instrumentation/gson/JsonParserInstrumentationTest.groovy diff --git a/dd-java-agent/instrumentation/gson/build.gradle b/dd-java-agent/instrumentation/gson/build.gradle deleted file mode 100644 index ec0a785c6e7..00000000000 --- a/dd-java-agent/instrumentation/gson/build.gradle +++ /dev/null @@ -1,23 +0,0 @@ -muzzle { - pass { - group = 'com.google.code.gson' - module = 'gson' - versions = '[1.1,]' - assertInverse = true - } -} - -apply from: "$rootDir/gradle/java.gradle" -apply plugin: 'call-site-instrumentation' - -addTestSuiteForDir('latestDepTest', 'test') - -dependencies { - compileOnly group: 'com.google.code.gson', name: 'gson', version: '1.1' - - testImplementation group: 'com.google.code.gson', name: 'gson', version: '1.1' - - testRuntimeOnly project(':dd-java-agent:instrumentation:iast-instrumenter') - - latestDepTestImplementation group: 'com.google.code.gson', name: 'gson', version: '+' -} diff --git a/dd-java-agent/instrumentation/gson/src/main/java/datadog/trace/instrumentation/gson/JsonParserInstrumentation.java b/dd-java-agent/instrumentation/gson/src/main/java/datadog/trace/instrumentation/gson/JsonParserInstrumentation.java deleted file mode 100644 index 0bdbe7dd167..00000000000 --- a/dd-java-agent/instrumentation/gson/src/main/java/datadog/trace/instrumentation/gson/JsonParserInstrumentation.java +++ /dev/null @@ -1,63 +0,0 @@ -package datadog.trace.instrumentation.gson; - -import static datadog.trace.agent.tooling.bytebuddy.matcher.NameMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.isConstructor; -import static net.bytebuddy.matcher.ElementMatchers.isMethod; -import static net.bytebuddy.matcher.ElementMatchers.takesArgument; -import static net.bytebuddy.matcher.ElementMatchers.takesArguments; - -import com.google.auto.service.AutoService; -import com.google.gson.JsonPrimitive; -import datadog.trace.agent.tooling.Instrumenter; -import datadog.trace.api.iast.InstrumentationBridge; -import datadog.trace.api.iast.Propagation; -import datadog.trace.api.iast.propagation.PropagationModule; -import net.bytebuddy.asm.Advice; - -@AutoService(Instrumenter.class) -public class JsonParserInstrumentation extends Instrumenter.Iast - implements Instrumenter.ForSingleType { - - public JsonParserInstrumentation() { - super("gson"); - } - - @Override - public String instrumentedType() { - return "com.google.gson.JsonParser"; - } - - @Override - public void adviceTransformations(AdviceTransformation transformation) { - transformation.applyAdvice( - isConstructor().and(takesArguments(1)).and(takesArgument(0, named("java.io.Reader"))), - getClass().getName() + "$ConstructAdvice"); - transformation.applyAdvice( - isMethod().and(takesArguments(0).and(named("JsonString"))), - getClass().getName() + "$ParseAdvice"); - } - - public static class ConstructAdvice { - @Advice.OnMethodExit(suppress = Throwable.class) - @Propagation - public static void afterInit( - @Advice.This Object self, @Advice.Argument(0) final java.io.Reader input) { - final PropagationModule iastModule = InstrumentationBridge.PROPAGATION; - if (iastModule != null && input != null) { - iastModule.taintIfInputIsTainted(self, input); - } - } - } - - public static class ParseAdvice { - @Advice.OnMethodExit(suppress = Throwable.class) - @Propagation - public static void afterParse( - @Advice.This Object self, @Advice.Return final JsonPrimitive result) { - final PropagationModule iastModule = InstrumentationBridge.PROPAGATION; - if (iastModule != null && result != null) { - iastModule.taintIfInputIsTainted(result.getAsString(), self); - } - } - } -} diff --git a/dd-java-agent/instrumentation/gson/src/test/groovy/datadog/trace/instrumentation/gson/JsonParserInstrumentationTest.groovy b/dd-java-agent/instrumentation/gson/src/test/groovy/datadog/trace/instrumentation/gson/JsonParserInstrumentationTest.groovy deleted file mode 100644 index e6297f9330c..00000000000 --- a/dd-java-agent/instrumentation/gson/src/test/groovy/datadog/trace/instrumentation/gson/JsonParserInstrumentationTest.groovy +++ /dev/null @@ -1,81 +0,0 @@ -package datadog.trace.instrumentation.gson - -import com.google.gson.Gson -import com.google.gson.JsonParser -import datadog.trace.agent.test.AgentTestRunner -import datadog.trace.api.iast.InstrumentationBridge -import datadog.trace.api.iast.propagation.PropagationModule - -class JsonParserInstrumentationTest extends AgentTestRunner { - - @Override - protected void configurePreAgent() { - injectSysConfig("dd.iast.enabled", "true") - } - - void 'Test Gson instrumented'(){ - given: - final gson = new Gson() - - when: - final result = gson.fromJson('{"name": "nameTest", "value" : "valueTest"}', TestBean) - - then: - result instanceof TestBean - result.getName() == 'nameTest' - result.getValue() == 'valueTest' - } - - - void 'test'() { - given: - final module = Mock(PropagationModule) - InstrumentationBridge.registerIastModule(module) - - when: - final parser = new JsonParser(new StringReader(json)) - - then: - 1 * module.taintIfInputIsTainted(_ as JsonParser, _ as StringReader) - 0 * _ - - when: - parser.parse() - - then: - callsAfterParse * module.taintIfInputIsTainted(_ as String, _ as JsonParser) - 0 * _ - - where: - json | callsAfterParse - '"Test"' | 1 - '1' | 0 - '{"name": "nameTest", "value" : "valueTest"}' | 4 - '[{"name": "nameTest", "value" : "valueTest"}]' | 4 - '[{"name": "nameTest", "value" : "valueTest"}, {"name": "nameTest2", "value" : "valueTest2"}]' | 8 - } - - - static final class TestBean { - - private String name - - private String value - - String getName() { - return name - } - - void setName(String name) { - this.name = name - } - - String getValue() { - return value - } - - void setValue(String value) { - this.value = value - } - } -} From 83a0d41f90bdcd5ba44f3f92783ffcaac5f469bd Mon Sep 17 00:00:00 2001 From: Alejandro Gonzalez Date: Tue, 17 Oct 2023 07:57:35 +0200 Subject: [PATCH 12/18] Gson instrumentation for 1.4 and 1.5 --- .../trace/instrumentation/iastinstrumenter/iast_exclusion.trie | 1 + 1 file changed, 1 insertion(+) diff --git a/dd-java-agent/instrumentation/iast-instrumenter/src/main/resources/datadog/trace/instrumentation/iastinstrumenter/iast_exclusion.trie b/dd-java-agent/instrumentation/iast-instrumenter/src/main/resources/datadog/trace/instrumentation/iastinstrumenter/iast_exclusion.trie index 05e3234670b..3ba7bc0674c 100644 --- a/dd-java-agent/instrumentation/iast-instrumenter/src/main/resources/datadog/trace/instrumentation/iastinstrumenter/iast_exclusion.trie +++ b/dd-java-agent/instrumentation/iast-instrumenter/src/main/resources/datadog/trace/instrumentation/iastinstrumenter/iast_exclusion.trie @@ -77,6 +77,7 @@ 1 com.google.* #Need for gson propagation 2 com.google.gson.Gson +2 com.google.gson.JsonParser 1 com.googlecode.* 1 com.hazelcast.* 1 com.hdivsecurity.* From 8999064cc74c2bd3184d7d1284c4e98e402c441a Mon Sep 17 00:00:00 2001 From: Alejandro Gonzalez Date: Wed, 18 Oct 2023 08:16:20 +0200 Subject: [PATCH 13/18] Gson instrumentation from 1.6 --- .../trace/instrumentation/iastinstrumenter/iast_exclusion.trie | 1 + 1 file changed, 1 insertion(+) diff --git a/dd-java-agent/instrumentation/iast-instrumenter/src/main/resources/datadog/trace/instrumentation/iastinstrumenter/iast_exclusion.trie b/dd-java-agent/instrumentation/iast-instrumenter/src/main/resources/datadog/trace/instrumentation/iastinstrumenter/iast_exclusion.trie index 3ba7bc0674c..4e7d4c9a409 100644 --- a/dd-java-agent/instrumentation/iast-instrumenter/src/main/resources/datadog/trace/instrumentation/iastinstrumenter/iast_exclusion.trie +++ b/dd-java-agent/instrumentation/iast-instrumenter/src/main/resources/datadog/trace/instrumentation/iastinstrumenter/iast_exclusion.trie @@ -78,6 +78,7 @@ #Need for gson propagation 2 com.google.gson.Gson 2 com.google.gson.JsonParser +2 com.google.gson.stream.JsonReader 1 com.googlecode.* 1 com.hazelcast.* 1 com.hdivsecurity.* From b508a187e396f22520cfdbd1b0dc4c05e2dcde92 Mon Sep 17 00:00:00 2001 From: jean-philippe bempel Date: Tue, 10 Oct 2023 09:59:18 +0200 Subject: [PATCH 14/18] Introduce PII redaction based on keywords Redacts values based on a list of predefined words name are normalized in lower case and by removing special characters: `@`, `$`, `-` and `_` Redaction happening at: - expression language for reference, index and getmember operations - serialization for snapshot or template values including maps - capture of the values from instrumentation For conditions (log or span decoration probes) evaluation of a redacted values triggers an evaluation exception that will be reported as evaluation error into a snapshot. --- .../debugger/el/ValueReferenceResolver.java | 2 + .../datadog/debugger/el/ProbeCondition.java | 46 ++++++++++++++++++- 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/dd-java-agent/agent-debugger/debugger-bootstrap/src/main/java/datadog/trace/bootstrap/debugger/el/ValueReferenceResolver.java b/dd-java-agent/agent-debugger/debugger-bootstrap/src/main/java/datadog/trace/bootstrap/debugger/el/ValueReferenceResolver.java index af355600080..0650e3dfc8a 100644 --- a/dd-java-agent/agent-debugger/debugger-bootstrap/src/main/java/datadog/trace/bootstrap/debugger/el/ValueReferenceResolver.java +++ b/dd-java-agent/agent-debugger/debugger-bootstrap/src/main/java/datadog/trace/bootstrap/debugger/el/ValueReferenceResolver.java @@ -8,6 +8,8 @@ public interface ValueReferenceResolver { Object getMember(Object target, String name); + default void redacted(String expr) {} + default ValueReferenceResolver withExtensions(Map extensions) { return this; } diff --git a/dd-java-agent/agent-debugger/debugger-el/src/main/java/com/datadog/debugger/el/ProbeCondition.java b/dd-java-agent/agent-debugger/debugger-el/src/main/java/com/datadog/debugger/el/ProbeCondition.java index 8ded283ec93..2b56076d567 100644 --- a/dd-java-agent/agent-debugger/debugger-el/src/main/java/com/datadog/debugger/el/ProbeCondition.java +++ b/dd-java-agent/agent-debugger/debugger-el/src/main/java/com/datadog/debugger/el/ProbeCondition.java @@ -11,6 +11,7 @@ import datadog.trace.bootstrap.debugger.el.ValueReferenceResolver; import edu.umd.cs.findbugs.annotations.NonNull; import java.io.IOException; +import java.util.Map; /** Implements expression language for probe condition */ public final class ProbeCondition implements DebuggerScript { @@ -103,14 +104,55 @@ public Boolean execute(ValueReferenceResolver valueRefResolver) { if (when == null) { return true; } - if (when.evaluate(valueRefResolver)) { - then.evaluate(valueRefResolver); + ProbeConditionResolver conditionResolver = new ProbeConditionResolver(valueRefResolver); + if (when.evaluate(conditionResolver)) { + then.evaluate(conditionResolver); + conditionResolver.checkRedacted(); return true; } + conditionResolver.checkRedacted(); return false; } public void accept(Visitor visitor) { when.accept(visitor); } + + private static class ProbeConditionResolver implements ValueReferenceResolver { + private final ValueReferenceResolver delegate; + private String expr; + private boolean redacted; + + public ProbeConditionResolver(ValueReferenceResolver delegate) { + this.delegate = delegate; + } + + @Override + public Object lookup(String name) { + return delegate.lookup(name); + } + + @Override + public Object getMember(Object target, String name) { + return delegate.getMember(target, name); + } + + @Override + public void redacted(String expr) { + this.redacted = true; + this.expr = expr; + } + + public void checkRedacted() { + if (redacted) { + throw new EvaluationException( + "Could not evaluate the expression because '" + expr + "' was redacted", expr); + } + } + + @Override + public ValueReferenceResolver withExtensions(Map extensions) { + return delegate.withExtensions(extensions); + } + } } From 503d337a9fdf2adc246b49f50c8ec69ebe0c3a6f Mon Sep 17 00:00:00 2001 From: jean-philippe bempel Date: Mon, 16 Oct 2023 09:55:00 +0200 Subject: [PATCH 15/18] Throw exception on expression language in any case --- .../debugger/el/ValueReferenceResolver.java | 2 - .../datadog/debugger/el/ProbeCondition.java | 46 +------------------ 2 files changed, 2 insertions(+), 46 deletions(-) diff --git a/dd-java-agent/agent-debugger/debugger-bootstrap/src/main/java/datadog/trace/bootstrap/debugger/el/ValueReferenceResolver.java b/dd-java-agent/agent-debugger/debugger-bootstrap/src/main/java/datadog/trace/bootstrap/debugger/el/ValueReferenceResolver.java index 0650e3dfc8a..af355600080 100644 --- a/dd-java-agent/agent-debugger/debugger-bootstrap/src/main/java/datadog/trace/bootstrap/debugger/el/ValueReferenceResolver.java +++ b/dd-java-agent/agent-debugger/debugger-bootstrap/src/main/java/datadog/trace/bootstrap/debugger/el/ValueReferenceResolver.java @@ -8,8 +8,6 @@ public interface ValueReferenceResolver { Object getMember(Object target, String name); - default void redacted(String expr) {} - default ValueReferenceResolver withExtensions(Map extensions) { return this; } diff --git a/dd-java-agent/agent-debugger/debugger-el/src/main/java/com/datadog/debugger/el/ProbeCondition.java b/dd-java-agent/agent-debugger/debugger-el/src/main/java/com/datadog/debugger/el/ProbeCondition.java index 2b56076d567..8ded283ec93 100644 --- a/dd-java-agent/agent-debugger/debugger-el/src/main/java/com/datadog/debugger/el/ProbeCondition.java +++ b/dd-java-agent/agent-debugger/debugger-el/src/main/java/com/datadog/debugger/el/ProbeCondition.java @@ -11,7 +11,6 @@ import datadog.trace.bootstrap.debugger.el.ValueReferenceResolver; import edu.umd.cs.findbugs.annotations.NonNull; import java.io.IOException; -import java.util.Map; /** Implements expression language for probe condition */ public final class ProbeCondition implements DebuggerScript { @@ -104,55 +103,14 @@ public Boolean execute(ValueReferenceResolver valueRefResolver) { if (when == null) { return true; } - ProbeConditionResolver conditionResolver = new ProbeConditionResolver(valueRefResolver); - if (when.evaluate(conditionResolver)) { - then.evaluate(conditionResolver); - conditionResolver.checkRedacted(); + if (when.evaluate(valueRefResolver)) { + then.evaluate(valueRefResolver); return true; } - conditionResolver.checkRedacted(); return false; } public void accept(Visitor visitor) { when.accept(visitor); } - - private static class ProbeConditionResolver implements ValueReferenceResolver { - private final ValueReferenceResolver delegate; - private String expr; - private boolean redacted; - - public ProbeConditionResolver(ValueReferenceResolver delegate) { - this.delegate = delegate; - } - - @Override - public Object lookup(String name) { - return delegate.lookup(name); - } - - @Override - public Object getMember(Object target, String name) { - return delegate.getMember(target, name); - } - - @Override - public void redacted(String expr) { - this.redacted = true; - this.expr = expr; - } - - public void checkRedacted() { - if (redacted) { - throw new EvaluationException( - "Could not evaluate the expression because '" + expr + "' was redacted", expr); - } - } - - @Override - public ValueReferenceResolver withExtensions(Map extensions) { - return delegate.withExtensions(extensions); - } - } } From 7cfac2a251a0a50dfeb16cd70adba6c88688fb87 Mon Sep 17 00:00:00 2001 From: Alejandro Gonzalez Date: Thu, 19 Oct 2023 09:13:48 +0200 Subject: [PATCH 16/18] remove unnecessary exclusions --- .../trace/instrumentation/iastinstrumenter/iast_exclusion.trie | 2 -- 1 file changed, 2 deletions(-) diff --git a/dd-java-agent/instrumentation/iast-instrumenter/src/main/resources/datadog/trace/instrumentation/iastinstrumenter/iast_exclusion.trie b/dd-java-agent/instrumentation/iast-instrumenter/src/main/resources/datadog/trace/instrumentation/iastinstrumenter/iast_exclusion.trie index 4e7d4c9a409..05e3234670b 100644 --- a/dd-java-agent/instrumentation/iast-instrumenter/src/main/resources/datadog/trace/instrumentation/iastinstrumenter/iast_exclusion.trie +++ b/dd-java-agent/instrumentation/iast-instrumenter/src/main/resources/datadog/trace/instrumentation/iastinstrumenter/iast_exclusion.trie @@ -77,8 +77,6 @@ 1 com.google.* #Need for gson propagation 2 com.google.gson.Gson -2 com.google.gson.JsonParser -2 com.google.gson.stream.JsonReader 1 com.googlecode.* 1 com.hazelcast.* 1 com.hdivsecurity.* From af5be912d02e8ae8e6435d552098d61dc743f9aa Mon Sep 17 00:00:00 2001 From: Alejandro Gonzalez Date: Mon, 23 Oct 2023 13:10:22 +0200 Subject: [PATCH 17/18] Add instrumentation to constructor with InputStream and ReInit methods --- .../gson/JsonParserInstrumentation.java | 20 +++++++++- .../gson/JsonParserInstrumentationTest.groovy | 37 +++++++++++-------- 2 files changed, 39 insertions(+), 18 deletions(-) diff --git a/dd-java-agent/instrumentation/gson-1.1/src/main/java/datadog/trace/instrumentation/gson/JsonParserInstrumentation.java b/dd-java-agent/instrumentation/gson-1.1/src/main/java/datadog/trace/instrumentation/gson/JsonParserInstrumentation.java index 0141bc5fed4..66eb30b007c 100644 --- a/dd-java-agent/instrumentation/gson-1.1/src/main/java/datadog/trace/instrumentation/gson/JsonParserInstrumentation.java +++ b/dd-java-agent/instrumentation/gson-1.1/src/main/java/datadog/trace/instrumentation/gson/JsonParserInstrumentation.java @@ -13,6 +13,7 @@ import datadog.trace.api.iast.InstrumentationBridge; import datadog.trace.api.iast.Propagation; import datadog.trace.api.iast.propagation.PropagationModule; +import java.io.InputStream; import net.bytebuddy.asm.Advice; @AutoService(Instrumenter.class) @@ -43,7 +44,22 @@ public void adviceTransformations(AdviceTransformation transformation) { isConstructor().and(takesArguments(1)).and(takesArgument(0, named("java.io.Reader"))), getClass().getName() + "$ConstructAdvice"); transformation.applyAdvice( - isMethod().and(takesArguments(0).and(named("JsonString"))), + isConstructor().and(takesArguments(2)).and(takesArguments(InputStream.class, String.class)), + getClass().getName() + "$ConstructAdvice"); + transformation.applyAdvice( + isMethod() + .and(named("ReInit")) + .and(takesArguments(1)) + .and(takesArgument(0, named("java.io.Reader"))), + getClass().getName() + "$ConstructAdvice"); + transformation.applyAdvice( + isMethod() + .and(named("ReInit")) + .and(takesArguments(2)) + .and(takesArguments(InputStream.class, String.class)), + getClass().getName() + "$ConstructAdvice"); + transformation.applyAdvice( + isMethod().and(named("JsonString")).and(takesArguments(0)), getClass().getName() + "$ParseAdvice"); } @@ -51,7 +67,7 @@ public static class ConstructAdvice { @Advice.OnMethodExit(suppress = Throwable.class) @Propagation public static void afterInit( - @Advice.This Object self, @Advice.Argument(0) final java.io.Reader input) { + @Advice.This Object self, @Advice.Argument(0) final java.lang.Object input) { final PropagationModule iastModule = InstrumentationBridge.PROPAGATION; if (iastModule != null && input != null) { iastModule.taintIfInputIsTainted(self, input); diff --git a/dd-java-agent/instrumentation/gson-1.1/src/test/groovy/datadog/trace/instrumentation/gson/JsonParserInstrumentationTest.groovy b/dd-java-agent/instrumentation/gson-1.1/src/test/groovy/datadog/trace/instrumentation/gson/JsonParserInstrumentationTest.groovy index e6297f9330c..467eed1d85a 100644 --- a/dd-java-agent/instrumentation/gson-1.1/src/test/groovy/datadog/trace/instrumentation/gson/JsonParserInstrumentationTest.groovy +++ b/dd-java-agent/instrumentation/gson-1.1/src/test/groovy/datadog/trace/instrumentation/gson/JsonParserInstrumentationTest.groovy @@ -31,12 +31,20 @@ class JsonParserInstrumentationTest extends AgentTestRunner { given: final module = Mock(PropagationModule) InstrumentationBridge.registerIastModule(module) + final input = inputClass.newInstance(inputClass == StringReader ? json : json.getBytes()) when: - final parser = new JsonParser(new StringReader(json)) + final parser = new JsonParser(input) then: - 1 * module.taintIfInputIsTainted(_ as JsonParser, _ as StringReader) + 1 * module.taintIfInputIsTainted(_ as JsonParser, input) + 0 * _ + + when: + parser.ReInit(input) + + then: + 1 * module.taintIfInputIsTainted(_ as JsonParser, input) 0 * _ when: @@ -47,12 +55,17 @@ class JsonParserInstrumentationTest extends AgentTestRunner { 0 * _ where: - json | callsAfterParse - '"Test"' | 1 - '1' | 0 - '{"name": "nameTest", "value" : "valueTest"}' | 4 - '[{"name": "nameTest", "value" : "valueTest"}]' | 4 - '[{"name": "nameTest", "value" : "valueTest"}, {"name": "nameTest2", "value" : "valueTest2"}]' | 8 + json | inputClass | callsAfterParse + '"Test"' | StringReader | 1 + '1'| StringReader| 0 + '{"name": "nameTest", "value" : "valueTest"}'| StringReader| 4 + '[{"name": "nameTest", "value" : "valueTest"}]'| StringReader| 4 + '[{"name": "nameTest", "value" : "valueTest"}, {"name": "nameTest2", "value" : "valueTest2"}]'| StringReader | 8 + '"Test"' | StringReader| 1 + '1'| ByteArrayInputStream | 0 + '{"name": "nameTest", "value" : "valueTest"}'| ByteArrayInputStream | 4 + '[{"name": "nameTest", "value" : "valueTest"}]'| ByteArrayInputStream | 4 + '[{"name": "nameTest", "value" : "valueTest"}, {"name": "nameTest2", "value" : "valueTest2"}]'| ByteArrayInputStream | 8 } @@ -66,16 +79,8 @@ class JsonParserInstrumentationTest extends AgentTestRunner { return name } - void setName(String name) { - this.name = name - } - String getValue() { return value } - - void setValue(String value) { - this.value = value - } } } From 3d3f83ef8895a125330e9717b900b968d7bbf0a6 Mon Sep 17 00:00:00 2001 From: Alejandro Gonzalez Date: Mon, 23 Oct 2023 13:13:14 +0200 Subject: [PATCH 18/18] Gson IAST source propagation for version 1.1 --- .../agent-jmxfetch/integrations-core | 2 +- .../instrumentation/gson-1.4/build.gradle | 23 ------ .../gson/JsonParserJavaccInstrumentation.java | 69 ---------------- ...JsonParserJavaccInstrumentationTest.groovy | 76 ------------------ .../instrumentation/gson-1.6/build.gradle | 24 ------ .../gson/JsonReaderInstrumentation.java | 73 ----------------- .../gson/JsonReaderInstrumentationTest.groovy | 79 ------------------- settings.gradle | 2 - 8 files changed, 1 insertion(+), 347 deletions(-) delete mode 100644 dd-java-agent/instrumentation/gson-1.4/build.gradle delete mode 100644 dd-java-agent/instrumentation/gson-1.4/src/main/java/datadog/trace/instrumentation/gson/JsonParserJavaccInstrumentation.java delete mode 100644 dd-java-agent/instrumentation/gson-1.4/src/test/groovy/datadog/trace/instrumentation/gson/JsonParserJavaccInstrumentationTest.groovy delete mode 100644 dd-java-agent/instrumentation/gson-1.6/build.gradle delete mode 100644 dd-java-agent/instrumentation/gson-1.6/src/main/java/datadog/trace/instrumentation/gson/JsonReaderInstrumentation.java delete mode 100644 dd-java-agent/instrumentation/gson-1.6/src/test/groovy/datadog/trace/instrumentation/gson/JsonReaderInstrumentationTest.groovy diff --git a/dd-java-agent/agent-jmxfetch/integrations-core b/dd-java-agent/agent-jmxfetch/integrations-core index 03aed80d105..899ada25e4c 160000 --- a/dd-java-agent/agent-jmxfetch/integrations-core +++ b/dd-java-agent/agent-jmxfetch/integrations-core @@ -1 +1 @@ -Subproject commit 03aed80d105aa81b047e74c6da086165cac5ff6f +Subproject commit 899ada25e4cddb58f5c51d9e1e97ef85300f6d51 diff --git a/dd-java-agent/instrumentation/gson-1.4/build.gradle b/dd-java-agent/instrumentation/gson-1.4/build.gradle deleted file mode 100644 index 5a5e9dc40ea..00000000000 --- a/dd-java-agent/instrumentation/gson-1.4/build.gradle +++ /dev/null @@ -1,23 +0,0 @@ -muzzle { - pass { - group = 'com.google.code.gson' - module = 'gson' - versions = '[1.4, 1.5]' - assertInverse = true - } -} - -apply from: "$rootDir/gradle/java.gradle" -apply plugin: 'call-site-instrumentation' - -addTestSuiteForDir('latestDepTest', 'test') - -dependencies { - compileOnly group: 'com.google.code.gson', name: 'gson', version: '1.4' - - testImplementation group: 'com.google.code.gson', name: 'gson', version: '1.4' - - testRuntimeOnly project(':dd-java-agent:instrumentation:iast-instrumenter') - - latestDepTestImplementation group: 'com.google.code.gson', name: 'gson', version: '1.5' -} diff --git a/dd-java-agent/instrumentation/gson-1.4/src/main/java/datadog/trace/instrumentation/gson/JsonParserJavaccInstrumentation.java b/dd-java-agent/instrumentation/gson-1.4/src/main/java/datadog/trace/instrumentation/gson/JsonParserJavaccInstrumentation.java deleted file mode 100644 index 81676d62ae7..00000000000 --- a/dd-java-agent/instrumentation/gson-1.4/src/main/java/datadog/trace/instrumentation/gson/JsonParserJavaccInstrumentation.java +++ /dev/null @@ -1,69 +0,0 @@ -package datadog.trace.instrumentation.gson; - -import static datadog.trace.agent.tooling.bytebuddy.matcher.NameMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.isConstructor; -import static net.bytebuddy.matcher.ElementMatchers.isMethod; -import static net.bytebuddy.matcher.ElementMatchers.takesArgument; -import static net.bytebuddy.matcher.ElementMatchers.takesArguments; - -import com.google.auto.service.AutoService; -import com.google.gson.JsonPrimitive; -import datadog.trace.agent.tooling.Instrumenter; -import datadog.trace.agent.tooling.muzzle.Reference; -import datadog.trace.api.iast.InstrumentationBridge; -import datadog.trace.api.iast.Propagation; -import datadog.trace.api.iast.propagation.PropagationModule; -import net.bytebuddy.asm.Advice; - -@AutoService(Instrumenter.class) -public class JsonParserJavaccInstrumentation extends Instrumenter.Iast - implements Instrumenter.ForSingleType { - - public JsonParserJavaccInstrumentation() { - super("gson"); - } - - @Override - public String instrumentedType() { - return "com.google.gson.JsonParserJavacc"; - } - - @Override - public Reference[] additionalMuzzleReferences() { - return new Reference[] {new Reference.Builder("com.google.gson.JsonParserJavacc").build()}; - } - - @Override - public void adviceTransformations(AdviceTransformation transformation) { - transformation.applyAdvice( - isConstructor().and(takesArguments(1)).and(takesArgument(0, named("java.io.Reader"))), - getClass().getName() + "$ConstructAdvice"); - transformation.applyAdvice( - isMethod().and(takesArguments(0).and(named("JsonString"))), - getClass().getName() + "$ParseAdvice"); - } - - public static class ConstructAdvice { - @Advice.OnMethodExit(suppress = Throwable.class) - @Propagation - public static void afterInit( - @Advice.This Object self, @Advice.Argument(0) final java.io.Reader input) { - final PropagationModule iastModule = InstrumentationBridge.PROPAGATION; - if (iastModule != null && input != null) { - iastModule.taintIfInputIsTainted(self, input); - } - } - } - - public static class ParseAdvice { - @Advice.OnMethodExit(suppress = Throwable.class) - @Propagation - public static void afterParse( - @Advice.This Object self, @Advice.Return final JsonPrimitive result) { - final PropagationModule iastModule = InstrumentationBridge.PROPAGATION; - if (iastModule != null && result != null) { - iastModule.taintIfInputIsTainted(result.getAsString(), self); - } - } - } -} diff --git a/dd-java-agent/instrumentation/gson-1.4/src/test/groovy/datadog/trace/instrumentation/gson/JsonParserJavaccInstrumentationTest.groovy b/dd-java-agent/instrumentation/gson-1.4/src/test/groovy/datadog/trace/instrumentation/gson/JsonParserJavaccInstrumentationTest.groovy deleted file mode 100644 index 0db5084387c..00000000000 --- a/dd-java-agent/instrumentation/gson-1.4/src/test/groovy/datadog/trace/instrumentation/gson/JsonParserJavaccInstrumentationTest.groovy +++ /dev/null @@ -1,76 +0,0 @@ -package datadog.trace.instrumentation.gson - -import com.google.gson.Gson -import com.google.gson.JsonParser -import com.google.gson.JsonParserJavacc -import datadog.trace.agent.test.AgentTestRunner -import datadog.trace.api.iast.InstrumentationBridge -import datadog.trace.api.iast.propagation.PropagationModule - -class JsonParserJavaccInstrumentationTest extends AgentTestRunner { - - @Override - protected void configurePreAgent() { - injectSysConfig("dd.iast.enabled", "true") - } - - void 'Test Gson instrumented'(){ - given: - final gson = new Gson() - - when: - final result = gson.fromJson('{"name": "nameTest", "value" : "valueTest"}', TestBean) - - then: - result instanceof TestBean - result.getName() == 'nameTest' - result.getValue() == 'valueTest' - } - - - void 'test'() { - given: - final module = Mock(PropagationModule) - InstrumentationBridge.registerIastModule(module) - - when: - new JsonParser().parse(new StringReader(json)) - - then: - 1 * module.taintIfInputIsTainted(_ as JsonParserJavacc, _ as StringReader) - callsAfterParse * module.taintIfInputIsTainted(_ as String, _ as JsonParserJavacc) - 0 * _ - - where: - json | callsAfterParse - '"Test"' | 1 - '1' | 0 - '{"name": "nameTest", "value" : "valueTest"}' | 4 - '[{"name": "nameTest", "value" : "valueTest"}]' | 4 - '[{"name": "nameTest", "value" : "valueTest"}, {"name": "nameTest2", "value" : "valueTest2"}]' | 8 - } - - - static final class TestBean { - - private String name - - private String value - - String getName() { - return name - } - - void setName(String name) { - this.name = name - } - - String getValue() { - return value - } - - void setValue(String value) { - this.value = value - } - } -} diff --git a/dd-java-agent/instrumentation/gson-1.6/build.gradle b/dd-java-agent/instrumentation/gson-1.6/build.gradle deleted file mode 100644 index 92ae4ba9947..00000000000 --- a/dd-java-agent/instrumentation/gson-1.6/build.gradle +++ /dev/null @@ -1,24 +0,0 @@ -muzzle { - pass { - group = 'com.google.code.gson' - module = 'gson' - versions = '[1.6, ]' - skipVersions = ['1.7'] //only has html - assertInverse = true - } -} - -apply from: "$rootDir/gradle/java.gradle" -apply plugin: 'call-site-instrumentation' - -addTestSuiteForDir('latestDepTest', 'test') - -dependencies { - compileOnly group: 'com.google.code.gson', name: 'gson', version: '1.6' - - testImplementation group: 'com.google.code.gson', name: 'gson', version: '1.6' - - testRuntimeOnly project(':dd-java-agent:instrumentation:iast-instrumenter') - - latestDepTestImplementation group: 'com.google.code.gson', name: 'gson', version: '+' -} diff --git a/dd-java-agent/instrumentation/gson-1.6/src/main/java/datadog/trace/instrumentation/gson/JsonReaderInstrumentation.java b/dd-java-agent/instrumentation/gson-1.6/src/main/java/datadog/trace/instrumentation/gson/JsonReaderInstrumentation.java deleted file mode 100644 index f59ac0d4cb8..00000000000 --- a/dd-java-agent/instrumentation/gson-1.6/src/main/java/datadog/trace/instrumentation/gson/JsonReaderInstrumentation.java +++ /dev/null @@ -1,73 +0,0 @@ -package datadog.trace.instrumentation.gson; - -import static datadog.trace.agent.tooling.bytebuddy.matcher.NameMatchers.named; -import static datadog.trace.agent.tooling.bytebuddy.matcher.NameMatchers.namedOneOf; -import static net.bytebuddy.matcher.ElementMatchers.isConstructor; -import static net.bytebuddy.matcher.ElementMatchers.isMethod; -import static net.bytebuddy.matcher.ElementMatchers.isPublic; -import static net.bytebuddy.matcher.ElementMatchers.returns; -import static net.bytebuddy.matcher.ElementMatchers.takesArgument; -import static net.bytebuddy.matcher.ElementMatchers.takesArguments; - -import com.google.auto.service.AutoService; -import datadog.trace.agent.tooling.Instrumenter; -import datadog.trace.agent.tooling.muzzle.Reference; -import datadog.trace.api.iast.InstrumentationBridge; -import datadog.trace.api.iast.Propagation; -import datadog.trace.api.iast.propagation.PropagationModule; -import net.bytebuddy.asm.Advice; - -@AutoService(Instrumenter.class) -public class JsonReaderInstrumentation extends Instrumenter.Iast - implements Instrumenter.ForSingleType { - - public JsonReaderInstrumentation() { - super("gson"); - } - - @Override - public String instrumentedType() { - return "com.google.gson.stream.JsonReader"; - } - - @Override - public Reference[] additionalMuzzleReferences() { - return new Reference[] {new Reference.Builder("com.google.gson.stream.JsonReader").build()}; - } - - @Override - public void adviceTransformations(AdviceTransformation transformation) { - transformation.applyAdvice( - isConstructor().and(takesArguments(1)).and(takesArgument(0, named("java.io.Reader"))), - getClass().getName() + "$ConstructAdvice"); - transformation.applyAdvice( - isMethod() - .and(isPublic()) - .and(returns(String.class)) - .and(namedOneOf("nextName", "nextString")), - getClass().getName() + "$MethodAdvice"); - } - - public static class ConstructAdvice { - @Advice.OnMethodExit(suppress = Throwable.class) - @Propagation - public static void afterInit( - @Advice.This Object self, @Advice.Argument(0) final java.io.Reader input) { - final PropagationModule iastModule = InstrumentationBridge.PROPAGATION; - if (iastModule != null && input != null) { - iastModule.taintIfInputIsTainted(self, input); - } - } - } - - public static class MethodAdvice { - @Advice.OnMethodExit(suppress = Throwable.class) - @Propagation - public static void afterMethod(@Advice.This Object self, @Advice.Return final String result) { - final PropagationModule iastModule = InstrumentationBridge.PROPAGATION; - if (iastModule != null && result != null) { - iastModule.taintIfInputIsTainted(result, self); - } - } - } -} diff --git a/dd-java-agent/instrumentation/gson-1.6/src/test/groovy/datadog/trace/instrumentation/gson/JsonReaderInstrumentationTest.groovy b/dd-java-agent/instrumentation/gson-1.6/src/test/groovy/datadog/trace/instrumentation/gson/JsonReaderInstrumentationTest.groovy deleted file mode 100644 index 84b03668ca0..00000000000 --- a/dd-java-agent/instrumentation/gson-1.6/src/test/groovy/datadog/trace/instrumentation/gson/JsonReaderInstrumentationTest.groovy +++ /dev/null @@ -1,79 +0,0 @@ -package datadog.trace.instrumentation.gson - -import com.google.gson.Gson -import com.google.gson.stream.JsonReader -import datadog.trace.agent.test.AgentTestRunner -import datadog.trace.api.iast.InstrumentationBridge -import datadog.trace.api.iast.propagation.PropagationModule - -class JsonReaderInstrumentationTest extends AgentTestRunner { - - @Override - protected void configurePreAgent() { - injectSysConfig("dd.iast.enabled", "true") - } - - void 'Test Gson instrumented'(){ - given: - final gson = new Gson() - - when: - final result = gson.fromJson('{"name": "nameTest", "value" : "valueTest"}', TestBean) - - then: - result instanceof TestBean - result.getName() == 'nameTest' - result.getValue() == 'valueTest' - } - - void 'test'() { - given: - final module = Mock(PropagationModule) - InstrumentationBridge.registerIastModule(module) - final gson = new Gson() - - when: - final reader = new JsonReader(new StringReader(json)) - - then: - 1 * module.taintIfInputIsTainted(_ as JsonReader, _ as StringReader) - - when: - gson.fromJson(reader, clazz) - - then: - calls * module.taintIfInputIsTainted(_ as String, _ as JsonReader) - 0 * _ - - where: - json | clazz | calls - '"Test"' | String | 1 - '{"name": "nameTest", "value" : "valueTest"}' | TestBean | 4 - '[{"name": "nameTest", "value" : "valueTest"}]' | TestBean[] | 4 - '[{"name": "nameTest", "value" : "valueTest"}, {"name": "nameTest2", "value" : "valueTest2"}]' | TestBean[].class | 8 - } - - - static final class TestBean { - - private String name - - private String value - - String getName() { - return name - } - - void setName(String name) { - this.name = name - } - - String getValue() { - return value - } - - void setValue(String value) { - this.value = value - } - } -} diff --git a/settings.gradle b/settings.gradle index e9e71db27b7..781451af15b 100644 --- a/settings.gradle +++ b/settings.gradle @@ -213,8 +213,6 @@ include ':dd-java-agent:instrumentation:grizzly-client-1.9' include ':dd-java-agent:instrumentation:grizzly-http-2.3.20' include ':dd-java-agent:instrumentation:grpc-1.5' include ':dd-java-agent:instrumentation:gson-1.1' -include ':dd-java-agent:instrumentation:gson-1.4' -include ':dd-java-agent:instrumentation:gson-1.6' include ':dd-java-agent:instrumentation:guava-10' include ':dd-java-agent:instrumentation:hazelcast-3.6' include ':dd-java-agent:instrumentation:hazelcast-3.9'