Skip to content

Commit 46b5986

Browse files
authored
Increase IAST propagation to StringBuilder setLength (#8119)
1 parent 37acd7b commit 46b5986

File tree

8 files changed

+117
-2
lines changed

8 files changed

+117
-2
lines changed

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

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -831,6 +831,30 @@ public void onStringValueOf(Object param, @Nonnull String result) {
831831
}
832832
}
833833

834+
@Override
835+
public void onStringBuilderSetLength(@Nonnull CharSequence self, int length) {
836+
if (self.length() != length) {
837+
return;
838+
}
839+
final IastContext ctx = IastContext.Provider.get();
840+
if (ctx == null) {
841+
return;
842+
}
843+
final TaintedObjects taintedObjects = ctx.getTaintedObjects();
844+
final TaintedObject selfTainted = taintedObjects.get(self);
845+
if (selfTainted == null) {
846+
return;
847+
}
848+
final Range[] rangesSelf = selfTainted.getRanges();
849+
if (rangesSelf.length == 0) {
850+
return;
851+
}
852+
Range[] newRanges = Ranges.forSubstring(0, length, rangesSelf);
853+
if (newRanges != null && newRanges.length > 0) {
854+
selfTainted.setRanges(newRanges);
855+
}
856+
}
857+
834858
/**
835859
* Adds the tainted ranges belonging to the current parameter added via placeholder taking care of
836860
* an optional tainted placeholder.

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

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1436,6 +1436,48 @@ class StringModuleTest extends IastModuleImplTestBase {
14361436
taintFormat(result, taintedObject.getRanges()) == "==>my_input<=="
14371437
}
14381438
1439+
void 'onStringBuilderSetLength is empty or different lengths (#self, #length)'() {
1440+
given:
1441+
self?.setLength(self.length())
1442+
1443+
when:
1444+
module.onStringBuilderSetLength(self, length)
1445+
1446+
then:
1447+
mockCalls * tracer.activeSpan() >> null
1448+
0 * _
1449+
1450+
where:
1451+
self | length | mockCalls
1452+
sb("123") | 2 | 0
1453+
sb() | 0 | 1
1454+
}
1455+
1456+
void 'onStringBuilderSetLength (#input, #length)'() {
1457+
final taintedObjects = ctx.getTaintedObjects()
1458+
def self = addFromTaintFormat(taintedObjects, input)
1459+
if (self instanceof StringBuilder) {
1460+
((StringBuilder) self).setLength(length)
1461+
} else if (self instanceof StringBuffer) {
1462+
((StringBuffer) self).setLength(length)
1463+
}
1464+
final result = self.toString()
1465+
1466+
when:
1467+
module.onStringBuilderSetLength(self, length)
1468+
def taintedObject = taintedObjects.get(self)
1469+
1470+
then:
1471+
1 * tracer.activeSpan() >> span
1472+
taintFormat(result, taintedObject.getRanges()) == expected
1473+
1474+
where:
1475+
input | length | expected
1476+
sb("==>0123<==") | 3 | "==>012<=="
1477+
sb("0123==>456<==78") | 5 | "0123==>4<=="
1478+
sb("01==>234<==5==>678<==90") | 8 | "01==>234<==5==>67<=="
1479+
}
1480+
14391481
private static Date date(final String pattern, final String value) {
14401482
return new SimpleDateFormat(pattern).parse(value)
14411483
}

dd-java-agent/instrumentation/java-lang/src/main/java/datadog/trace/instrumentation/java/lang/StringBuilderCallSite.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,4 +181,17 @@ public static CharSequence afterSubSequence(
181181
}
182182
return result;
183183
}
184+
185+
@CallSite.After("void java.lang.StringBuilder.setLength(int)")
186+
public static void afterSetLength(
187+
@CallSite.This final CharSequence self, @CallSite.Argument final int length) {
188+
final StringModule module = InstrumentationBridge.STRING;
189+
if (module != null) {
190+
try {
191+
module.onStringBuilderSetLength(self, length);
192+
} catch (final Throwable e) {
193+
module.onUnexpectedException("afterSetLength threw", e);
194+
}
195+
}
196+
}
184197
}

dd-java-agent/instrumentation/java-lang/src/test/groovy/datadog/trace/instrumentation/java/lang/StringBuilderCallSiteTest.groovy

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,24 @@ class StringBuilderCallSiteTest extends AgentTestRunner {
250250
"buffer" | new TestStringBufferSuite() | sbf('012345') | 1 | 5 | '1234'
251251
}
252252
253+
def 'test string #type setLength with length: #length call site'() {
254+
setup:
255+
final iastModule = Mock(StringModule)
256+
InstrumentationBridge.registerIastModule(iastModule)
257+
258+
when:
259+
suite.setLength(param, length)
260+
261+
then:
262+
param.toString() == expected
263+
1 * iastModule.onStringBuilderSetLength(param, length)
264+
0 * _
265+
266+
where:
267+
type | suite | param | length | expected
268+
"builder" | new TestStringBuilderSuite() | sb('012345') | 5 | '01234'
269+
}
270+
253271
private static class BrokenToString {
254272
@Override
255273
String toString() {

dd-java-agent/instrumentation/java-lang/src/test/java/foo/bar/TestAbstractStringBuilderSuite.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,7 @@ public interface TestAbstractStringBuilderSuite<E> {
2020

2121
CharSequence subSequence(final E self, final int beginIndex, final int endIndex);
2222

23+
void setLength(final E self, final int length);
24+
2325
String toString(final E target);
2426
}

dd-java-agent/instrumentation/java-lang/src/test/java/foo/bar/TestStringBufferSuite.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,16 @@ public String substring(final StringBuffer self, final int beginIndex) {
7878
@Override
7979
public CharSequence subSequence(
8080
final StringBuffer self, final int beginIndex, final int endIndex) {
81-
LOGGER.debug("Before string builder subSequence {} from {} to {}", self, beginIndex, endIndex);
81+
LOGGER.debug("Before string buffer subSequence {} from {} to {}", self, beginIndex, endIndex);
8282
final CharSequence result = self.subSequence(beginIndex, endIndex);
83-
LOGGER.debug("After string builder subSequence {}", result);
83+
LOGGER.debug("After string buffer subSequence {}", result);
8484
return result;
8585
}
86+
87+
@Override
88+
public void setLength(final StringBuffer self, final int length) {
89+
LOGGER.debug("Before string buffer setLength {} with length {}", self, length);
90+
self.setLength(length);
91+
LOGGER.debug("After string buffer setLength {}", self);
92+
}
8693
}

dd-java-agent/instrumentation/java-lang/src/test/java/foo/bar/TestStringBuilderSuite.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,4 +108,11 @@ public CharSequence subSequence(
108108
LOGGER.debug("After string builder subSequence {}", result);
109109
return result;
110110
}
111+
112+
@Override
113+
public void setLength(final StringBuilder self, final int length) {
114+
LOGGER.debug("Before string builder setLength {} with length {}", self, length);
115+
self.setLength(length);
116+
LOGGER.debug("After string builder setLength {}", self);
117+
}
111118
}

internal-api/src/main/java/datadog/trace/api/iast/propagation/StringModule.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ void onStringBuilderAppend(
1818

1919
void onStringBuilderToString(@Nonnull CharSequence builder, @Nonnull String result);
2020

21+
void onStringBuilderSetLength(@Nonnull CharSequence self, int length);
22+
2123
void onStringConcatFactory(
2224
@Nullable String result,
2325
@Nullable String[] args,

0 commit comments

Comments
 (0)