-
Notifications
You must be signed in to change notification settings - Fork 292
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix jackson json parser propagation for field names (#7606)
- Loading branch information
Showing
41 changed files
with
1,308 additions
and
66 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
23 changes: 23 additions & 0 deletions
23
dd-java-agent/instrumentation/jackson-core/jackson-core-2.12/build.gradle
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
muzzle { | ||
pass { | ||
group = 'com.fasterxml.jackson.core' | ||
module = 'jackson-core' | ||
versions = "[2.12.0, 2.16.0)" | ||
} | ||
} | ||
|
||
apply from: "$rootDir/gradle/java.gradle" | ||
|
||
addTestSuiteForDir('latestDepTest', 'test') | ||
|
||
final jacksonVersion = '2.12.0' | ||
dependencies { | ||
compileOnly(group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: jacksonVersion) | ||
compileOnly(group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: jacksonVersion) | ||
|
||
testImplementation(group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: jacksonVersion) | ||
testImplementation(group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: jacksonVersion) | ||
|
||
latestDepTestImplementation group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: '2.15.+' | ||
latestDepTestImplementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.15.+' | ||
} |
11 changes: 11 additions & 0 deletions
11
.../jackson-core-2.12/src/main/java/com/fasterxml/jackson/core/json/JsonParser212Helper.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package com.fasterxml.jackson.core.json; | ||
|
||
import com.fasterxml.jackson.core.sym.ByteQuadsCanonicalizer212Helper; | ||
|
||
public final class JsonParser212Helper { | ||
private JsonParser212Helper() {} | ||
|
||
public static boolean fetchIntern(UTF8StreamJsonParser jsonParser) { | ||
return ByteQuadsCanonicalizer212Helper.fetchIntern(jsonParser._symbols); | ||
} | ||
} |
9 changes: 9 additions & 0 deletions
9
...re-2.12/src/main/java/com/fasterxml/jackson/core/sym/ByteQuadsCanonicalizer212Helper.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package com.fasterxml.jackson.core.sym; | ||
|
||
public final class ByteQuadsCanonicalizer212Helper { | ||
private ByteQuadsCanonicalizer212Helper() {} | ||
|
||
public static boolean fetchIntern(ByteQuadsCanonicalizer symbols) { | ||
return symbols._intern; | ||
} | ||
} |
103 changes: 103 additions & 0 deletions
103
.../main/java/datadog/trace/instrumentation/jackson_2_12/core/JsonParserInstrumentation.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
package datadog.trace.instrumentation.jackson_2_12.core; | ||
|
||
import static datadog.trace.agent.tooling.bytebuddy.matcher.ClassLoaderMatchers.hasClassNamed; | ||
import static datadog.trace.agent.tooling.bytebuddy.matcher.HierarchyMatchers.declaresMethod; | ||
import static datadog.trace.agent.tooling.bytebuddy.matcher.HierarchyMatchers.extendsClass; | ||
import static datadog.trace.agent.tooling.bytebuddy.matcher.NameMatchers.*; | ||
import static datadog.trace.agent.tooling.bytebuddy.matcher.NameMatchers.named; | ||
import static datadog.trace.agent.tooling.bytebuddy.matcher.NameMatchers.namedOneOf; | ||
import static java.util.Collections.singletonMap; | ||
import static net.bytebuddy.matcher.ElementMatchers.*; | ||
|
||
import com.fasterxml.jackson.core.JsonParser; | ||
import com.fasterxml.jackson.core.JsonToken; | ||
import com.fasterxml.jackson.core.json.JsonParser212Helper; | ||
import com.fasterxml.jackson.core.json.UTF8StreamJsonParser; | ||
import com.google.auto.service.AutoService; | ||
import datadog.trace.agent.tooling.Instrumenter; | ||
import datadog.trace.agent.tooling.InstrumenterModule; | ||
import datadog.trace.api.iast.Propagation; | ||
import datadog.trace.bootstrap.ContextStore; | ||
import datadog.trace.bootstrap.InstrumentationContext; | ||
import datadog.trace.bootstrap.instrumentation.iast.NamedContext; | ||
import java.util.Map; | ||
import net.bytebuddy.asm.Advice; | ||
import net.bytebuddy.description.type.TypeDescription; | ||
import net.bytebuddy.matcher.ElementMatcher; | ||
|
||
@AutoService(InstrumenterModule.class) | ||
public class JsonParserInstrumentation extends InstrumenterModule.Iast | ||
implements Instrumenter.ForTypeHierarchy { | ||
|
||
static final String TARGET_TYPE = "com.fasterxml.jackson.core.JsonParser"; | ||
static final ElementMatcher.Junction<ClassLoader> VERSION_POST_2_8_0_AND_PRE_2_12_0 = | ||
hasClassNamed("com.fasterxml.jackson.core.StreamReadCapability") | ||
.and(not(hasClassNamed("com.fasterxml.jackson.core.StreamWriteConstraints"))); | ||
|
||
public JsonParserInstrumentation() { | ||
super("jackson", "jackson-2_12"); | ||
} | ||
|
||
@Override | ||
public void methodAdvice(MethodTransformer transformer) { | ||
final String className = JsonParserInstrumentation.class.getName(); | ||
transformer.applyAdvice( | ||
namedOneOf("getCurrentName", "nextFieldName") | ||
.and(isPublic()) | ||
.and(takesNoArguments()) | ||
.and(returns(String.class)), | ||
className + "$NameAdvice"); | ||
} | ||
|
||
@Override | ||
public String hierarchyMarkerType() { | ||
return TARGET_TYPE; | ||
} | ||
|
||
@Override | ||
public ElementMatcher<TypeDescription> hierarchyMatcher() { | ||
return declaresMethod(namedOneOf("getCurrentName", "nextFieldName")) | ||
.and( | ||
extendsClass(named(hierarchyMarkerType())) | ||
.and(namedNoneOf("com.fasterxml.jackson.core.base.ParserMinimalBase"))); | ||
} | ||
|
||
@Override | ||
public ElementMatcher.Junction<ClassLoader> classLoaderMatcher() { | ||
return VERSION_POST_2_8_0_AND_PRE_2_12_0; | ||
} | ||
|
||
@Override | ||
public Map<String, String> contextStore() { | ||
return singletonMap(TARGET_TYPE, "datadog.trace.bootstrap.instrumentation.iast.NamedContext"); | ||
} | ||
|
||
@Override | ||
public String[] helperClassNames() { | ||
return new String[] { | ||
"com.fasterxml.jackson.core.json" + ".JsonParser212Helper", | ||
"com.fasterxml.jackson.core.sym" + ".ByteQuadsCanonicalizer212Helper", | ||
}; | ||
} | ||
|
||
public static class NameAdvice { | ||
|
||
@Advice.OnMethodExit(suppress = Throwable.class) | ||
@Propagation | ||
public static void onExit(@Advice.This JsonParser jsonParser, @Advice.Return String result) { | ||
if (jsonParser != null | ||
&& result != null | ||
&& jsonParser.getCurrentToken() == JsonToken.FIELD_NAME) { | ||
final ContextStore<JsonParser, NamedContext> store = | ||
InstrumentationContext.get(JsonParser.class, NamedContext.class); | ||
final NamedContext context = NamedContext.getOrCreate(store, jsonParser); | ||
if (jsonParser instanceof UTF8StreamJsonParser | ||
&& JsonParser212Helper.fetchIntern((UTF8StreamJsonParser) jsonParser)) { | ||
context.setCurrentName(result); | ||
return; | ||
} | ||
context.taintName(result); | ||
} | ||
} | ||
} | ||
} |
98 changes: 98 additions & 0 deletions
98
...groovy/datadog/trace/instrumentation/jackson212/core/JsonParserInstrumentationTest.groovy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
package datadog.trace.instrumentation.jackson212.core | ||
|
||
import com.fasterxml.jackson.databind.ObjectMapper | ||
import datadog.trace.agent.test.AgentTestRunner | ||
import datadog.trace.api.iast.InstrumentationBridge | ||
import datadog.trace.api.iast.SourceTypes | ||
import datadog.trace.api.iast.Taintable | ||
import datadog.trace.api.iast.propagation.PropagationModule | ||
import groovy.json.JsonOutput | ||
|
||
import java.nio.charset.Charset | ||
|
||
class JsonParserInstrumentationTest extends AgentTestRunner { | ||
|
||
private final static String JSON_STRING = '{"root":"root_value","nested":["array_0","array_1"]}' | ||
|
||
@Override | ||
protected void configurePreAgent() { | ||
injectSysConfig("dd.iast.enabled", "true") | ||
} | ||
|
||
void 'test json parsing (tainted)'() { | ||
given: | ||
final source = new SourceImpl(origin: SourceTypes.REQUEST_BODY, name: 'body', value: JSON_STRING) | ||
final module = Mock(PropagationModule) | ||
InstrumentationBridge.registerIastModule(module) | ||
and: | ||
final reader = new ObjectMapper().readerFor(Map) | ||
when: | ||
final taintedResult = reader.readValue(target) as Map | ||
then: | ||
JsonOutput.toJson(taintedResult) == JSON_STRING | ||
_ * module.taintObjectIfTainted(_, _) | ||
_ * module.findSource(_) >> source | ||
1 * module.taintString(_, 'root', source.origin, 'root', JSON_STRING) | ||
1 * module.taintString(_, 'nested', source.origin, 'nested', JSON_STRING) | ||
0 * _ | ||
where: | ||
target << [JSON_STRING] | ||
} | ||
void 'test json parsing (tainted but field names)'() { | ||
given: | ||
final source = new SourceImpl(origin: SourceTypes.REQUEST_BODY, name: 'body', value: JSON_STRING) | ||
final module = Mock(PropagationModule) | ||
InstrumentationBridge.registerIastModule(module) | ||
and: | ||
final reader = new ObjectMapper() | ||
when: | ||
final taintedResult = reader.readValue(target, Map) | ||
then: | ||
JsonOutput.toJson(taintedResult) == JSON_STRING | ||
_ * module.taintObjectIfTainted(_, _) | ||
_ * module.findSource(_) >> source | ||
0 * _ | ||
where: | ||
target << [new ByteArrayInputStream(JSON_STRING.getBytes(Charset.defaultCharset()))] | ||
} | ||
void 'test json parsing (not tainted)'() { | ||
given: | ||
final module = Mock(PropagationModule) | ||
InstrumentationBridge.registerIastModule(module) | ||
and: | ||
final reader = new ObjectMapper().readerFor(Map) | ||
when: | ||
final taintedResult = reader.readValue(target) as Map | ||
then: | ||
JsonOutput.toJson(taintedResult) == JSON_STRING | ||
_ * module.taintObjectIfTainted(_, _) | ||
_ * module.findSource(_) >> null | ||
0 * _ | ||
where: | ||
target << testSuite() | ||
} | ||
private static List<Object> testSuite() { | ||
return [JSON_STRING, new ByteArrayInputStream(JSON_STRING.getBytes(Charset.defaultCharset()))] | ||
} | ||
private static class SourceImpl implements Taintable.Source { | ||
byte origin | ||
String name | ||
String value | ||
} | ||
} |
23 changes: 23 additions & 0 deletions
23
dd-java-agent/instrumentation/jackson-core/jackson-core-2.16/build.gradle
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
muzzle { | ||
pass { | ||
group = 'com.fasterxml.jackson.core' | ||
module = 'jackson-core' | ||
versions = "[2.16.0,)" | ||
} | ||
} | ||
|
||
apply from: "$rootDir/gradle/java.gradle" | ||
|
||
addTestSuiteForDir('latestDepTest', 'test') | ||
|
||
final jacksonVersion = '2.16.0' | ||
dependencies { | ||
compileOnly(group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: jacksonVersion) | ||
compileOnly(group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: jacksonVersion) | ||
|
||
testImplementation(group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: jacksonVersion) | ||
testImplementation(group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: jacksonVersion) | ||
|
||
latestDepTestImplementation group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: '2.+' | ||
latestDepTestImplementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.+' | ||
} |
11 changes: 11 additions & 0 deletions
11
.../jackson-core-2.16/src/main/java/com/fasterxml/jackson/core/json/JsonParser216Helper.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package com.fasterxml.jackson.core.json; | ||
|
||
import com.fasterxml.jackson.core.sym.ByteQuadsCanonicalizer216Helper; | ||
|
||
public final class JsonParser216Helper { | ||
private JsonParser216Helper() {} | ||
|
||
public static boolean fetchInterner(UTF8StreamJsonParser jsonParser) { | ||
return ByteQuadsCanonicalizer216Helper.fetchInterner(jsonParser._symbols); | ||
} | ||
} |
9 changes: 9 additions & 0 deletions
9
...re-2.16/src/main/java/com/fasterxml/jackson/core/sym/ByteQuadsCanonicalizer216Helper.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package com.fasterxml.jackson.core.sym; | ||
|
||
public final class ByteQuadsCanonicalizer216Helper { | ||
private ByteQuadsCanonicalizer216Helper() {} | ||
|
||
public static boolean fetchInterner(ByteQuadsCanonicalizer symbols) { | ||
return symbols._interner != null; | ||
} | ||
} |
Oops, something went wrong.