Skip to content

Commit 5b0591e

Browse files
rjernstelasticsearchmachineelasticmachine
authored
Consider entitlement lib as system module (#123315)
* Consider entitlement lib as system module Entitlements sometimes needs to perform sensitive operations, particularly within the FileAccessTree. This commit expands the trivially allowed check to include entitlements as one of the system modules alongside the jdk. One consequence is that the self test must be moved outside entitlements. * [CI] Auto commit changes from spotless * remove old method call --------- Co-authored-by: elasticsearchmachine <[email protected]> Co-authored-by: Elastic Machine <[email protected]>
1 parent 4a6343a commit 5b0591e

File tree

3 files changed

+38
-59
lines changed

3 files changed

+38
-59
lines changed

libs/entitlement/src/main/java/org/elasticsearch/entitlement/bootstrap/EntitlementBootstrap.java

Lines changed: 0 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,13 @@
1414
import com.sun.tools.attach.AttachNotSupportedException;
1515
import com.sun.tools.attach.VirtualMachine;
1616

17-
import org.elasticsearch.core.CheckedConsumer;
1817
import org.elasticsearch.core.SuppressForbidden;
1918
import org.elasticsearch.entitlement.initialization.EntitlementInitialization;
20-
import org.elasticsearch.entitlement.runtime.api.NotEntitledException;
2119
import org.elasticsearch.entitlement.runtime.policy.Policy;
2220
import org.elasticsearch.logging.LogManager;
2321
import org.elasticsearch.logging.Logger;
2422

2523
import java.io.IOException;
26-
import java.lang.reflect.InvocationTargetException;
2724
import java.nio.file.Files;
2825
import java.nio.file.Path;
2926
import java.util.Map;
@@ -114,7 +111,6 @@ public static void bootstrap(
114111
);
115112
exportInitializationToAgent();
116113
loadAgent(findAgentJar());
117-
selfTest();
118114
}
119115

120116
@SuppressForbidden(reason = "The VirtualMachine API is the only way to attach a java agent dynamically")
@@ -160,50 +156,5 @@ private static String findAgentJar() {
160156
}
161157
}
162158

163-
/**
164-
* Attempt a few sensitive operations to ensure that some are permitted and some are forbidden.
165-
* <p>
166-
*
167-
* This serves two purposes:
168-
*
169-
* <ol>
170-
* <li>
171-
* a smoke test to make sure the entitlements system is not completely broken, and
172-
* </li>
173-
* <li>
174-
* an early test of certain important operations so they don't fail later on at an awkward time.
175-
* </li>
176-
* </ol>
177-
*
178-
* @throws IllegalStateException if the entitlements system can't prevent an unauthorized action of our choosing
179-
*/
180-
private static void selfTest() {
181-
ensureCannotStartProcess(ProcessBuilder::start);
182-
// Try again with reflection
183-
ensureCannotStartProcess(EntitlementBootstrap::reflectiveStartProcess);
184-
}
185-
186-
private static void ensureCannotStartProcess(CheckedConsumer<ProcessBuilder, ?> startProcess) {
187-
try {
188-
// The command doesn't matter; it doesn't even need to exist
189-
startProcess.accept(new ProcessBuilder(""));
190-
} catch (NotEntitledException e) {
191-
logger.debug("Success: Entitlement protection correctly prevented process creation");
192-
return;
193-
} catch (Exception e) {
194-
throw new IllegalStateException("Failed entitlement protection self-test", e);
195-
}
196-
throw new IllegalStateException("Entitlement protection self-test was incorrectly permitted");
197-
}
198-
199-
private static void reflectiveStartProcess(ProcessBuilder pb) throws Exception {
200-
try {
201-
var start = ProcessBuilder.class.getMethod("start");
202-
start.invoke(pb);
203-
} catch (InvocationTargetException e) {
204-
throw (Exception) e.getCause();
205-
}
206-
}
207-
208159
private static final Logger logger = LogManager.getLogger(EntitlementBootstrap.class);
209160
}

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

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
import org.elasticsearch.core.Strings;
1313
import org.elasticsearch.core.SuppressForbidden;
1414
import org.elasticsearch.entitlement.bootstrap.EntitlementBootstrap;
15-
import org.elasticsearch.entitlement.bridge.EntitlementChecker;
1615
import org.elasticsearch.entitlement.instrumentation.InstrumentationService;
1716
import org.elasticsearch.entitlement.runtime.api.NotEntitledException;
1817
import org.elasticsearch.entitlement.runtime.policy.entitlements.CreateClassLoaderEntitlement;
@@ -126,11 +125,12 @@ private static Set<Module> findSystemModules() {
126125
.stream()
127126
.map(ModuleReference::descriptor)
128127
.collect(Collectors.toUnmodifiableSet());
129-
return ModuleLayer.boot()
130-
.modules()
131-
.stream()
132-
.filter(m -> systemModulesDescriptors.contains(m.getDescriptor()))
133-
.collect(Collectors.toUnmodifiableSet());
128+
return Stream.concat(
129+
// entitlements is a "system" module, we can do anything from it
130+
Stream.of(PolicyManager.class.getModule()),
131+
// anything in the boot layer is also part of the system
132+
ModuleLayer.boot().modules().stream().filter(m -> systemModulesDescriptors.contains(m.getDescriptor()))
133+
).collect(Collectors.toUnmodifiableSet());
134134
}
135135

