Skip to content

Create span tag: _dd.appsec.rasp.timeout #8269

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jan 30, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,8 @@ public class AppSecRequestContext implements DataBundle, Closeable {
private volatile PowerwafMetrics raspMetrics;
private final AtomicInteger raspMetricsCounter = new AtomicInteger(0);
private volatile boolean blocked;
private volatile int timeouts;
private volatile int wafTimeouts;
private volatile int raspTimeouts;

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

private static final AtomicIntegerFieldUpdater<AppSecRequestContext> TIMEOUTS_UPDATER =
AtomicIntegerFieldUpdater.newUpdater(AppSecRequestContext.class, "timeouts");
private static final AtomicIntegerFieldUpdater<AppSecRequestContext> WAF_TIMEOUTS_UPDATER =
AtomicIntegerFieldUpdater.newUpdater(AppSecRequestContext.class, "wafTimeouts");
private static final AtomicIntegerFieldUpdater<AppSecRequestContext> RASP_TIMEOUTS_UPDATER =
AtomicIntegerFieldUpdater.newUpdater(AppSecRequestContext.class, "raspTimeouts");

// to be called by the Event Dispatcher
public void addAll(DataBundle newData) {
Expand Down Expand Up @@ -177,12 +180,20 @@ public boolean isBlocked() {
return blocked;
}

public void increaseTimeouts() {
TIMEOUTS_UPDATER.incrementAndGet(this);
public void increaseWafTimeouts() {
WAF_TIMEOUTS_UPDATER.incrementAndGet(this);
}

public int getTimeouts() {
return timeouts;
public void increaseRaspTimeouts() {
RASP_TIMEOUTS_UPDATER.incrementAndGet(this);
}

public int getWafTimeouts() {
return wafTimeouts;
}

public int getRaspTimeouts() {
return raspTimeouts;
}

public Additive getOrCreateAdditive(PowerwafContext ctx, boolean createMetrics, boolean isRasp) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -428,11 +428,13 @@ public void onDataAvailable(
try {
resultWithData = doRunPowerwaf(reqCtx, newData, ctxAndAddr, gwCtx);
} catch (TimeoutPowerwafException tpe) {
reqCtx.increaseTimeouts();
WafMetricCollector.get().wafRequestTimeout();
log.debug(LogCollector.EXCLUDE_TELEMETRY, "Timeout calling the WAF", tpe);
if (gwCtx.isRasp) {
reqCtx.increaseRaspTimeouts();
WafMetricCollector.get().raspTimeout(gwCtx.raspRuleType);
} else {
reqCtx.increaseWafTimeouts();
WafMetricCollector.get().wafRequestTimeout();
log.debug(LogCollector.EXCLUDE_TELEMETRY, "Timeout calling the WAF", tpe);
}
return;
} catch (AbstractPowerwafException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ public class PowerWAFStatsReporter implements TraceSegmentPostProcessor {
private static final String RASP_TOTAL_DDWAF_RUN_DURATION_US_TAG = "_dd.appsec.rasp.duration";
private static final String RASP_RULE_EVAL = "_dd.appsec.rasp.rule.eval";
private static final String RULE_FILE_VERSION = "_dd.appsec.event_rules.version";
public static final String TIMEOUTS_TAG = "_dd.appsec.waf.timeouts";
public static final String WAF_TIMEOUTS_TAG = "_dd.appsec.waf.timeouts";
public static final String RASP_TIMEOUT_TAG = "_dd.appsec.rasp.timeout";

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

if (ctx.getTimeouts() > 0) {
segment.setTagTop(TIMEOUTS_TAG, ctx.getTimeouts());
if (ctx.getWafTimeouts() > 0) {
segment.setTagTop(WAF_TIMEOUTS_TAG, ctx.getWafTimeouts());
}

if (ctx.getRaspTimeouts() > 0) {
segment.setTagTop(RASP_TIMEOUT_TAG, ctx.getRaspTimeouts());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -272,4 +272,22 @@ class AppSecRequestContextSpecification extends DDSpecification {
where:
postProcessing << [true, false]
}

def "test increase and get WafTimeouts"() {
when:
ctx.increaseWafTimeouts()
ctx.increaseWafTimeouts()

then:
ctx.getWafTimeouts() == 2
}

def "test increase and get RaspTimeouts"() {
when:
ctx.increaseRaspTimeouts()
ctx.increaseRaspTimeouts()

then:
ctx.getRaspTimeouts() == 2
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import com.datadog.appsec.event.data.MapDataBundle
import com.datadog.appsec.gateway.AppSecRequestContext
import com.datadog.appsec.gateway.GatewayContext
import com.datadog.appsec.report.AppSecEvent
import datadog.trace.api.telemetry.RuleType
import datadog.trace.util.stacktrace.StackTraceEvent
import com.datadog.appsec.test.StubAppSecConfigService
import datadog.communication.monitor.Monitoring
Expand Down Expand Up @@ -959,7 +960,7 @@ class PowerWAFModuleSpecification extends DDSpecification {
assert !flow.blocking
}

void 'timeout is honored'() {
void 'timeout is honored (waf)'() {
setup:
injectSysConfig('appsec.waf.timeout', '1')
PowerWAFModule.createLimitsObject()
Expand All @@ -981,8 +982,13 @@ class PowerWAFModuleSpecification extends DDSpecification {
ctx.getOrCreateAdditive(_, true) >> {
pwafAdditive = it[0].openAdditive() }
assert !flow.blocking
1 * ctx.increaseTimeouts()
1 * ctx.isAdditiveClosed()
1 * ctx.getOrCreateAdditive(_, true, false) >> {
pwafAdditive = it[0].openAdditive() }
1 * ctx.getWafMetrics()
1 * ctx.increaseWafTimeouts()
1 * mockWafMetricCollector.get().wafRequestTimeout()
0 * _

when:
pp.processTraceSegment(segment, ctx, [])
Expand All @@ -996,6 +1002,53 @@ class PowerWAFModuleSpecification extends DDSpecification {
PowerWAFModule.createLimitsObject()
}

void 'timeout is honored (rasp)'() {
setup:
injectSysConfig('appsec.waf.timeout', '1')
PowerWAFModule.createLimitsObject()
setupWithStubConfigService()
DataBundle db = MapDataBundle.of(KnownAddresses.HEADERS_NO_COOKIES,
new CaseInsensitiveMap<List<String>>(['user-agent': 'Arachni/v' + ('a' * 4000)]))
ChangeableFlow flow = new ChangeableFlow()

TraceSegment segment = Mock()
TraceSegmentPostProcessor pp = service.traceSegmentPostProcessors.last()

def mockWafMetricCollector = Mock(WafMetricCollector)
WafMetricCollector.INSTANCE = mockWafMetricCollector

gwCtx = new GatewayContext(false, RuleType.SQL_INJECTION)

when:
dataListener.onDataAvailable(flow, ctx, db, gwCtx)

then:
ctx.getOrCreateAdditive(_, true) >> {
pwafAdditive = it[0].openAdditive() }
assert !flow.blocking
1 * ctx.isAdditiveClosed()
1 * ctx.getOrCreateAdditive(_, true, true) >> {
pwafAdditive = it[0].openAdditive() }
1 * ctx.getRaspMetrics()
1 * ctx.getRaspMetricsCounter()
1 * ctx.increaseRaspTimeouts()
1 * mockWafMetricCollector.get().raspTimeout(gwCtx.raspRuleType)
1 * mockWafMetricCollector.raspRuleEval(RuleType.SQL_INJECTION)
0 * _

when:
pp.processTraceSegment(segment, ctx, [])

then:
1 * segment.setTagTop('_dd.appsec.rasp.timeout', 1L)
_ * segment.setTagTop(_, _)

cleanup:
injectSysConfig('appsec.waf.timeout', ConfigDefaults.DEFAULT_APPSEC_WAF_TIMEOUT as String)
PowerWAFModule.createLimitsObject()
gwCtx = new GatewayContext(false)
}

void 'configuration can be given later'() {
def cfgService = new StubAppSecConfigService([waf: null])
AppSecModuleConfigurer.Reconfiguration reconf = Mock()
Expand Down Expand Up @@ -1112,7 +1165,8 @@ class PowerWAFModuleSpecification extends DDSpecification {
1 * ctx.getWafMetrics()
1 * ctx.isAdditiveClosed() >> false
1 * ctx.closeAdditive() >> { pwafAdditive.close() }
_ * ctx.increaseTimeouts()
_ * ctx.increaseWafTimeouts()
_ * ctx.increaseRaspTimeouts()
0 * _

when: 'removing data and override config'
Expand All @@ -1136,7 +1190,8 @@ class PowerWAFModuleSpecification extends DDSpecification {
1 * ctx.isAdditiveClosed() >> false
1 * ctx.closeAdditive() >> {pwafAdditive.close()}
1 * reconf.reloadSubscriptions()
_ * ctx.increaseTimeouts()
_ * ctx.increaseWafTimeouts()
_ * ctx.increaseRaspTimeouts()
0 * _

when: 'data is readded'
Expand All @@ -1162,7 +1217,8 @@ class PowerWAFModuleSpecification extends DDSpecification {
1 * ctx.closeAdditive() >> {pwafAdditive.close()}
1 * flow.isBlocking()
1 * ctx.isThrottled(null)
_ * ctx.increaseTimeouts()
_ * ctx.increaseWafTimeouts()
_ * ctx.increaseRaspTimeouts()
0 * _

when: 'toggling the rule off'
Expand All @@ -1184,7 +1240,8 @@ class PowerWAFModuleSpecification extends DDSpecification {
1 * ctx.getWafMetrics()
1 * ctx.isAdditiveClosed() >> false
1 * ctx.closeAdditive()
_ * ctx.increaseTimeouts()
_ * ctx.increaseWafTimeouts()
_ * ctx.increaseRaspTimeouts()
0 * _
}

Expand Down Expand Up @@ -1214,7 +1271,8 @@ class PowerWAFModuleSpecification extends DDSpecification {
1 * ctx.getWafMetrics()
1 * ctx.isAdditiveClosed() >> false
1 * ctx.closeAdditive() >> {pwafAdditive.close()}
_ * ctx.increaseTimeouts()
_ * ctx.increaseWafTimeouts()
_ * ctx.increaseRaspTimeouts()
0 * _

when: 'rule enabled in config a has no effect'
Expand All @@ -1238,7 +1296,8 @@ class PowerWAFModuleSpecification extends DDSpecification {
1 * ctx.getWafMetrics()
1 * ctx.isAdditiveClosed() >> false
1 * ctx.closeAdditive() >> {pwafAdditive.close()}
_ * ctx.increaseTimeouts()
_ * ctx.increaseWafTimeouts()
_ * ctx.increaseRaspTimeouts()
0 * _

when: 'rule enabled in config c overrides b'
Expand Down Expand Up @@ -1266,7 +1325,8 @@ class PowerWAFModuleSpecification extends DDSpecification {
1 * ctx.reportEvents(_ as Collection<AppSecEvent>)
1 * ctx.isAdditiveClosed() >> false
1 * ctx.closeAdditive() >> {pwafAdditive.close()}
_ * ctx.increaseTimeouts()
_ * ctx.increaseWafTimeouts()
_ * ctx.increaseRaspTimeouts()
1 * ctx.isThrottled(null)
0 * _

Expand All @@ -1289,7 +1349,8 @@ class PowerWAFModuleSpecification extends DDSpecification {
1 * ctx.getWafMetrics()
1 * ctx.isAdditiveClosed() >> false
1 * ctx.closeAdditive()
_ * ctx.increaseTimeouts()
_ * ctx.increaseWafTimeouts()
_ * ctx.increaseRaspTimeouts()
0 * _
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ class PowerWAFStatsReporterSpecification extends DDSpecification {
metrics.totalDdwafRunTimeNs = 1_000
TraceSegment segment = Mock()
reporter.rulesVersion = '1.2.3'
def wafTimeouts = 1

and:
ctx.getWafTimeouts() >> wafTimeouts

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

void 'reporter reports rasp timings and version'() {
Expand All @@ -40,6 +45,10 @@ class PowerWAFStatsReporterSpecification extends DDSpecification {
raspMetrics.totalDdwafRunTimeNs = 3_000
TraceSegment segment = Mock()
reporter.rulesVersion = '1.2.3'
def raspTimeouts = 1

and:
ctx.getRaspTimeouts() >> raspTimeouts

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

void 'reports nothing if metrics are null'() {
Expand Down
Loading