Skip to content

Commit fbe2772

Browse files
authored
Merge branch 'master' into dougqh/crash-tracking-in-smoke-tests
2 parents 43e4f33 + cd1b746 commit fbe2772

File tree

65 files changed

+1315
-407
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+1315
-407
lines changed

.circleci/config.continue.yml.j2

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ instrumentation_modules: &instrumentation_modules "dd-java-agent/instrumentation
3636
debugger_modules: &debugger_modules "dd-java-agent/agent-debugger|dd-java-agent/agent-bootstrap|dd-java-agent/agent-builder|internal-api|communication|dd-trace-core"
3737
profiling_modules: &profiling_modules "dd-java-agent/agent-profiling"
3838

39-
default_system_tests_commit: &default_system_tests_commit 53d9b2c43876a39e5c0426f4df4dd5fd79d062e8
39+
default_system_tests_commit: &default_system_tests_commit 67fe30ac7504997685859d31feae1782f3527f39
4040

4141
parameters:
4242
nightly:

.github/workflows/check-pull-requests.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ jobs:
2727
const ignoreReleaseNotes = labels.filter(label => label == 'tag: no release notes').length > 0
2828
const hasTypeLabel = labels.filter(label => label.startsWith('type:')).length > 0
2929
const hasComponentLabel = labels.filter(label => label.startsWith('comp:')).length > 0
30-
const hasInstrumentationLabel = labels.filter(label => label.startsWith('instr:')).length > 0
30+
const hasInstrumentationLabel = labels.filter(label => label.startsWith('inst:')).length > 0
3131
const labelsCheckFailed = !ignoreReleaseNotes && (!hasTypeLabel || (!hasComponentLabel && !hasInstrumentationLabel));
3232
if (labelsCheckFailed) {
3333
core.setFailed('Please add at least one type, and one component or instrumentation label to the pull request.')
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"pull_request": {
3+
"number": 7884,
4+
"draft": false,
5+
"labels": [
6+
{
7+
"name": "inst: java"
8+
},
9+
{
10+
"name": "type: bug"
11+
}
12+
],
13+
"title": "Adding some new features"
14+
}
15+
}

.github/workflows/tests/check-pull-requests/test-pull-request.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#!/bin/bash
22
source "$(dirname "$0")/../env.sh"
33
testworkflow pull_request && \
4+
testworkflow pull_request instrumentation && \
45
testworkflow pull_request draft && \
56
testworkflow pull_request no-release-notes && \
67
! testworkflow pull_request missing-label && \

dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/instrumentation/decorator/HttpClientDecorator.java

Lines changed: 65 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,24 @@
11
package datadog.trace.bootstrap.instrumentation.decorator;
22

33
import static datadog.trace.api.cache.RadixTreeCache.UNSET_STATUS;
4+
import static datadog.trace.api.gateway.Events.EVENTS;
45
import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.traceConfig;
56
import static datadog.trace.bootstrap.instrumentation.decorator.http.HttpResourceDecorator.HTTP_RESOURCE_DECORATOR;
67

8+
import datadog.appsec.api.blocking.BlockingException;
79
import datadog.trace.api.Config;
810
import datadog.trace.api.DDTags;
911
import datadog.trace.api.InstrumenterConfig;
1012
import datadog.trace.api.ProductActivation;
13+
import datadog.trace.api.gateway.BlockResponseFunction;
14+
import datadog.trace.api.gateway.Flow;
15+
import datadog.trace.api.gateway.RequestContext;
16+
import datadog.trace.api.gateway.RequestContextSlot;
1117
import datadog.trace.api.iast.InstrumentationBridge;
1218
import datadog.trace.api.iast.sink.SsrfModule;
1319
import datadog.trace.api.naming.SpanNaming;
1420
import datadog.trace.bootstrap.instrumentation.api.AgentSpan;
21+
import datadog.trace.bootstrap.instrumentation.api.AgentTracer;
1522
import datadog.trace.bootstrap.instrumentation.api.InternalSpanTypes;
1623
import datadog.trace.bootstrap.instrumentation.api.Tags;
1724
import datadog.trace.bootstrap.instrumentation.api.URIUtils;
@@ -21,6 +28,7 @@
2128
import java.util.BitSet;
2229
import java.util.LinkedHashMap;
2330
import java.util.Map;
31+
import java.util.function.BiFunction;
2432
import org.slf4j.Logger;
2533
import org.slf4j.LoggerFactory;
2634

