Skip to content

Commit 1a8a272

Browse files
Merge branch 'master' into alexeyk/debug-ci-timeout
2 parents 12703ea + 3a35f77 commit 1a8a272

File tree

22 files changed

+294
-243
lines changed

22 files changed

+294
-243
lines changed

build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ plugins {
1212
id("io.github.gradle-nexus.publish-plugin") version "2.0.0"
1313

1414
id("com.gradleup.shadow") version "8.3.6" apply false
15-
id("me.champeau.jmh") version "0.7.0" apply false
15+
id("me.champeau.jmh") version "0.7.3" apply false
1616
id("org.gradle.playframework") version "0.13" apply false
1717
id("info.solidsoft.pitest") version "1.9.11" apply false
1818
}

dd-java-agent/agent-bootstrap/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ idea {
6363
}
6464

6565
jmh {
66-
jmhVersion = '1.32'
66+
jmhVersion = libs.versions.jmh.get()
6767
duplicateClassesStrategy = DuplicatesStrategy.EXCLUDE
6868
}
6969

dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/sink/DebuggerSink.java

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ public class DebuggerSink {
2323
private static final long LOW_RATE_INITIAL_FLUSH_INTERVAL = 1000;
2424
static final long LOW_RATE_STEP_SIZE = 200;
2525
private static final String PREFIX = "debugger.sink.";
26+
private static final String DROPPED_REQ_METRIC = PREFIX + "dropped.requests";
27+
private static final String UPLOAD_REMAINING_CAP_METRIC =
28+
PREFIX + "upload.queue.remaining.capacity";
29+
private static final String CURRENT_FLUSH_INTERVAL_METRIC = PREFIX + "current.flush.interval";
30+
private static final String SKIP_METRIC = PREFIX + "skip";
2631

2732
private final ProbeStatusSink probeStatusSink;
2833
private final SnapshotSink snapshotSink;
@@ -109,7 +114,7 @@ public SymbolSink getSymbolSink() {
109114
public void addSnapshot(Snapshot snapshot) {
110115
boolean added = snapshotSink.addLowRate(snapshot);
111116
if (!added) {
112-
debuggerMetrics.count(PREFIX + "dropped.requests", 1);
117+
debuggerMetrics.count(DROPPED_REQ_METRIC, 1);
113118
} else {
114119
probeStatusSink.addEmitting(snapshot.getProbe().getProbeId());
115120
}
@@ -120,7 +125,7 @@ public void addHighRateSnapshot(Snapshot snapshot) {
120125
if (!added) {
121126
long dropped = highRateDropped.incrementAndGet();
122127
if (dropped % 100 == 0) {
123-
debuggerMetrics.count(PREFIX + "dropped.requests", 100);
128+
debuggerMetrics.count(DROPPED_REQ_METRIC, 100);
124129
}
125130
} else {
126131
probeStatusSink.addEmitting(snapshot.getProbe().getProbeId());
@@ -151,9 +156,8 @@ void lowRateFlush(DebuggerSink ignored) {
151156
}
152157

153158
private void reconsiderLowRateFlushInterval(DebuggerSink debuggerSink) {
154-
debuggerMetrics.histogram(
155-
PREFIX + "upload.queue.remaining.capacity", snapshotSink.remainingCapacity());
156-
debuggerMetrics.histogram(PREFIX + "current.flush.interval", currentLowRateFlushInterval);
159+
debuggerMetrics.histogram(UPLOAD_REMAINING_CAP_METRIC, snapshotSink.remainingCapacity());
160+
debuggerMetrics.histogram(CURRENT_FLUSH_INTERVAL_METRIC, currentLowRateFlushInterval);
157161
doReconsiderLowRateFlushInterval();
158162
}
159163

@@ -225,7 +229,7 @@ private void reportError(ProbeId probeId, DiagnosticMessage msg) {
225229

226230
/** Notifies the snapshot was skipped for one of the SkipCause reason */
227231
public void skipSnapshot(String probeId, SkipCause cause) {
228-
debuggerMetrics.incrementCounter(PREFIX + "skip", cause.tag(), "probe_id:" + probeId);
232+
debuggerMetrics.incrementCounter(SKIP_METRIC, cause.tag(), "probe_id:" + probeId);
229233
}
230234

231235
long getCurrentLowRateFlushInterval() {

dd-java-agent/agent-iast/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ spotless {
112112
}
113113

114114
jmh {
115-
jmhVersion = '1.28'
115+
jmhVersion = libs.versions.jmh.get()
116116
duplicateClassesStrategy = DuplicatesStrategy.EXCLUDE
117117
}
118118

dd-java-agent/agent-tooling/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ dependencies {
6363
}
6464

6565
jmh {
66-
jmhVersion = '1.32'
66+
jmhVersion = libs.versions.jmh.get()
6767
includeTests = true
6868
}
6969
compileJmhJava.dependsOn compileTestJava

dd-java-agent/appsec/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ processResources {
5151
}
5252

5353
jmh {
54-
jmhVersion = '1.32'
54+
jmhVersion = libs.versions.jmh.get()
5555
duplicateClassesStrategy = DuplicatesStrategy.EXCLUDE
5656
jvmArgs = ['-Ddd.appsec.enabled=true -Xms64m -Xmx64m']
5757
failOnError = false

dd-java-agent/appsec/src/main/java/com/datadog/appsec/config/AppSecConfigServiceImpl.java

Lines changed: 74 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,11 @@
6060
import java.util.ArrayList;
6161
import java.util.Collections;
6262
import java.util.HashMap;
63-
import java.util.HashSet;
6463
import java.util.List;
6564
import java.util.Map;
6665
import java.util.Set;
6766
import java.util.concurrent.ConcurrentHashMap;
67+
import java.util.concurrent.atomic.AtomicBoolean;
6868
import okio.Okio;
6969
import org.slf4j.Logger;
7070
import org.slf4j.LoggerFactory;
@@ -99,7 +99,11 @@ public class AppSecConfigServiceImpl implements AppSecConfigService {
9999

100100
private boolean hasUserWafConfig;
101101
private boolean defaultConfigActivated;
102-
private final Set<String> usedDDWafConfigKeys = new HashSet<>();
102+
private final AtomicBoolean subscribedToRulesAndData = new AtomicBoolean();
103+
private final Set<String> usedDDWafConfigKeys =
104+
Collections.newSetFromMap(new ConcurrentHashMap<>());
105+
private final Set<String> ignoredConfigKeys =
106+
Collections.newSetFromMap(new ConcurrentHashMap<>());
103107
private final String DEFAULT_WAF_CONFIG_RULE = "DEFAULT_WAF_CONFIG";
104108
private String currentRuleVersion;
105109
private List<AppSecModule> modulesToUpdateVersionIn;
@@ -122,13 +126,15 @@ private void subscribeConfigurationPoller() {
122126
subscribeAsmFeatures();
123127

124128
if (!hasUserWafConfig) {
125-
subscribeRulesAndData();
129+
updateRulesAndDataSubscription();
126130
} else {
127131
log.debug("Will not subscribe to ASM, ASM_DD and ASM_DATA (AppSec custom rules in use)");
128132
}
129133

130134
this.configurationPoller.addConfigurationEndListener(applyRemoteConfigListener);
135+
}
131136

137+
private long getRulesAndDataCapabilities() {
132138
long capabilities =
133139
CAPABILITY_ASM_DD_RULES
134140
| CAPABILITY_ASM_IP_BLOCKING
@@ -154,13 +160,36 @@ private void subscribeConfigurationPoller() {
154160
capabilities |= CAPABILITY_ASM_RASP_LFI;
155161
}
156162
}
157-
this.configurationPoller.addCapabilities(capabilities);
163+
return capabilities;
164+
}
165+
166+
private void updateRulesAndDataSubscription() {
167+
if (hasUserWafConfig) {
168+
return; // do nothing if the customer has custom rules
169+
}
170+
if (AppSecSystem.isActive()) {
171+
subscribeRulesAndData();
172+
} else {
173+
unsubscribeRulesAndData();
174+
}
158175
}
159176

160177
private void subscribeRulesAndData() {
161-
this.configurationPoller.addListener(Product.ASM_DD, new AppSecConfigChangesDDListener());
162-
this.configurationPoller.addListener(Product.ASM_DATA, new AppSecConfigChangesListener());
163-
this.configurationPoller.addListener(Product.ASM, new AppSecConfigChangesListener());
178+
if (subscribedToRulesAndData.compareAndSet(false, true)) {
179+
this.configurationPoller.addListener(Product.ASM_DD, new AppSecConfigChangesDDListener());
180+
this.configurationPoller.addListener(Product.ASM_DATA, new AppSecConfigChangesListener());
181+
this.configurationPoller.addListener(Product.ASM, new AppSecConfigChangesListener());
182+
this.configurationPoller.addCapabilities(getRulesAndDataCapabilities());
183+
}
184+
}
185+
186+
private void unsubscribeRulesAndData() {
187+
if (subscribedToRulesAndData.compareAndSet(true, false)) {
188+
this.configurationPoller.removeListeners(Product.ASM_DD);
189+
this.configurationPoller.removeListeners(Product.ASM_DATA);
190+
this.configurationPoller.removeListeners(Product.ASM);
191+
this.configurationPoller.removeCapabilities(getRulesAndDataCapabilities());
192+
}
164193
}
165194

166195
public void modulesToUpdateVersionIn(List<AppSecModule> modules) {
@@ -175,19 +204,21 @@ private class AppSecConfigChangesListener implements ProductListener {
175204
@Override
176205
public void accept(ConfigKey configKey, byte[] content, PollingRateHinter pollingRateHinter)
177206
throws IOException {
178-
maybeInitializeDefaultConfig();
179-
180207
if (content == null) {
181-
try {
182-
wafBuilder.removeConfig(configKey.toString());
183-
} catch (UnclassifiedWafException e) {
184-
throw new RuntimeException(e);
185-
}
208+
remove(configKey, pollingRateHinter);
209+
return;
210+
}
211+
final String key = configKey.toString();
212+
Map<String, Object> contentMap =
213+
ADAPTER.fromJson(Okio.buffer(Okio.source(new ByteArrayInputStream(content))));
214+
if (contentMap == null || contentMap.isEmpty()) {
215+
ignoredConfigKeys.add(key);
186216
} else {
187-
Map<String, Object> contentMap =
188-
ADAPTER.fromJson(Okio.buffer(Okio.source(new ByteArrayInputStream(content))));
217+
ignoredConfigKeys.remove(key);
189218
try {
190-
handleWafUpdateResultReport(configKey.toString(), contentMap);
219+
beforeApply(key, contentMap);
220+
maybeInitializeDefaultConfig();
221+
handleWafUpdateResultReport(key, contentMap);
191222
} catch (AppSecModule.AppSecModuleActivationException e) {
192223
throw new RuntimeException(e);
193224
}
@@ -197,19 +228,32 @@ public void accept(ConfigKey configKey, byte[] content, PollingRateHinter pollin
197228
@Override
198229
public void remove(ConfigKey configKey, PollingRateHinter pollingRateHinter)
199230
throws IOException {
200-
accept(configKey, null, pollingRateHinter);
231+
final String key = configKey.toString();
232+
if (ignoredConfigKeys.remove(key)) {
233+
return;
234+
}
235+
try {
236+
maybeInitializeDefaultConfig();
237+
wafBuilder.removeConfig(key);
238+
afterRemove(key);
239+
} catch (UnclassifiedWafException e) {
240+
throw new RuntimeException(e);
241+
}
201242
}
202243

203244
@Override
204245
public void commit(PollingRateHinter pollingRateHinter) {
205246
// no action needed
206247
}
248+
249+
protected void beforeApply(final String key, final Map<String, Object> contentMap) {}
250+
251+
protected void afterRemove(final String key) {}
207252
}
208253

209254
private class AppSecConfigChangesDDListener extends AppSecConfigChangesListener {
210255
@Override
211-
public void accept(ConfigKey configKey, byte[] content, PollingRateHinter pollingRateHinter)
212-
throws IOException {
256+
protected void beforeApply(final String key, final Map<String, Object> config) {
213257
if (defaultConfigActivated) { // if we get any config, remove the default one
214258
log.debug("Removing default config");
215259
try {
@@ -219,15 +263,12 @@ public void accept(ConfigKey configKey, byte[] content, PollingRateHinter pollin
219263
}
220264
defaultConfigActivated = false;
221265
}
222-
usedDDWafConfigKeys.add(configKey.toString());
223-
super.accept(configKey, content, pollingRateHinter);
266+
usedDDWafConfigKeys.add(key);
224267
}
225268

226269
@Override
227-
public void remove(ConfigKey configKey, PollingRateHinter pollingRateHinter)
228-
throws IOException {
229-
super.remove(configKey, pollingRateHinter);
230-
usedDDWafConfigKeys.remove(configKey.toString());
270+
protected void afterRemove(final String key) {
271+
usedDDWafConfigKeys.remove(key);
231272
}
232273
}
233274

@@ -282,7 +323,6 @@ private void subscribeAsmFeatures() {
282323
Product.ASM_FEATURES,
283324
AppSecFeaturesDeserializer.INSTANCE,
284325
(configKey, newConfig, hinter) -> {
285-
maybeInitializeDefaultConfig();
286326
if (newConfig == null) {
287327
mergedAsmFeatures.removeConfig(configKey);
288328
} else {
@@ -339,8 +379,6 @@ public void init() {
339379
} else {
340380
hasUserWafConfig = true;
341381
}
342-
this.mergedAsmFeatures.clear();
343-
this.usedDDWafConfigKeys.clear();
344382

345383
if (wafConfig.isEmpty()) {
346384
throw new IllegalStateException("Expected default waf config to be available");
@@ -353,9 +391,12 @@ public void init() {
353391
}
354392

355393
public void maybeSubscribeConfigPolling() {
394+
final ProductActivation appSecActivation = tracerConfig.getAppSecActivation();
395+
if (appSecActivation == ProductActivation.FULLY_DISABLED) {
396+
return; // shouldn't happen but just in case.
397+
}
356398
if (this.configurationPoller != null) {
357-
if (hasUserWafConfig
358-
&& tracerConfig.getAppSecActivation() == ProductActivation.FULLY_ENABLED) {
399+
if (hasUserWafConfig && appSecActivation == ProductActivation.FULLY_ENABLED) {
359400
log.info(
360401
"AppSec will not use remote config because "
361402
+ "there is a custom user configuration and AppSec is explicitly enabled");
@@ -494,6 +535,7 @@ public void close() {
494535
this.configurationPoller.removeListeners(Product.ASM);
495536
this.configurationPoller.removeListeners(Product.ASM_FEATURES);
496537
this.configurationPoller.removeConfigurationEndListener(applyRemoteConfigListener);
538+
this.subscribedToRulesAndData.set(false);
497539
this.configurationPoller.stop();
498540
if (this.wafBuilder != null) {
499541
this.wafBuilder.close();
@@ -526,6 +568,7 @@ private void setAppSecActivation(final AppSecFeatures.Asm asm) {
526568
if (AppSecSystem.isActive() != newState) {
527569
log.info("AppSec {} (runtime)", newState ? "enabled" : "disabled");
528570
AppSecSystem.setActive(newState);
571+
updateRulesAndDataSubscription();
529572
}
530573
}
531574

dd-java-agent/appsec/src/main/java/com/datadog/appsec/ddwaf/WafInitialization.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ private static boolean initWAF() {
1515
try {
1616
boolean simpleLoad = System.getProperty("POWERWAF_SIMPLE_LOAD") != null;
1717
Waf.initialize(simpleLoad);
18-
} catch (Exception e) {
18+
} catch (Throwable e) {
1919
Logger logger = LoggerFactory.getLogger(WafInitialization.class);
2020
logger.warn("Error initializing WAF library", e);
2121
StandardizedLogging.libddwafCannotBeLoaded(logger, getLibc());

0 commit comments

Comments
 (0)