Skip to content

Commit 71046f9

Browse files
committed
Upgrade libddwaf java to 14.0.0
1 parent 33fc3c9 commit 71046f9

20 files changed

+442
-401
lines changed

dd-java-agent/appsec/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ dependencies {
1515
implementation project(':internal-api')
1616
implementation project(':communication')
1717
implementation project(':telemetry')
18-
implementation group: 'io.sqreen', name: 'libsqreen', version: '13.0.1'
18+
implementation group: 'io.sqreen', name: 'libsqreen', version: '14.0.0-SNAPSHOT'
1919
implementation libs.moshi
2020

2121
testImplementation libs.bytebuddy

dd-java-agent/appsec/src/jmh/java/datadog/appsec/benchmark/WafBenchmark.java

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
import com.datadog.appsec.config.AppSecConfigDeserializer;
88
import com.datadog.appsec.event.data.KnownAddresses;
99
import com.datadog.ddwaf.Waf;
10+
import com.datadog.ddwaf.WafBuilder;
1011
import com.datadog.ddwaf.WafContext;
11-
import com.datadog.ddwaf.WafHandle;
1212
import com.datadog.ddwaf.WafMetrics;
1313
import com.datadog.ddwaf.exception.AbstractWafException;
1414
import java.io.IOException;
@@ -44,14 +44,14 @@ public class WafBenchmark {
4444
BenchmarkUtil.initializeWaf();
4545
}
4646

47-
WafHandle ctx;
47+
WafBuilder wafBuilder;
4848
Map<String, Object> wafData = new HashMap<>();
4949
Waf.Limits limits = new Waf.Limits(50, 500, 1000, 5000000, 5000000);
5050

5151
@Benchmark
5252
public void withMetrics() throws Exception {
53-
WafMetrics metricsCollector = ctx.createMetrics();
54-
WafContext add = ctx.openContext();
53+
WafMetrics metricsCollector = new WafMetrics();
54+
WafContext add = new WafContext(wafBuilder);
5555
try {
5656
add.run(wafData, limits, metricsCollector);
5757
} finally {
@@ -61,7 +61,7 @@ public void withMetrics() throws Exception {
6161

6262
@Benchmark
6363
public void withoutMetrics() throws Exception {
64-
WafContext add = ctx.openContext();
64+
WafContext add = new WafContext(wafBuilder);
6565
try {
6666
add.run(wafData, limits, null);
6767
} finally {
@@ -75,7 +75,8 @@ public void setUp() throws AbstractWafException, IOException {
7575
Map<String, AppSecConfig> cfg =
7676
Collections.singletonMap("waf", AppSecConfigDeserializer.INSTANCE.deserialize(stream));
7777
AppSecConfig waf = cfg.get("waf");
78-
ctx = Waf.createHandle("waf", waf.getRawConfig());
78+
wafBuilder = new WafBuilder();
79+
wafBuilder.addOrUpdateConfig("waf", waf.getRawConfig());
7980

8081
wafData.put(KnownAddresses.REQUEST_METHOD.getKey(), "POST");
8182
wafData.put(
@@ -112,6 +113,8 @@ public void setUp() throws AbstractWafException, IOException {
112113

113114
@TearDown(Level.Trial)
114115
public void teardown() {
115-
ctx.close();
116+
if (wafBuilder != null && !wafBuilder.isOnline()) {
117+
wafBuilder.destroy();
118+
}
116119
}
117120
}

dd-java-agent/appsec/src/main/java/com/datadog/appsec/AppSecModule.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33
import com.datadog.appsec.config.AppSecModuleConfigurer;
44
import com.datadog.appsec.event.DataListener;
55
import com.datadog.appsec.event.data.Address;
6+
import com.datadog.ddwaf.WafBuilder;
67
import java.util.Collection;
78

89
public interface AppSecModule {
9-
void config(AppSecModuleConfigurer appSecConfigService) throws AppSecModuleActivationException;
10+
void config(AppSecModuleConfigurer appSecConfigService, WafBuilder wafBuilder)
11+
throws AppSecModuleActivationException;
1012

1113
String getName();
1214

dd-java-agent/appsec/src/main/java/com/datadog/appsec/AppSecSystem.java

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,14 @@
77
import com.datadog.appsec.config.AppSecConfigService;
88
import com.datadog.appsec.config.AppSecConfigServiceImpl;
99
import com.datadog.appsec.ddwaf.WAFModule;
10+
import com.datadog.appsec.ddwaf.WafInitialization;
1011
import com.datadog.appsec.event.EventDispatcher;
1112
import com.datadog.appsec.event.ReplaceableEventProducerService;
1213
import com.datadog.appsec.gateway.GatewayBridge;
1314
import com.datadog.appsec.util.AbortStartupException;
1415
import com.datadog.appsec.util.StandardizedLogging;
16+
import com.datadog.ddwaf.WafBuilder;
17+
import com.datadog.ddwaf.WafConfig;
1518
import datadog.appsec.api.blocking.Blocking;
1619
import datadog.appsec.api.blocking.BlockingService;
1720
import datadog.communication.ddagent.SharedCommunicationObjects;
@@ -43,6 +46,7 @@ public class AppSecSystem {
4346
private static ReplaceableEventProducerService REPLACEABLE_EVENT_PRODUCER; // testing
4447
private static Runnable STOP_SUBSCRIPTION_SERVICE;
4548
private static Runnable RESET_SUBSCRIPTION_SERVICE;
49+
private static WafBuilder wafBuilder;
4650

4751
public static void start(SubscriptionService gw, SharedCommunicationObjects sco) {
4852
try {
@@ -64,7 +68,10 @@ private static void doStart(SubscriptionService gw, SharedCommunicationObjects s
6468
return;
6569
}
6670
log.debug("AppSec is starting ({})", appSecEnabledConfig);
67-
71+
if (!WafInitialization.ONLINE) {
72+
log.debug("In-app WAF initialization failed. See previous log entries");
73+
return;
74+
}
6875
REPLACEABLE_EVENT_PRODUCER = new ReplaceableEventProducerService();
6976
EventDispatcher eventDispatcher = new EventDispatcher();
7077
REPLACEABLE_EVENT_PRODUCER.replaceEventProducerService(eventDispatcher);
@@ -86,7 +93,8 @@ private static void doStart(SubscriptionService gw, SharedCommunicationObjects s
8693
APP_SEC_CONFIG_SERVICE =
8794
new AppSecConfigServiceImpl(
8895
config, configurationPoller, () -> reloadSubscriptions(REPLACEABLE_EVENT_PRODUCER));
89-
APP_SEC_CONFIG_SERVICE.init();
96+
wafBuilder = new WafBuilder(createWafConfig(config));
97+
APP_SEC_CONFIG_SERVICE.init(wafBuilder);
9098

9199
sco.createRemaining(config);
92100

@@ -105,7 +113,7 @@ private static void doStart(SubscriptionService gw, SharedCommunicationObjects s
105113

106114
setActive(appSecEnabledConfig == ProductActivation.FULLY_ENABLED);
107115

108-
APP_SEC_CONFIG_SERVICE.maybeSubscribeConfigPolling();
116+
APP_SEC_CONFIG_SERVICE.maybeSubscribeConfigPolling(wafBuilder);
109117

110118
Blocking.setBlockingService(new BlockingServiceImpl(REPLACEABLE_EVENT_PRODUCER));
111119

@@ -143,8 +151,8 @@ public static void stop() {
143151
RESET_SUBSCRIPTION_SERVICE = null;
144152
}
145153
Blocking.setBlockingService(BlockingService.NOOP);
146-
147154
APP_SEC_CONFIG_SERVICE.close();
155+
wafBuilder.destroy();
148156
}
149157

150158
private static void loadModules(EventDispatcher eventDispatcher, Monitoring monitoring) {
@@ -157,7 +165,7 @@ private static void loadModules(EventDispatcher eventDispatcher, Monitoring moni
157165
try {
158166
AppSecConfigService.TransactionalAppSecModuleConfigurer cfgObject;
159167
cfgObject = APP_SEC_CONFIG_SERVICE.createAppSecModuleConfigurer();
160-
module.config(cfgObject);
168+
module.config(cfgObject, wafBuilder);
161169
cfgObject.commit();
162170
} catch (RuntimeException | AppSecModule.AppSecModuleActivationException t) {
163171
log.error("Startup of appsec module {} failed", module.getName(), t);
@@ -209,4 +217,21 @@ public static Set<String> getStartedModulesInfo() {
209217
return Collections.emptySet();
210218
}
211219
}
220+
221+
private static WafConfig createWafConfig(Config config) {
222+
WafConfig wafConfig = new WafConfig();
223+
String keyRegexp = config.getAppSecObfuscationParameterKeyRegexp();
224+
if (keyRegexp != null) {
225+
wafConfig.obfuscatorKeyRegex = keyRegexp;
226+
} else { // reset
227+
wafConfig.obfuscatorKeyRegex = WafConfig.DEFAULT_KEY_REGEX;
228+
}
229+
String valueRegexp = config.getAppSecObfuscationParameterValueRegexp();
230+
if (valueRegexp != null) {
231+
wafConfig.obfuscatorValueRegex = valueRegexp;
232+
} else { // reset
233+
wafConfig.obfuscatorValueRegex = WafConfig.DEFAULT_VALUE_REGEX;
234+
}
235+
return wafConfig;
236+
}
212237
}

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
package com.datadog.appsec.config;
22

3+
import com.datadog.ddwaf.WafBuilder;
34
import java.io.Closeable;
45

56
public interface AppSecConfigService extends Closeable {
6-
void init();
7-
87
void close();
98

9+
void init(WafBuilder wafBuilder);
10+
1011
TransactionalAppSecModuleConfigurer createAppSecModuleConfigurer();
1112

1213
interface TransactionalAppSecModuleConfigurer extends AppSecModuleConfigurer {

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

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
import com.datadog.appsec.config.CurrentAppSecConfig.DirtyStatus;
2828
import com.datadog.appsec.util.AbortStartupException;
2929
import com.datadog.appsec.util.StandardizedLogging;
30+
import com.datadog.ddwaf.WafBuilder;
31+
import com.datadog.ddwaf.exception.InvalidRuleSetException;
3032
import datadog.remoteconfig.ConfigurationEndListener;
3133
import datadog.remoteconfig.ConfigurationPoller;
3234
import datadog.remoteconfig.Product;
@@ -75,6 +77,8 @@ public class AppSecConfigServiceImpl implements AppSecConfigService {
7577
this::applyRemoteConfigListener;
7678

7779
private boolean hasUserWafConfig;
80+
private boolean defaultConfigActivated;
81+
private final String DEFAULT_WAF_CONFIG_RULE = "DEFAULT_WAF_CONFIG";
7882

7983
public AppSecConfigServiceImpl(
8084
Config tracerConfig,
@@ -85,12 +89,12 @@ public AppSecConfigServiceImpl(
8589
this.reconfiguration = reconfig;
8690
}
8791

88-
private void subscribeConfigurationPoller() {
92+
private void subscribeConfigurationPoller(WafBuilder wafBuilder) {
8993
// see also close() method
9094
subscribeAsmFeatures();
9195

9296
if (!hasUserWafConfig) {
93-
subscribeRulesAndData();
97+
subscribeRulesAndData(wafBuilder);
9498
} else {
9599
log.debug("Will not subscribe to ASM, ASM_DD and ASM_DATA (AppSec custom rules in use)");
96100
}
@@ -125,7 +129,7 @@ private void subscribeConfigurationPoller() {
125129
this.configurationPoller.addCapabilities(capabilities);
126130
}
127131

128-
private void subscribeRulesAndData() {
132+
private void subscribeRulesAndData(WafBuilder wafBuilder) {
129133
this.configurationPoller.addListener(
130134
Product.ASM_DD,
131135
AppSecConfigDeserializer.INSTANCE,
@@ -134,13 +138,20 @@ private void subscribeRulesAndData() {
134138
if (!initialized) {
135139
throw new IllegalStateException();
136140
}
137-
if (newConfig == null) {
138-
if (DEFAULT_WAF_CONFIG == null) {
139-
throw new IllegalStateException("Expected default waf config to be available");
141+
if (newConfig == null || newConfig.getRawConfig() == null) {
142+
log.debug("AppSec config given by remote config was pulled. Removing WAF config");
143+
wafBuilder.removeConfig(configKey);
144+
} else {
145+
if (defaultConfigActivated) {
146+
log.debug("Removing default config");
147+
wafBuilder.removeConfig(DEFAULT_WAF_CONFIG_RULE);
148+
defaultConfigActivated = false;
149+
}
150+
try {
151+
wafBuilder.addOrUpdateConfig(configKey, newConfig.getRawConfig());
152+
} catch (InvalidRuleSetException e) {
153+
throw new RuntimeException(e);
140154
}
141-
log.debug(
142-
"AppSec config given by remote config was pulled. Restoring default WAF config");
143-
newConfig = DEFAULT_WAF_CONFIG;
144155
}
145156
this.currentAppSecConfig.setDdConfig(newConfig);
146157
// base rules can contain all rules/data/exclusions/etc
@@ -155,8 +166,14 @@ private void subscribeRulesAndData() {
155166
}
156167
if (newConfig == null) {
157168
currentAppSecConfig.mergedAsmData.removeConfig(configKey);
169+
wafBuilder.removeConfig(configKey);
158170
} else {
159171
currentAppSecConfig.mergedAsmData.addConfig(configKey, newConfig);
172+
try {
173+
wafBuilder.addOrUpdateConfig(configKey, newConfig.getRawConfig());
174+
} catch (InvalidRuleSetException e) {
175+
throw new RuntimeException(e);
176+
}
160177
}
161178
this.currentAppSecConfig.dirtyStatus.data = true;
162179
});
@@ -170,9 +187,15 @@ private void subscribeRulesAndData() {
170187
DirtyStatus dirtyStatus;
171188
if (newConfig == null) {
172189
dirtyStatus = currentAppSecConfig.userConfigs.removeConfig(configKey);
190+
wafBuilder.removeConfig(configKey);
173191
} else {
174192
AppSecUserConfig userCfg = newConfig.build(configKey);
175193
dirtyStatus = currentAppSecConfig.userConfigs.addConfig(userCfg);
194+
try {
195+
wafBuilder.addOrUpdateConfig(configKey, newConfig.getRawConfig());
196+
} catch (InvalidRuleSetException e) {
197+
throw new RuntimeException(e);
198+
}
176199
}
177200

178201
this.currentAppSecConfig.dirtyStatus.mergeFrom(dirtyStatus);
@@ -218,7 +241,7 @@ private void distributeSubConfigurations(
218241
}
219242

220243
@Override
221-
public void init() {
244+
public void init(WafBuilder wafBuilder) {
222245
AppSecConfig wafConfig;
223246
hasUserWafConfig = false;
224247
try {
@@ -242,17 +265,22 @@ public void init() {
242265
this.lastConfig.put("waf", this.currentAppSecConfig);
243266
this.mergedAsmFeatures = new MergedAsmFeatures();
244267
this.initialized = true;
268+
269+
if (DEFAULT_WAF_CONFIG == null) {
270+
throw new IllegalStateException("Expected default waf config to be available");
271+
}
272+
defaultConfigActivated = true;
245273
}
246274

247-
public void maybeSubscribeConfigPolling() {
275+
public void maybeSubscribeConfigPolling(WafBuilder wafBuilder) {
248276
if (this.configurationPoller != null) {
249277
if (hasUserWafConfig
250278
&& tracerConfig.getAppSecActivation() == ProductActivation.FULLY_ENABLED) {
251279
log.info(
252280
"AppSec will not use remote config because "
253281
+ "there is a custom user configuration and AppSec is explicitly enabled");
254282
} else {
255-
subscribeConfigurationPoller();
283+
subscribeConfigurationPoller(wafBuilder);
256284
}
257285
} else {
258286
log.info("Remote config is disabled; AppSec will not be able to use it");

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ public class AppSecData {
1212
@Json(name = "exclusion_data")
1313
private List<Map<String, Object>> exclusion;
1414

15+
private Map<String, Object> rawConfig;
16+
1517
public List<Map<String, Object>> getRules() {
1618
return rules;
1719
}
@@ -27,4 +29,12 @@ public List<Map<String, Object>> getExclusion() {
2729
public void setExclusion(List<Map<String, Object>> exclusion) {
2830
this.exclusion = exclusion;
2931
}
32+
33+
public Map<String, Object> getRawConfig() {
34+
return rawConfig;
35+
}
36+
37+
public void setRawConfig(Map<String, Object> rawConfig) {
38+
this.rawConfig = rawConfig;
39+
}
3040
}

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

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import java.io.ByteArrayInputStream;
88
import java.io.IOException;
99
import java.io.InputStream;
10+
import java.util.Map;
1011
import okio.Okio;
1112

1213
public class AppSecDataDeserializer implements ConfigurationDeserializer<AppSecData> {
@@ -18,10 +19,29 @@ private AppSecDataDeserializer() {}
1819

1920
@Override
2021
public AppSecData deserialize(byte[] content) throws IOException {
22+
if (content == null || content.length == 0) {
23+
return null;
24+
}
2125
return deserialize(new ByteArrayInputStream(content));
2226
}
2327

28+
@SuppressWarnings("unchecked")
2429
private AppSecData deserialize(InputStream is) throws IOException {
25-
return ADAPTER.fromJson(Okio.buffer(Okio.source(is)));
30+
AppSecData appSecData = ADAPTER.fromJson(Okio.buffer(Okio.source(is)));
31+
is.reset();
32+
if (appSecData != null && is.available() > 0) {
33+
appSecData.setRawConfig(MOSHI.adapter(Map.class).fromJson(Okio.buffer(Okio.source(is))));
34+
if (appSecData.getRawConfig().containsKey("rules_data")) {
35+
appSecData.getRawConfig().put("rules", appSecData.getRawConfig().get("rules_data"));
36+
appSecData.getRawConfig().remove("rules_data");
37+
}
38+
if (appSecData.getRawConfig().containsKey("exclusion_data")) {
39+
appSecData
40+
.getRawConfig()
41+
.put("exclusions", appSecData.getRawConfig().get("exclusion_data"));
42+
appSecData.getRawConfig().remove("exclusion_data");
43+
}
44+
}
45+
return appSecData;
2646
}
2747
}

0 commit comments

Comments
 (0)