Skip to content

Commit 310e0b5

Browse files
rjernstelasticsearchmachineelasticmachine
authored
Consider entitlement lib as system module (elastic#123315) (elastic#123338)
* 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 34bf77a commit 310e0b5

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;
@@ -52,6 +54,7 @@
5254
import java.io.InputStream;
5355
import java.io.PrintStream;
5456
import java.lang.invoke.MethodHandles;
57+
import java.lang.reflect.InvocationTargetException;
5558
import java.nio.file.Files;
5659
import java.nio.file.Path;
5760
import java.security.Permission;
@@ -248,6 +251,7 @@ private static void initPhase2(Bootstrap bootstrap) throws IOException {
248251
nodeEnv.logsDir(),
249252
nodeEnv.tmpDir()
250253
);
254+
entitlementSelfTest();
251255
} else {
252256
assert RuntimeVersionFeature.isSecurityManagerAvailable();
253257
// no need to explicitly enable native access for legacy code
@@ -264,6 +268,34 @@ private static void initPhase2(Bootstrap bootstrap) throws IOException {
264268
bootstrap.setPluginsLoader(pluginsLoader);
265269
}
266270

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

0 commit comments

Comments
 (0)