Skip to content

Commit 1759b2d

Browse files
authored
Create span tag: _dd.appsec.rasp.timeout (#8269)
1 parent 77fbf0a commit 1759b2d

File tree

6 files changed

+130
-23
lines changed

6 files changed

+130
-23
lines changed

dd-java-agent/appsec/src/main/java/com/datadog/appsec/gateway/AppSecRequestContext.java

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,8 @@ public class AppSecRequestContext implements DataBundle, Closeable {
122122
private volatile PowerwafMetrics raspMetrics;
123123
private final AtomicInteger raspMetricsCounter = new AtomicInteger(0);
124124
private volatile boolean blocked;
125-
private volatile int timeouts;
125+
private volatile int wafTimeouts;
126+
private volatile int raspTimeouts;
126127

127128
// keep a reference to the last published usr.id
128129
private volatile String userId;
@@ -133,8 +134,10 @@ public class AppSecRequestContext implements DataBundle, Closeable {
133134
// keep a reference to the last published usr.session_id
134135
private volatile String sessionId;
135136

136-
private static final AtomicIntegerFieldUpdater<AppSecRequestContext> TIMEOUTS_UPDATER =
137-
AtomicIntegerFieldUpdater.newUpdater(AppSecRequestContext.class, "timeouts");
137+
private static final AtomicIntegerFieldUpdater<AppSecRequestContext> WAF_TIMEOUTS_UPDATER =
138+
AtomicIntegerFieldUpdater.newUpdater(AppSecRequestContext.class, "wafTimeouts");
139+
private static final AtomicIntegerFieldUpdater<AppSecRequestContext> RASP_TIMEOUTS_UPDATER =
140+
AtomicIntegerFieldUpdater.newUpdater(AppSecRequestContext.class, "raspTimeouts");
138141

139142
// to be called by the Event Dispatcher
140143
public void addAll(DataBundle newData) {
@@ -177,12 +180,20 @@ public boolean isBlocked() {
177180
return blocked;
178181
}
179182

180-
public void increaseTimeouts() {
181-
TIMEOUTS_UPDATER.incrementAndGet(this);
183+
public void increaseWafTimeouts() {
184+
WAF_TIMEOUTS_UPDATER.incrementAndGet(this);
182185
}
183186

184-
public int getTimeouts() {
185-
return timeouts;
187+
public void increaseRaspTimeouts() {
188+
RASP_TIMEOUTS_UPDATER.incrementAndGet(this);
189+
}
190+
191+
public int getWafTimeouts() {
192+
return wafTimeouts;
193+
}
194+
195+
public int getRaspTimeouts() {
196+
return raspTimeouts;
186197
}
187198

188199
public Additive getOrCreateAdditive(PowerwafContext ctx, boolean createMetrics, boolean isRasp) {

dd-java-agent/appsec/src/main/java/com/datadog/appsec/powerwaf/PowerWAFModule.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -428,11 +428,13 @@ public void onDataAvailable(
428428
try {
429429
resultWithData = doRunPowerwaf(reqCtx, newData, ctxAndAddr, gwCtx);
430430
} catch (TimeoutPowerwafException tpe) {
431-
reqCtx.increaseTimeouts();
432-
WafMetricCollector.get().wafRequestTimeout();
433-
log.debug(LogCollector.EXCLUDE_TELEMETRY, "Timeout calling the WAF", tpe);
434431
if (gwCtx.isRasp) {
432+
reqCtx.increaseRaspTimeouts();
435433
WafMetricCollector.get().raspTimeout(gwCtx.raspRuleType);
434+
} else {
435+
reqCtx.increaseWafTimeouts();
436+
WafMetricCollector.get().wafRequestTimeout();
437+
log.debug(LogCollector.EXCLUDE_TELEMETRY, "Timeout calling the WAF", tpe);
436438
}
437439
return;
438440
} catch (AbstractPowerwafException e) {

dd-java-agent/appsec/src/main/java/com/datadog/appsec/powerwaf/PowerWAFStatsReporter.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ public class PowerWAFStatsReporter implements TraceSegmentPostProcessor {
1414
private static final String RASP_TOTAL_DDWAF_RUN_DURATION_US_TAG = "_dd.appsec.rasp.duration";
1515
private static final String RASP_RULE_EVAL = "_dd.appsec.rasp.rule.eval";
1616
private static final String RULE_FILE_VERSION = "_dd.appsec.event_rules.version";
17-
public static final String TIMEOUTS_TAG = "_dd.appsec.waf.timeouts";
17+
public static final String WAF_TIMEOUTS_TAG = "_dd.appsec.waf.timeouts";
18+
public static final String RASP_TIMEOUT_TAG = "_dd.appsec.rasp.timeout";
1819

1920
// XXX: if config is updated, this may not match the actual version run during this request
2021
// However, as of this point, we don't update rules at runtime.
@@ -46,8 +47,12 @@ public void processTraceSegment(
4647
segment.setTagTop(RULE_FILE_VERSION, rulesVersion);
4748
}
4849

49-
if (ctx.getTimeouts() > 0) {
50-
segment.setTagTop(TIMEOUTS_TAG, ctx.getTimeouts());
50+
if (ctx.getWafTimeouts() > 0) {
51+
segment.setTagTop(WAF_TIMEOUTS_TAG, ctx.getWafTimeouts());
52+
}
53+
54+
if (ctx.getRaspTimeouts() > 0) {
55+
segment.setTagTop(RASP_TIMEOUT_TAG, ctx.getRaspTimeouts());
5156
}
5257
}
5358
}

dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/gateway/AppSecRequestContextSpecification.groovy

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,4 +272,22 @@ class AppSecRequestContextSpecification extends DDSpecification {
272272
where:
273273
postProcessing << [true, false]
274274
}
275+
276+
def "test increase and get WafTimeouts"() {
277+
when:
278+
ctx.increaseWafTimeouts()
279+
ctx.increaseWafTimeouts()
280+
281+
then:
282+
ctx.getWafTimeouts() == 2
283+
}
284+
285+
def "test increase and get RaspTimeouts"() {
286+
when:
287+
ctx.increaseRaspTimeouts()
288+
ctx.increaseRaspTimeouts()
289+
290+
then:
291+
ctx.getRaspTimeouts() == 2
292+
}
275293
}

dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/powerwaf/PowerWAFModuleSpecification.groovy

Lines changed: 71 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import com.datadog.appsec.event.data.MapDataBundle
1717
import com.datadog.appsec.gateway.AppSecRequestContext
1818
import com.datadog.appsec.gateway.GatewayContext
1919
import com.datadog.appsec.report.AppSecEvent
20+
import datadog.trace.api.telemetry.RuleType
2021
import datadog.trace.util.stacktrace.StackTraceEvent
2122
import com.datadog.appsec.test.StubAppSecConfigService
2223
import datadog.communication.monitor.Monitoring
@@ -959,7 +960,7 @@ class PowerWAFModuleSpecification extends DDSpecification {
959960
assert !flow.blocking
960961
}
961962

962-
void 'timeout is honored'() {
963+
void 'timeout is honored (waf)'() {
963964
setup:
964965
injectSysConfig('appsec.waf.timeout', '1')
965966
PowerWAFModule.createLimitsObject()
@@ -981,8 +982,13 @@ class PowerWAFModuleSpecification extends DDSpecification {
981982
ctx.getOrCreateAdditive(_, true) >> {
982983
pwafAdditive = it[0].openAdditive() }
983984
assert !flow.blocking
984-
1 * ctx.increaseTimeouts()
985+
1 * ctx.isAdditiveClosed()
986+
1 * ctx.getOrCreateAdditive(_, true, false) >> {
987+
pwafAdditive = it[0].openAdditive() }
988+
1 * ctx.getWafMetrics()
989+
1 * ctx.increaseWafTimeouts()
985990
1 * mockWafMetricCollector.get().wafRequestTimeout()
991+
0 * _
986992
987993
when:
988994
pp.processTraceSegment(segment, ctx, [])
@@ -996,6 +1002,53 @@ class PowerWAFModuleSpecification extends DDSpecification {
9961002
PowerWAFModule.createLimitsObject()
9971003
}
9981004
1005+
void 'timeout is honored (rasp)'() {
1006+
setup:
1007+
injectSysConfig('appsec.waf.timeout', '1')
1008+
PowerWAFModule.createLimitsObject()
1009+
setupWithStubConfigService()
1010+
DataBundle db = MapDataBundle.of(KnownAddresses.HEADERS_NO_COOKIES,
1011+
new CaseInsensitiveMap<List<String>>(['user-agent': 'Arachni/v' + ('a' * 4000)]))
1012+
ChangeableFlow flow = new ChangeableFlow()
1013+
1014+
TraceSegment segment = Mock()
1015+
TraceSegmentPostProcessor pp = service.traceSegmentPostProcessors.last()
1016+
1017+
def mockWafMetricCollector = Mock(WafMetricCollector)
1018+
WafMetricCollector.INSTANCE = mockWafMetricCollector
1019+
1020+
gwCtx = new GatewayContext(false, RuleType.SQL_INJECTION)
1021+
1022+
when:
1023+
dataListener.onDataAvailable(flow, ctx, db, gwCtx)
1024+
1025+
then:
1026+
ctx.getOrCreateAdditive(_, true) >> {
1027+
pwafAdditive = it[0].openAdditive() }
1028+
assert !flow.blocking
1029+
1 * ctx.isAdditiveClosed()
1030+
1 * ctx.getOrCreateAdditive(_, true, true) >> {
1031+
pwafAdditive = it[0].openAdditive() }
1032+
1 * ctx.getRaspMetrics()
1033+
1 * ctx.getRaspMetricsCounter()
1034+
1 * ctx.increaseRaspTimeouts()
1035+
1 * mockWafMetricCollector.get().raspTimeout(gwCtx.raspRuleType)
1036+
1 * mockWafMetricCollector.raspRuleEval(RuleType.SQL_INJECTION)
1037+
0 * _
1038+
1039+
when:
1040+
pp.processTraceSegment(segment, ctx, [])
1041+
1042+
then:
1043+
1 * segment.setTagTop('_dd.appsec.rasp.timeout', 1L)
1044+
_ * segment.setTagTop(_, _)
1045+
1046+
cleanup:
1047+
injectSysConfig('appsec.waf.timeout', ConfigDefaults.DEFAULT_APPSEC_WAF_TIMEOUT as String)
1048+
PowerWAFModule.createLimitsObject()
1049+
gwCtx = new GatewayContext(false)
1050+
}
1051+
9991052
void 'configuration can be given later'() {
10001053
def cfgService = new StubAppSecConfigService([waf: null])
10011054
AppSecModuleConfigurer.Reconfiguration reconf = Mock()
@@ -1112,7 +1165,8 @@ class PowerWAFModuleSpecification extends DDSpecification {
11121165
1 * ctx.getWafMetrics()
11131166
1 * ctx.isAdditiveClosed() >> false
11141167
1 * ctx.closeAdditive() >> { pwafAdditive.close() }
1115-
_ * ctx.increaseTimeouts()
1168+
_ * ctx.increaseWafTimeouts()
1169+
_ * ctx.increaseRaspTimeouts()
11161170
0 * _
11171171
11181172
when: 'removing data and override config'
@@ -1136,7 +1190,8 @@ class PowerWAFModuleSpecification extends DDSpecification {
11361190
1 * ctx.isAdditiveClosed() >> false
11371191
1 * ctx.closeAdditive() >> {pwafAdditive.close()}
11381192
1 * reconf.reloadSubscriptions()
1139-
_ * ctx.increaseTimeouts()
1193+
_ * ctx.increaseWafTimeouts()
1194+
_ * ctx.increaseRaspTimeouts()
11401195
0 * _
11411196
11421197
when: 'data is readded'
@@ -1162,7 +1217,8 @@ class PowerWAFModuleSpecification extends DDSpecification {
11621217
1 * ctx.closeAdditive() >> {pwafAdditive.close()}
11631218
1 * flow.isBlocking()
11641219
1 * ctx.isThrottled(null)
1165-
_ * ctx.increaseTimeouts()
1220+
_ * ctx.increaseWafTimeouts()
1221+
_ * ctx.increaseRaspTimeouts()
11661222
0 * _
11671223
11681224
when: 'toggling the rule off'
@@ -1184,7 +1240,8 @@ class PowerWAFModuleSpecification extends DDSpecification {
11841240
1 * ctx.getWafMetrics()
11851241
1 * ctx.isAdditiveClosed() >> false
11861242
1 * ctx.closeAdditive()
1187-
_ * ctx.increaseTimeouts()
1243+
_ * ctx.increaseWafTimeouts()
1244+
_ * ctx.increaseRaspTimeouts()
11881245
0 * _
11891246
}
11901247
@@ -1214,7 +1271,8 @@ class PowerWAFModuleSpecification extends DDSpecification {
12141271
1 * ctx.getWafMetrics()
12151272
1 * ctx.isAdditiveClosed() >> false
12161273
1 * ctx.closeAdditive() >> {pwafAdditive.close()}
1217-
_ * ctx.increaseTimeouts()
1274+
_ * ctx.increaseWafTimeouts()
1275+
_ * ctx.increaseRaspTimeouts()
12181276
0 * _
12191277
12201278
when: 'rule enabled in config a has no effect'
@@ -1238,7 +1296,8 @@ class PowerWAFModuleSpecification extends DDSpecification {
12381296
1 * ctx.getWafMetrics()
12391297
1 * ctx.isAdditiveClosed() >> false
12401298
1 * ctx.closeAdditive() >> {pwafAdditive.close()}
1241-
_ * ctx.increaseTimeouts()
1299+
_ * ctx.increaseWafTimeouts()
1300+
_ * ctx.increaseRaspTimeouts()
12421301
0 * _
12431302
12441303
when: 'rule enabled in config c overrides b'
@@ -1266,7 +1325,8 @@ class PowerWAFModuleSpecification extends DDSpecification {
12661325
1 * ctx.reportEvents(_ as Collection<AppSecEvent>)
12671326
1 * ctx.isAdditiveClosed() >> false
12681327
1 * ctx.closeAdditive() >> {pwafAdditive.close()}
1269-
_ * ctx.increaseTimeouts()
1328+
_ * ctx.increaseWafTimeouts()
1329+
_ * ctx.increaseRaspTimeouts()
12701330
1 * ctx.isThrottled(null)
12711331
0 * _
12721332
@@ -1289,7 +1349,8 @@ class PowerWAFModuleSpecification extends DDSpecification {
12891349
1 * ctx.getWafMetrics()
12901350
1 * ctx.isAdditiveClosed() >> false
12911351
1 * ctx.closeAdditive()
1292-
_ * ctx.increaseTimeouts()
1352+
_ * ctx.increaseWafTimeouts()
1353+
_ * ctx.increaseRaspTimeouts()
12931354
0 * _
12941355
}
12951356

dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/powerwaf/PowerWAFStatsReporterSpecification.groovy

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ class PowerWAFStatsReporterSpecification extends DDSpecification {
1818
metrics.totalDdwafRunTimeNs = 1_000
1919
TraceSegment segment = Mock()
2020
reporter.rulesVersion = '1.2.3'
21+
def wafTimeouts = 1
22+
23+
and:
24+
ctx.getWafTimeouts() >> wafTimeouts
2125

2226
when:
2327
reporter.processTraceSegment(segment, ctx, [])
@@ -27,6 +31,7 @@ class PowerWAFStatsReporterSpecification extends DDSpecification {
2731
1 * segment.setTagTop('_dd.appsec.waf.duration', 1)
2832
1 * segment.setTagTop('_dd.appsec.waf.duration_ext', 2)
2933
1 * segment.setTagTop('_dd.appsec.event_rules.version', '1.2.3')
34+
1 * segment.setTagTop('_dd.appsec.waf.timeouts', wafTimeouts)
3035
}
3136

3237
void 'reporter reports rasp timings and version'() {
@@ -40,6 +45,10 @@ class PowerWAFStatsReporterSpecification extends DDSpecification {
4045
raspMetrics.totalDdwafRunTimeNs = 3_000
4146
TraceSegment segment = Mock()
4247
reporter.rulesVersion = '1.2.3'
48+
def raspTimeouts = 1
49+
50+
and:
51+
ctx.getRaspTimeouts() >> raspTimeouts
4352

4453
when:
4554
reporter.processTraceSegment(segment, ctx, [])
@@ -52,6 +61,7 @@ class PowerWAFStatsReporterSpecification extends DDSpecification {
5261
1 * segment.setTagTop('_dd.appsec.rasp.duration_ext', 4)
5362
1 * segment.setTagTop('_dd.appsec.rasp.rule.eval', 5)
5463
1 * segment.setTagTop('_dd.appsec.event_rules.version', '1.2.3')
64+
1 * segment.setTagTop('_dd.appsec.rasp.timeout', raspTimeouts)
5565
}
5666

5767
void 'reports nothing if metrics are null'() {

0 commit comments

Comments
 (0)