136136
/**
@@ -564,10 +564,6 @@ private static boolean isTriviallyAllowed(Class<?> requestingClass) {
564564
logger.debug("Entitlement trivially allowed from system module [{}]", requestingClass.getModule().getName());
565565
return true;
566566
}
567-
if (EntitlementChecker.class.isAssignableFrom(requestingClass)) {
568-
logger.debug("Entitlement trivially allowed for EntitlementChecker class");
569-
return true;
570-
}
571567
logger.trace("Entitlement not trivially allowed");
572568
return false;
573569
}

server/src/main/java/org/elasticsearch/bootstrap/Elasticsearch.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,11 @@
2929
import org.elasticsearch.common.util.concurrent.RunOnce;
3030
import org.elasticsearch.core.AbstractRefCounted;
3131
import org.elasticsearch.core.Booleans;
32+
import org.elasticsearch.core.CheckedConsumer;
3233
import org.elasticsearch.core.IOUtils;
3334
import org.elasticsearch.core.SuppressForbidden;
3435
import org.elasticsearch.entitlement.bootstrap.EntitlementBootstrap;
36+
import org.elasticsearch.entitlement.runtime.api.NotEntitledException;
3537
import org.elasticsearch.entitlement.runtime.policy.Policy;
3638
import org.elasticsearch.entitlement.runtime.policy.PolicyParserUtils;
3739
import org.elasticsearch.entitlement.runtime.policy.entitlements.LoadNativeLibrariesEntitlement;
@@ -54,6 +56,7 @@
5456
import java.io.InputStream;
5557
import java.io.PrintStream;
5658
import java.lang.invoke.MethodHandles;
59+
import java.lang.reflect.InvocationTargetException;
5760
import java.nio.file.Files;
5861
import java.nio.file.Path;
5962
import java.security.Permission;
@@ -254,6 +257,7 @@ private static void initPhase2(Bootstrap bootstrap) throws IOException {
254257
nodeEnv.logsDir(),
255258
nodeEnv.tmpDir()
256259
);
260+
entitlementSelfTest();
257261
} else {
258262
assert RuntimeVersionFeature.isSecurityManagerAvailable();
259263
// no need to explicitly enable native access for legacy code
@@ -270,6 +274,34 @@ private static void initPhase2(Bootstrap bootstrap) throws IOException {
270274
bootstrap.setPluginsLoader(pluginsLoader);
271275
}
272276

277+
// check entitlements were loaded correctly. note this must be outside the entitlements lib.
278+
private static void entitlementSelfTest() {
279+
ensureCannotStartProcess(ProcessBuilder::start);
280+
// Try again with reflection
281+
ensureCannotStartProcess(Elasticsearch::reflectiveStartProcess);
282+
}
283+
284+
private static void ensureCannotStartProcess(CheckedConsumer<ProcessBuilder, ?> startProcess) {
285+
try {
286+
// The command doesn't matter; it doesn't even need to exist
287+
startProcess.accept(new ProcessBuilder(""));
288+
} catch (NotEntitledException e) {
289+
return;
290+
} catch (Exception e) {
291+
throw new IllegalStateException("Failed entitlement protection self-test", e);
292+
}
293+
throw new IllegalStateException("Entitlement protection self-test was incorrectly permitted");
294+
}
295+
296+
private static void reflectiveStartProcess(ProcessBuilder pb) throws Exception {
297+
try {
298+
var start = ProcessBuilder.class.getMethod("start");
299+
start.invoke(pb);
300+
} catch (InvocationTargetException e) {
301+
throw (Exception) e.getCause();
302+
}
303+
}
304+
273305
private static void ensureInitialized(Class<?>... classes) {
274306
for (final var clazz : classes) {
275307
try {

0 commit comments

Comments
 (0)