Skip to content

Commit f1447fe

Browse files
authored
[Entitlements] Instrument write access to System properties (#120357)
Instrument write access to System properties by means of the `WriteSystemPropertiesEntitlement`. `System.setProperties(Properties)` is always denied. Part of #ES-10359
1 parent 04b5b7a commit f1447fe

File tree

21 files changed

+334
-2
lines changed

21 files changed

+334
-2
lines changed

libs/entitlement/bridge/src/main/java/org/elasticsearch/entitlement/bridge/EntitlementChecker.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
import java.nio.channels.SocketChannel;
4343
import java.security.cert.CertStoreParameters;
4444
import java.util.List;
45+
import java.util.Properties;
4546

4647
import javax.net.ssl.HostnameVerifier;
4748
import javax.net.ssl.HttpsURLConnection;
@@ -121,6 +122,15 @@ public interface EntitlementChecker {
121122

122123
void check$java_lang_ProcessBuilder$$startPipeline(Class<?> callerClass, List<ProcessBuilder> builders);
123124

125+
////////////////////
126+
//
127+
// System Properties and similar
128+
//
129+
130+
void check$java_lang_System$$setProperty(Class<?> callerClass, String key, String value);
131+
132+
void check$java_lang_System$$clearProperty(Class<?> callerClass, String key);
133+
124134
////////////////////
125135
//
126136
// JVM-wide state changes
@@ -132,6 +142,8 @@ public interface EntitlementChecker {
132142

133143
void check$java_lang_System$$setErr(Class<?> callerClass, PrintStream err);
134144

145+
void check$java_lang_System$$setProperties(Class<?> callerClass, Properties props);
146+
135147
void check$java_lang_Runtime$addShutdownHook(Class<?> callerClass, Runtime runtime, Thread hook);
136148

137149
void check$java_lang_Runtime$removeShutdownHook(Class<?> callerClass, Runtime runtime, Thread hook);

libs/entitlement/qa/common/src/main/java/org/elasticsearch/entitlement/qa/common/RestEntitlementsCheckAction.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,10 @@ static CheckAction alwaysDenied(CheckedRunnable<Exception> action) {
124124
entry("timeZoneNameProvider", alwaysDenied(RestEntitlementsCheckAction::timeZoneNameProvider$)),
125125
entry("logManager", alwaysDenied(RestEntitlementsCheckAction::logManager$)),
126126

127+
entry("system_setProperty", forPlugins(WritePropertiesCheckActions::setSystemProperty)),
128+
entry("system_clearProperty", forPlugins(WritePropertiesCheckActions::clearSystemProperty)),
129+
entry("system_setSystemProperties", alwaysDenied(WritePropertiesCheckActions::setSystemProperties)),
130+
127131
// This group is a bit nasty: if entitlements don't prevent these, then networking is
128132
// irreparably borked for the remainder of the test run.
129133
entry(
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the "Elastic License
4+
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
5+
* Public License v 1"; you may not use this file except in compliance with, at
6+
* your election, the "Elastic License 2.0", the "GNU Affero General Public
7+
* License v3.0 only", or the "Server Side Public License, v 1".
8+
*/
9+
10+
package org.elasticsearch.entitlement.qa.common;
11+
12+
import org.elasticsearch.core.SuppressForbidden;
13+
14+
@SuppressForbidden(reason = "testing entitlements")
15+
class WritePropertiesCheckActions {
16+
private WritePropertiesCheckActions() {}
17+
18+
static void setSystemProperty() {
19+
System.setProperty("es.entitlements.checkSetSystemProperty", "true");
20+
try {
21+
System.clearProperty("es.entitlements.checkSetSystemProperty");
22+
} catch (RuntimeException e) {
23+
// ignore for this test case
24+
}
25+
26+
}
27+
28+
static void clearSystemProperty() {
29+
System.clearProperty("es.entitlements.checkClearSystemProperty");
30+
}
31+
32+
static void setSystemProperties() {
33+
System.setProperties(System.getProperties()); // no side effect in case if allowed (but shouldn't)
34+
}
35+
}

libs/entitlement/qa/entitlement-allowed-nonmodular/src/main/plugin-metadata/entitlement-policy.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,7 @@ ALL-UNNAMED:
33
- set_https_connection_properties
44
- inbound_network
55
- outbound_network
6+
- write_system_properties:
7+
properties:
8+
- es.entitlements.checkSetSystemProperty
9+
- es.entitlements.checkClearSystemProperty

libs/entitlement/qa/entitlement-allowed/src/main/plugin-metadata/entitlement-policy.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,7 @@ org.elasticsearch.entitlement.qa.common:
33
- set_https_connection_properties
44
- inbound_network
55
- outbound_network
6+
- write_system_properties:
7+
properties:
8+
- es.entitlements.checkSetSystemProperty
9+
- es.entitlements.checkClearSystemProperty
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
ALL-UNNAMED:
2+
- write_system_properties:
3+
properties:
4+
# entitlement itself not sufficient, also no wildcard support
5+
- "*"
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
org.elasticsearch.entitlement.qa.common:
2+
- write_system_properties:
3+
properties:
4+
# entitlement itself not sufficient, also no wildcard support
5+
- "*"

libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/api/ElasticsearchEntitlementChecker.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
import java.nio.channels.SocketChannel;
4747
import java.security.cert.CertStoreParameters;
4848
import java.util.List;
49+
import java.util.Properties;
4950

5051
import javax.net.ssl.HostnameVerifier;
5152
import javax.net.ssl.HttpsURLConnection;
@@ -211,6 +212,21 @@ public ElasticsearchEntitlementChecker(PolicyManager policyManager) {
211212
policyManager.checkChangeJVMGlobalState(callerClass);
212213
}
213214

215+
@Override
216+
public void check$java_lang_System$$clearProperty(Class<?> callerClass, String key) {
217+
policyManager.checkWriteProperty(callerClass, key);
218+
}
219+
220+
@Override
221+
public void check$java_lang_System$$setProperty(Class<?> callerClass, String key, String value) {
222+
policyManager.checkWriteProperty(callerClass, key);
223+
}
224+
225+
@Override
226+
public void check$java_lang_System$$setProperties(Class<?> callerClass, Properties props) {
227+
policyManager.checkChangeJVMGlobalState(callerClass);
228+
}
229+
214230
@Override
215231
public void check$java_util_spi_LocaleServiceProvider$(Class<?> callerClass) {
216232
policyManager.checkChangeJVMGlobalState(callerClass);

libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyManager.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,34 @@ public void checkAllNetworkAccess(Class<?> callerClass) {
237237
);
238238
}
239239

240+
public void checkWriteProperty(Class<?> callerClass, String property) {
241+
var requestingClass = requestingClass(callerClass);
242+
if (isTriviallyAllowed(requestingClass)) {
243+
return;
244+
}
245+
246+
ModuleEntitlements entitlements = getEntitlements(requestingClass);
247+
if (entitlements.getEntitlements(WriteSystemPropertiesEntitlement.class).anyMatch(e -> e.properties().contains(property))) {
248+
logger.debug(
249+
() -> Strings.format(
250+
"Entitled: class [%s], module [%s], entitlement [write_system_properties], property [%s]",
251+
requestingClass,
252+
requestingClass.getModule().getName(),
253+
property
254+
)
255+
);
256+
return;
257+
}
258+
throw new NotEntitledException(
259+
Strings.format(
260+
"Missing entitlement: class [%s], module [%s], entitlement [write_system_properties], property [%s]",
261+
requestingClass,
262+
requestingClass.getModule().getName(),
263+
property
264+
)
265+
);
266+
}
267+
240268
private void checkEntitlementPresent(Class<?> callerClass, Class<? extends Entitlement> entitlementClass) {
241269
var requestingClass = requestingClass(callerClass);
242270
if (isTriviallyAllowed(requestingClass)) {

libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyParser.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ public class PolicyParser {
4040
CreateClassLoaderEntitlement.class,
4141
SetHttpsConnectionPropertiesEntitlement.class,
4242
OutboundNetworkEntitlement.class,
43-
InboundNetworkEntitlement.class
43+
InboundNetworkEntitlement.class,
44+
WriteSystemPropertiesEntitlement.class
4445
).collect(Collectors.toUnmodifiableMap(PolicyParser::getEntitlementTypeName, Function.identity()));
4546

4647
protected final XContentParser policyParser;

0 commit comments

Comments
 (0)