Skip to content

Commit 2222bf1

Browse files
Attach values to sources coming from non char sequences
1 parent 1c33411 commit 2222bf1

11 files changed

Lines changed: 207 additions & 214 deletions

File tree

dd-java-agent/agent-iast/src/main/java/com/datadog/iast/model/Source.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ public final class Source implements Taintable.Source {
1616

1717
private static final Logger LOGGER = LoggerFactory.getLogger(Source.class);
1818

19+
/** Placeholder for non char sequence objects */
20+
public static final Object PROPAGATION_PLACEHOLDER = new Object();
21+
1922
// value to send in the rare case that the name/value have been garbage collected
2023
private static final String GARBAGE_COLLECTED_REF =
2124
"[unknown: original value was garbage collected]";
@@ -51,7 +54,9 @@ public String getValue() {
5154
@Nullable
5255
private String asString(@Nullable final Object target) {
5356
Object value = target;
54-
if (value instanceof Reference) {
57+
if (value == PROPAGATION_PLACEHOLDER) {
58+
value = null;
59+
} else if (value instanceof Reference) {
5560
value = ((Reference<?>) value).get();
5661
if (value == null) {
5762
value = GARBAGE_COLLECTED_REF;
@@ -90,4 +95,11 @@ public boolean equals(Object o) {
9095
public int hashCode() {
9196
return Objects.hash(origin, getName(), getValue());
9297
}
98+
99+
public Source attachValue(final CharSequence result) {
100+
if (value != PROPAGATION_PLACEHOLDER) {
101+
return this;
102+
}
103+
return new Source(origin, name, result);
104+
}
93105
}

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

Lines changed: 0 additions & 111 deletions
This file was deleted.
Lines changed: 15 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,36 @@
11
package com.datadog.iast.propagation;
22

3-
import static com.datadog.iast.taint.Ranges.highestPriorityRange;
4-
5-
import com.datadog.iast.model.Range;
6-
import com.datadog.iast.taint.Ranges;
3+
import datadog.trace.api.iast.propagation.CodecModule;
74
import javax.annotation.Nonnull;
85
import javax.annotation.Nullable;
96

10-
public class FastCodecModule extends BaseCodecModule {
7+
public class FastCodecModule extends PropagationModuleImpl implements CodecModule {
118

129
@Override
13-
protected Range[] urlDecodeRanges(
14-
@Nonnull final String value,
15-
@Nullable final String encoding,
16-
@Nonnull final String result,
17-
@Nonnull final Range[] ranges) {
18-
final Range range = highestPriorityRange(ranges);
19-
return new Range[] {Ranges.copyWithPosition(range, 0, result.length())};
10+
public void onUrlDecode(
11+
@Nonnull final String value, @Nullable final String encoding, @Nonnull final String result) {
12+
taintIfTainted(result, value);
2013
}
2114

2215
@Override
23-
protected Range[] fromBytesRanges(
24-
@Nonnull final byte[] value,
25-
@Nullable final String charset,
26-
@Nonnull final String result,
27-
@Nonnull final Range[] ranges) {
28-
final Range range = highestPriorityRange(ranges);
29-
return new Range[] {Ranges.copyWithPosition(range, 0, result.length())};
16+
public void onStringFromBytes(
17+
@Nonnull final byte[] value, @Nullable final String charset, @Nonnull final String result) {
18+
taintIfTainted(result, value);
3019
}
3120

3221
@Override
33-
protected Range[] getBytesRanges(
34-
@Nonnull final String value,
35-
@Nullable final String charset,
36-
@Nonnull final byte[] result,
37-
@Nonnull final Range[] ranges) {
38-
final Range range = highestPriorityRange(ranges);
39-
return new Range[] {Ranges.copyWithPosition(range, 0, result.length)};
22+
public void onStringGetBytes(
23+
@Nonnull final String value, @Nullable final String charset, @Nonnull final byte[] result) {
24+
taintIfTainted(result, value);
4025
}
4126

4227
@Override
43-
protected Range[] decodeBase64Ranges(
44-
@Nonnull final byte[] value, @Nonnull final byte[] result, @Nonnull final Range[] ranges) {
45-
final Range range = highestPriorityRange(ranges);
46-
return new Range[] {Ranges.copyWithPosition(range, 0, result.length)};
28+
public void onBase64Encode(@Nullable byte[] value, @Nullable byte[] result) {
29+
taintIfTainted(result, value);
4730
}
4831

4932
@Override
50-
protected Range[] encodeBase64Ranges(
51-
@Nonnull final byte[] value, @Nonnull final byte[] result, @Nonnull final Range[] ranges) {
52-
final Range range = highestPriorityRange(ranges);
53-
return new Range[] {Ranges.copyWithPosition(range, 0, result.length)};
33+
public void onBase64Decode(@Nullable byte[] value, @Nullable byte[] result) {
34+
taintIfTainted(result, value);
5435
}
5536
}

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

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.datadog.iast.propagation;
22

3+
import static com.datadog.iast.model.Source.PROPAGATION_PLACEHOLDER;
34
import static com.datadog.iast.taint.Ranges.highestPriorityRange;
45
import static com.datadog.iast.util.ObjectVisitor.State.CONTINUE;
56
import static datadog.trace.api.iast.VulnerabilityMarks.NOT_MARKED;
@@ -16,6 +17,7 @@
1617
import datadog.trace.api.iast.Taintable;
1718
import datadog.trace.api.iast.propagation.PropagationModule;
1819
import java.lang.ref.WeakReference;
20+
import java.lang.reflect.Array;
1921
import java.util.function.Predicate;
2022
import javax.annotation.Nonnull;
2123
import javax.annotation.Nullable;
@@ -313,7 +315,8 @@ private static Object sourceString(@Nullable final Object target, final boolean
313315
}
314316
return charSequence.toString();
315317
}
316-
return null; // ignore non char-sequence instances (e.g. byte buffers)
318+
// ignore non char-sequence instances (e.g. byte buffers)
319+
return value ? PROPAGATION_PLACEHOLDER : null;
317320
}
318321

319322
@Contract("null -> false")
@@ -324,6 +327,9 @@ private static boolean canBeTainted(@Nullable final Object target) {
324327
if (target instanceof CharSequence) {
325328
return Tainteds.canBeTainted((CharSequence) target);
326329
}
330+
if (target.getClass().isArray()) {
331+
return Array.getLength(target) > 0;
332+
}
327333
return true;
328334
}
329335

@@ -396,7 +402,7 @@ private static Source highestPrioritySource(
396402
private static void internalTaint(
397403
@Nullable final IastContext ctx,
398404
@Nonnull final Object value,
399-
@Nullable final Source source,
405+
@Nullable Source source,
400406
int mark) {
401407
if (source == null) {
402408
return;
@@ -409,6 +415,7 @@ private static void internalTaint(
409415
return;
410416
}
411417
if (value instanceof CharSequence) {
418+
source = source.attachValue((CharSequence) value);
412419
to.taint(value, Ranges.forCharSequence((CharSequence) value, source, mark));
413420
} else {
414421
to.taint(value, Ranges.forObject(source, mark));
@@ -419,7 +426,7 @@ private static void internalTaint(
419426
private static void internalTaint(
420427
@Nullable final IastContext ctx,
421428
@Nonnull final Object value,
422-
@Nullable final Range[] ranges,
429+
@Nullable Range[] ranges,
423430
final int mark) {
424431
if (ranges == null || ranges.length == 0) {
425432
return;
@@ -429,8 +436,11 @@ private static void internalTaint(
429436
} else {
430437
final TaintedObjects to = getTaintedObjects(ctx);
431438
if (to != null) {
432-
final Range[] markedRanges = markRanges(ranges, mark);
433-
to.taint(value, markedRanges);
439+
if (value instanceof CharSequence) {
440+
ranges = attachSourceValue(ranges, (CharSequence) value);
441+
}
442+
ranges = markRanges(ranges, mark);
443+
to.taint(value, ranges);
434444
}
435445
}
436446
}
@@ -449,6 +459,20 @@ private static Range[] markRanges(@Nonnull final Range[] ranges, final int mark)
449459
return result;
450460
}
451461

462+
public static Range[] attachSourceValue(
463+
@Nonnull final Range[] ranges, @Nonnull final CharSequence value) {
464+
// unbound sources can only occur when there's a single range in the array
465+
if (ranges.length != 1) {
466+
return ranges;
467+
}
468+
final Range range = ranges[0];
469+
final Source source = range.getSource();
470+
final Source newSource = range.getSource().attachValue(value);
471+
return newSource == source
472+
? ranges
473+
: Ranges.forCharSequence(value, newSource, range.getMarks());
474+
}
475+
452476
private static class LazyContext implements IastContext {
453477

454478
private boolean fetched;

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

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,7 @@ package com.datadog.iast.propagation
33
import com.datadog.iast.taint.Ranges
44
import com.datadog.iast.taint.TaintedObject
55
import datadog.trace.api.iast.propagation.CodecModule
6-
import groovy.transform.CompileDynamic
76

8-
9-
@CompileDynamic
107
class FastCodecModuleTest extends BaseCodecModuleTest {
118

129
@Override
@@ -40,37 +37,34 @@ class FastCodecModuleTest extends BaseCodecModuleTest {
4037

4138
@Override
4239
protected void assertOnStringGetBytes(final String value, final String charset, final TaintedObject source, final TaintedObject target) {
43-
final result = target.get() as byte[]
4440
assert target.ranges.size() == 1
4541

4642
final sourceRange = Ranges.highestPriorityRange(source.ranges)
4743
final range = target.ranges.first()
4844
assert range.start == 0
49-
assert range.length == result.length
45+
assert range.length == Integer.MAX_VALUE // unbound for non char sequences
5046
assert range.source == sourceRange.source
5147
}
5248

5349
@Override
5450
protected void assertBase64Decode(byte[] value, TaintedObject source, TaintedObject target) {
55-
final result = target.get() as byte[]
5651
assert target.ranges.size() == 1
5752

5853
final sourceRange = Ranges.highestPriorityRange(source.ranges)
5954
final range = target.ranges.first()
6055
assert range.start == 0
61-
assert range.length == result.length
56+
assert range.length == Integer.MAX_VALUE // unbound for non char sequences
6257
assert range.source == sourceRange.source
6358
}
6459

6560
@Override
6661
protected void assertBase64Encode(byte[] value, TaintedObject source, TaintedObject target) {
67-
final result = target.get() as byte[]
6862
assert target.ranges.size() == 1
6963

7064
final sourceRange = Ranges.highestPriorityRange(source.ranges)
7165
final range = target.ranges.first()
7266
assert range.start == 0
73-
assert range.length == result.length
67+
assert range.length == Integer.MAX_VALUE // unbound for non char sequences
7468
assert range.source == sourceRange.source
7569
}
7670
}

0 commit comments

Comments
 (0)