@@ -42,6 +50,8 @@ public abstract class HttpClientDecorator<REQUEST, RESPONSE> extends UriBasedCli
4250

4351
private static final boolean CLIENT_TAG_HEADERS = Config.get().isHttpClientTagHeaders();
4452

53+
private static final boolean APPSEC_RASP_ENABLED = Config.get().isAppSecRaspEnabled();
54+
4555
protected abstract String method(REQUEST request);
4656

4757
protected abstract URI url(REQUEST request) throws URISyntaxException;
@@ -68,9 +78,20 @@ protected boolean shouldSetResourceName() {
6878

6979
public AgentSpan onRequest(final AgentSpan span, final REQUEST request) {
7080
if (request != null) {
81+
7182
String method = method(request);
7283
span.setTag(Tags.HTTP_METHOD, method);
7384

85+
if (CLIENT_TAG_HEADERS) {
86+
for (Map.Entry<String, String> headerTag :
87+
traceConfig(span).getRequestHeaderTags().entrySet()) {
88+
String headerValue = getRequestHeader(request, headerTag.getKey());
89+
if (null != headerValue) {
90+
span.setTag(headerTag.getValue(), headerValue);
91+
}
92+
}
93+
}
94+
7495
// Copy of HttpServerDecorator url handling
7596
try {
7697
final URI url = url(request);
@@ -86,24 +107,15 @@ public AgentSpan onRequest(final AgentSpan span, final REQUEST request) {
86107
if (shouldSetResourceName()) {
87108
HTTP_RESOURCE_DECORATOR.withClientPath(span, method, url.getPath());
88109
}
110+
// SSRF exploit prevention check
111+
onNetworkConnection(url.toString());
89112
} else if (shouldSetResourceName()) {
90113
span.setResourceName(DEFAULT_RESOURCE_NAME);
91114
}
92115
} catch (final Exception e) {
93116
log.debug("Error tagging url", e);
94117
}
95-
96118
ssrfIastCheck(request);
97-
98-
if (CLIENT_TAG_HEADERS) {
99-
for (Map.Entry<String, String> headerTag :
100-
traceConfig(span).getRequestHeaderTags().entrySet()) {
101-
String headerValue = getRequestHeader(request, headerTag.getKey());
102-
if (null != headerValue) {
103-
span.setTag(headerTag.getValue(), headerValue);
104-
}
105-
}
106-
}
107119
}
108120
return span;
109121
}
@@ -175,6 +187,48 @@ public long getResponseContentLength(final RESPONSE response) {
175187
return 0;
176188
}
177189

190+
private void onNetworkConnection(final String networkConnection) {
191+
if (!APPSEC_RASP_ENABLED) {
192+
return;
193+
}
194+
if (networkConnection == null) {
195+
return;
196+
}
197+
final BiFunction<RequestContext, String, Flow<Void>> networkConnectionCallback =
198+
AgentTracer.get()
199+
.getCallbackProvider(RequestContextSlot.APPSEC)
200+
.getCallback(EVENTS.networkConnection());
201+
202+
if (networkConnectionCallback == null) {
203+
return;
204+
}
205+
206+
final AgentSpan span = AgentTracer.get().activeSpan();
207+
if (span == null) {
208+
return;
209+
}
210+
211+
final RequestContext ctx = span.getRequestContext();
212+
if (ctx == null) {
213+
return;
214+
}
215+
216+
Flow<Void> flow = networkConnectionCallback.apply(ctx, networkConnection);
217+
Flow.Action action = flow.getAction();
218+
if (action instanceof Flow.Action.RequestBlockingAction) {
219+
BlockResponseFunction brf = ctx.getBlockResponseFunction();
220+
if (brf != null) {
221+
Flow.Action.RequestBlockingAction rba = (Flow.Action.RequestBlockingAction) action;
222+
brf.tryCommitBlockingResponse(
223+
ctx.getTraceSegment(),
224+
rba.getStatusCode(),
225+
rba.getBlockingContentType(),
226+
rba.getExtraHeaders());
227+
}
228+
throw new BlockingException("Blocked request (for SSRF attempt)");
229+
}
230+
}
231+
178232
/* This method must be overriden after making the proper propagations to the client before **/
179233
protected Object sourceUrl(REQUEST request) {
180234
return null;

dd-java-agent/agent-bootstrap/src/test/groovy/datadog/trace/bootstrap/instrumentation/decorator/HttpClientDecoratorTest.groovy

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
package datadog.trace.bootstrap.instrumentation.decorator
22

33
import datadog.trace.api.DDTags
4+
import datadog.trace.api.config.AppSecConfig
5+
import datadog.trace.api.gateway.CallbackProvider
6+
import static datadog.trace.api.gateway.Events.EVENTS
7+
import datadog.trace.api.gateway.RequestContext
8+
import datadog.trace.api.gateway.RequestContextSlot
9+
import datadog.trace.api.internal.TraceSegment
410
import datadog.trace.api.iast.InstrumentationBridge
511
import datadog.trace.api.iast.sink.SsrfModule
612
import datadog.trace.bootstrap.instrumentation.api.AgentSpan
@@ -12,11 +18,39 @@ import spock.lang.Shared
1218
import static datadog.trace.api.config.TraceInstrumentationConfig.HTTP_CLIENT_HOST_SPLIT_BY_DOMAIN
1319
import static datadog.trace.api.config.TraceInstrumentationConfig.HTTP_CLIENT_TAG_QUERY_STRING
1420

21+
import java.util.function.BiFunction
22+
1523
class HttpClientDecoratorTest extends ClientDecoratorTest {
1624

1725
@Shared
1826
def testUrl = new URI("http://myhost:123/somepath")
1927

28+
@Shared
29+
protected static final ORIGINAL_TRACER = AgentTracer.get()
30+
31+
protected traceSegment
32+
protected reqCtx
33+
protected span2
34+
protected tracer
35+
36+
void setup() {
37+
traceSegment = Stub(TraceSegment)
38+
reqCtx = Stub(RequestContext) {
39+
getTraceSegment() >> traceSegment
40+
}
41+
span2 = Stub(AgentSpan) {
42+
getRequestContext() >> reqCtx
43+
}
44+
tracer = Stub(AgentTracer.TracerAPI) {
45+
activeSpan() >> span2
46+
}
47+
AgentTracer.forceRegister(tracer)
48+
}
49+
50+
void cleanup() {
51+
AgentTracer.forceRegister(ORIGINAL_TRACER)
52+
}
53+
2054
def span = Mock(AgentSpan)
2155

2256
def "test onRequest"() {
@@ -199,6 +233,26 @@ class HttpClientDecoratorTest extends ClientDecoratorTest {
199233
'false' | [method: "test-method", url: testUrl, path: '/somepath']
200234
}
201235

236+
void "test SSRF Exploit prevention onResponse"(){
237+
setup:
238+
injectSysConfig(AppSecConfig.APPSEC_ENABLED, 'true')
239+
injectSysConfig(AppSecConfig.APPSEC_RASP_ENABLED, 'true')
240+
241+
final callbackProvider = Mock(CallbackProvider)
242+
final listener = Mock(BiFunction)
243+
tracer.getCallbackProvider(RequestContextSlot.APPSEC) >> callbackProvider
244+
245+
final decorator = newDecorator()
246+
final req = [method: "GET", url: new URI("http://localhost:1234/somepath")]
247+
248+
when:
249+
decorator.onRequest(span2, req)
250+
251+
then:
252+
1 * callbackProvider.getCallback(EVENTS.networkConnection()) >> listener
253+
1 * listener.apply(reqCtx, _ as String)
254+
}
255+
202256
@Override
203257
def newDecorator(String serviceName = "test-service") {
204258
return new HttpClientDecorator<Map, Map>() {

dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/git/tree/GitClient.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -484,7 +484,7 @@ public Path createPackFiles(List<String> objectHashes)
484484
return executeCommand(
485485
Command.PACK_OBJECTS,
486486
() -> {
487-
byte[] input = Strings.join("\n", objectHashes).getBytes(Charset.defaultCharset());
487+
byte[] input = String.join("\n", objectHashes).getBytes(Charset.defaultCharset());
488488

489489
Path tempDirectory = createTempDirectory();
490490
String basename = Strings.random(8);

dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/utils/ShellCommandExecutor.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import datadog.trace.context.TraceScope;
66
import datadog.trace.util.AgentThreadFactory;
77
import datadog.trace.util.AgentThreadFactory.AgentThread;
8-
import datadog.trace.util.Strings;
98
import java.io.ByteArrayInputStream;
109
import java.io.ByteArrayOutputStream;
1110
import java.io.File;
@@ -124,7 +123,7 @@ private <T> T executeCommand(
124123
throw new ShellCommandFailedException(
125124
exitValue,
126125
"Command '"
127-
+ Strings.join(" ", command)
126+
+ String.join(" ", command)
128127
+ "' failed with exit code "
129128
+ exitValue
130129
+ ": "
@@ -147,7 +146,7 @@ private <T> T executeCommand(
147146
terminate(p);
148147
throw new TimeoutException(
149148
"Timeout while waiting for '"
150-
+ Strings.join(" ", command)
149+
+ String.join(" ", command)
151150
+ "'; "
152151
+ IOUtils.readFully(errorStreamConsumer.read(), Charset.defaultCharset()));
153152
}

dd-java-agent/agent-iast/src/main/java/com/datadog/iast/propagation/StringModuleImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ public void onStringConcatFactory(
185185
@Override
186186
@SuppressFBWarnings("ES_COMPARING_PARAMETER_STRING_WITH_EQ")
187187
public void onStringSubSequence(
188-
@Nonnull String self, int beginIndex, int endIndex, @Nullable CharSequence result) {
188+
@Nonnull CharSequence self, int beginIndex, int endIndex, @Nullable CharSequence result) {
189189
if (self == result || !canBeTainted(result)) {
190190
return;
191191
}

dd-java-agent/agent-iast/src/test/groovy/com/datadog/iast/propagation/StringModuleTest.groovy

Lines changed: 36 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -481,37 +481,42 @@ class StringModuleTest extends IastModuleImplTestBase {
481481
}
482482
483483
where:
484-
self | beginIndex | endIndex | expected
485-
"==>0123<==" | 0 | 4 | "==>0123<=="
486-
"0123==>456<==78" | 0 | 5 | "0123==>4<=="
487-
"01==>234<==5==>678<==90" | 0 | 8 | "01==>234<==5==>67<=="
488-
"==>0123<==" | 0 | 3 | "==>012<=="
489-
"==>0123<==" | 1 | 4 | "==>123<=="
490-
"==>0123<==" | 1 | 3 | "==>12<=="
491-
"0123==>456<==78" | 1 | 8 | "123==>456<==7"
492-
"0123==>456<==78" | 0 | 4 | "0123"
493-
"0123==>456<==78" | 7 | 9 | "78"
494-
"0123==>456<==78" | 1 | 5 | "123==>4<=="
495-
"0123==>456<==78" | 1 | 6 | "123==>45<=="
496-
"0123==>456<==78" | 4 | 7 | "==>456<=="
497-
"0123==>456<==78" | 6 | 8 | "==>6<==7"
498-
"0123==>456<==78" | 5 | 8 | "==>56<==7"
499-
"0123==>456<==78" | 4 | 6 | "==>45<=="
500-
"01==>234<==5==>678<==90" | 1 | 10 | "1==>234<==5==>678<==9"
501-
"01==>234<==5==>678<==90" | 1 | 2 | "1"
502-
"01==>234<==5==>678<==90" | 5 | 6 | "5"
503-
"01==>234<==5==>678<==90" | 9 | 10 | "9"
504-
"01==>234<==5==>678<==90" | 1 | 4 | "1==>23<=="
505-
"01==>234<==5==>678<==90" | 2 | 4 | "==>23<=="
506-
"01==>234<==5==>678<==90" | 2 | 5 | "==>234<=="
507-
"01==>234<==5==>678<==90" | 1 | 8 | "1==>234<==5==>67<=="
508-
"01==>234<==5==>678<==90" | 2 | 8 | "==>234<==5==>67<=="
509-
"01==>234<==5==>678<==90" | 2 | 9 | "==>234<==5==>678<=="
510-
"01==>234<==5==>678<==90" | 5 | 8 | "5==>67<=="
511-
"01==>234<==5==>678<==90" | 6 | 8 | "==>67<=="
512-
"01==>234<==5==>678<==90" | 6 | 9 | "==>678<=="
513-
"01==>234<==5==>678<==90" | 4 | 9 | "==>4<==5==>678<=="
514-
"01==>234<==5==>678<==90" | 4 | 8 | "==>4<==5==>67<=="
484+
self | beginIndex | endIndex | expected
485+
"==>0123<==" | 0 | 4 | "==>0123<=="
486+
"0123==>456<==78" | 0 | 5 | "0123==>4<=="
487+
"01==>234<==5==>678<==90" | 0 | 8 | "01==>234<==5==>67<=="
488+
"==>0123<==" | 0 | 3 | "==>012<=="
489+
"==>0123<==" | 1 | 4 | "==>123<=="
490+
"==>0123<==" | 1 | 3 | "==>12<=="
491+
"0123==>456<==78" | 1 | 8 | "123==>456<==7"
492+
"0123==>456<==78" | 0 | 4 | "0123"
493+
"0123==>456<==78" | 7 | 9 | "78"
494+
"0123==>456<==78" | 1 | 5 | "123==>4<=="
495+
"0123==>456<==78" | 1 | 6 | "123==>45<=="
496+
"0123==>456<==78" | 4 | 7 | "==>456<=="
497+
"0123==>456<==78" | 6 | 8 | "==>6<==7"
498+
"0123==>456<==78" | 5 | 8 | "==>56<==7"
499+
"0123==>456<==78" | 4 | 6 | "==>45<=="
500+
"01==>234<==5==>678<==90" | 1 | 10 | "1==>234<==5==>678<==9"
501+
"01==>234<==5==>678<==90" | 1 | 2 | "1"
502+
"01==>234<==5==>678<==90" | 5 | 6 | "5"
503+
"01==>234<==5==>678<==90" | 9 | 10 | "9"
504+
"01==>234<==5==>678<==90" | 1 | 4 | "1==>23<=="
505+
"01==>234<==5==>678<==90" | 2 | 4 | "==>23<=="
506+
"01==>234<==5==>678<==90" | 2 | 5 | "==>234<=="
507+
"01==>234<==5==>678<==90" | 1 | 8 | "1==>234<==5==>67<=="
508+
"01==>234<==5==>678<==90" | 2 | 8 | "==>234<==5==>67<=="
509+
"01==>234<==5==>678<==90" | 2 | 9 | "==>234<==5==>678<=="
510+
"01==>234<==5==>678<==90" | 5 | 8 | "5==>67<=="
511+
"01==>234<==5==>678<==90" | 6 | 8 | "==>67<=="
512+
"01==>234<==5==>678<==90" | 6 | 9 | "==>678<=="
513+
"01==>234<==5==>678<==90" | 4 | 9 | "==>4<==5==>678<=="
514+
"01==>234<==5==>678<==90" | 4 | 8 | "==>4<==5==>67<=="
515+
sb("==>0123<==") | 0 | 4 | "==>0123<=="
516+
sb("0123==>456<==78") | 0 | 5 | "0123==>4<=="
517+
sb("01==>234<==5==>678<==90") | 0 | 8 | "01==>234<==5==>67<=="
518+
sb("0123==>456<==78") | 4 | 6 | "==>45<=="
519+
sb("01==>234<==5==>678<==90") | 4 | 8 | "==>4<==5==>67<=="
515520
}
516521
517522
void 'onStringJoin without null delimiter or elements (#delimiter, #elements)'() {

0 commit comments

Comments
 (0)