Skip to content

Commit 2ad1de6

Browse files
Add allowlist for known-good JDK contexts.
1 parent 1c248cd commit 2ad1de6

File tree

2 files changed

+71
-172
lines changed

2 files changed

+71
-172
lines changed

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/RecomputedFields.java

Lines changed: 0 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,8 @@
3333
import java.lang.ref.WeakReference;
3434
import java.lang.reflect.Field;
3535
import java.lang.reflect.Modifier;
36-
import java.net.SocketPermission;
3736
import java.nio.charset.CharsetDecoder;
3837
import java.nio.charset.CoderResult;
39-
import java.security.AccessControlContext;
4038
import java.util.Map;
4139
import java.util.concurrent.ConcurrentHashMap;
4240
import java.util.concurrent.ConcurrentMap;
@@ -48,7 +46,6 @@
4846
import java.util.concurrent.locks.ReentrantLock;
4947
import java.util.function.Consumer;
5048

51-
import org.graalvm.compiler.phases.common.LazyValue;
5249
import org.graalvm.compiler.serviceprovider.GraalUnsafeAccess;
5350
import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
5451
import org.graalvm.nativeimage.ImageSingletons;
@@ -363,118 +360,6 @@ public static int getCommonPoolParallelism() {
363360
}
364361
}
365362

366-
/**
367-
* Since AccessControlContextFeature replaces all AccessControlContext objects with
368-
* NO_CONTEXT_SINGLETON, we need to reinitialize them in runtime.
369-
*/
370-
371-
@TargetClass(className = "java.security.AccessController$AccHolder", onlyWith = JDK11OrLater.class)
372-
@SuppressWarnings("unused") //
373-
final class Target_java_security_AccessController_AccHolder {
374-
@Alias @InjectAccessors(AccessControllerUtil.INNOCUOUS_ACC.class) static AccessControlContext innocuousAcc;
375-
}
376-
377-
@TargetClass(className = "java.util.Calendar$CalendarAccessControlContext")
378-
@SuppressWarnings("unused") //
379-
final class Target_java_util_Calendar_CalendarAccessControlContext {
380-
@Alias @InjectAccessors(CalendarAccessControlContextAcc.class) static AccessControlContext INSTANCE;
381-
}
382-
383-
class CalendarAccessControlContextAcc {
384-
static LazyValue<AccessControlContext> acc = new LazyValue<>(() -> AccessControllerUtil.contextWithPermissions(
385-
new RuntimePermission("accessClassInPackage.sun.util.calendar")));
386-
387-
static AccessControlContext get() {
388-
return acc.get();
389-
}
390-
}
391-
392-
@TargetClass(className = "java.util.concurrent.ForkJoinPool$DefaultForkJoinWorkerThreadFactory", onlyWith = JDK11OrLater.class)
393-
@SuppressWarnings("unused") //
394-
final class Target_java_util_concurrent_ForkJoinPool_DefaultForkJoinWorkerThreadFactory {
395-
@Alias @InjectAccessors(DefaultForkJoinWorkerThreadFactoryAcc.class) static AccessControlContext ACC;
396-
}
397-
398-
class DefaultForkJoinWorkerThreadFactoryAcc {
399-
static LazyValue<AccessControlContext> acc = new LazyValue<>(() -> AccessControllerUtil.contextWithPermissions(
400-
new RuntimePermission("getClassLoader"),
401-
new RuntimePermission("setContextClassLoader")));
402-
403-
static AccessControlContext get() {
404-
return acc.get();
405-
}
406-
}
407-
408-
@TargetClass(className = "java.util.concurrent.ForkJoinPool$InnocuousForkJoinWorkerThreadFactory", onlyWith = JDK11OrLater.class)
409-
@SuppressWarnings("unused") //
410-
final class Target_java_util_concurrent_ForkJoinPool_InnocuousForkJoinWorkerThreadFactory {
411-
@Alias @InjectAccessors(InnocuousForkJoinWorkerThreadFactoryAcc.class) static AccessControlContext ACC;
412-
}
413-
414-
class InnocuousForkJoinWorkerThreadFactoryAcc {
415-
static LazyValue<AccessControlContext> acc = new LazyValue<>(() -> AccessControllerUtil.contextWithPermissions(
416-
new RuntimePermission("modifyThread"),
417-
new RuntimePermission("enableContextClassLoaderOverride"),
418-
new RuntimePermission("modifyThreadGroup"),
419-
new RuntimePermission("getClassLoader"),
420-
new RuntimePermission("setContextClassLoader")));
421-
422-
static AccessControlContext get() {
423-
return acc.get();
424-
}
425-
}
426-
427-
@TargetClass(className = "java.util.concurrent.ForkJoinWorkerThread")
428-
@SuppressWarnings("unused") //
429-
final class Target_java_util_concurrent_ForkJoinWorkerThread {
430-
@Alias @InjectAccessors(AccessControllerUtil.INNOCUOUS_ACC.class) static AccessControlContext INNOCUOUS_ACC;
431-
}
432-
433-
@TargetClass(className = "sun.misc.InnocuousThread", onlyWith = JDK8OrEarlier.class)
434-
@SuppressWarnings("unused") //
435-
final class Target_sun_misc_InnocuousThread {
436-
@Alias @InjectAccessors(AccessControllerUtil.INNOCUOUS_ACC.class) static AccessControlContext ACC;
437-
}
438-
439-
@TargetClass(className = "jdk.internal.misc.InnocuousThread", onlyWith = JDK11OrLater.class)
440-
@SuppressWarnings("unused") //
441-
final class Target_jdk_internal_misc_InnocuousThread {
442-
@Alias @InjectAccessors(AccessControllerUtil.INNOCUOUS_ACC.class) static AccessControlContext ACC;
443-
}
444-
445-
@TargetClass(className = "javax.management.Monitor", onlyWith = PlatformHasClass.class)
446-
@SuppressWarnings("unused") //
447-
final class Target_javax_management_Monitor {
448-
@Alias @InjectAccessors(AccessControllerUtil.NO_PERMISSIONS_CONTEXT.class) static AccessControlContext noPermissionsACC;
449-
}
450-
451-
@TargetClass(className = "java.rmi.activation.ActivationID")
452-
@SuppressWarnings("unused") //
453-
final class Target_java_rmi_activation_ActivationID {
454-
@Alias @InjectAccessors(AccessControllerUtil.NO_PERMISSIONS_CONTEXT.class) static AccessControlContext NOPERMS_ACC;
455-
}
456-
457-
@TargetClass(className = "sun.rmi.transport.DGCCClient", onlyWith = PlatformHasClass.class)
458-
@SuppressWarnings("unused") //
459-
final class Target_sun_rmi_transport_DGCCClient {
460-
@Alias @InjectAccessors(SocketAcc.class) static AccessControlContext SOCKET_ACC;
461-
}
462-
463-
class SocketAcc {
464-
static LazyValue<AccessControlContext> acc = new LazyValue<>(() -> AccessControllerUtil.contextWithPermissions(
465-
new SocketPermission("*", "connect,resolve")));
466-
467-
static AccessControlContext get() {
468-
return acc.get();
469-
}
470-
}
471-
472-
@TargetClass(className = "sun.rmi.transport.tcp.TCPTransport")
473-
@SuppressWarnings("unused") //
474-
final class Target_sun_rmi_transport_tcp_TCPTransport {
475-
@Alias @InjectAccessors(AccessControllerUtil.NO_PERMISSIONS_CONTEXT.class) static AccessControlContext NOPERMS_ACC;
476-
}
477-
478363
/**
479364
* An injected field to replace ForkJoinPool.common.
480365
*

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/SecuritySubstitutions.java

Lines changed: 71 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import java.security.Provider;
4141
import java.security.SecureRandom;
4242
import java.util.ArrayDeque;
43+
import java.util.ArrayList;
4344
import java.util.List;
4445
import java.util.Map;
4546
import java.util.Objects;
@@ -48,7 +49,7 @@
4849

4950
import jdk.vm.ci.meta.MetaAccessProvider;
5051
import jdk.vm.ci.meta.ResolvedJavaField;
51-
import org.graalvm.compiler.phases.common.LazyValue;
52+
import org.graalvm.collections.Pair;
5253
import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
5354
import org.graalvm.nativeimage.Platform;
5455
import org.graalvm.nativeimage.Platforms;
@@ -160,7 +161,8 @@ static <T> T executePrivileged(PrivilegedAction<T> action, AccessControlContext
160161
}
161162

162163
if (context != null && context.equals(AccessControllerUtil.NO_CONTEXT_SINGLETON)) {
163-
VMError.shouldNotReachHere("Invoked AccessControlContext was replaced at build time but wasn't reinitialized at run time.");
164+
VMError.shouldNotReachHere("Invoked AccessControlContext was replaced at build time but wasn't reinitialized at run time.\n" +
165+
"This might be an indicator of improper build time initialization, or of a non-compatible JDK version.");
164166
}
165167

166168
AccessControllerUtil.PrivilegedStack.push(context, caller);
@@ -199,50 +201,6 @@ class AccessControllerUtil {
199201
}
200202
}
201203

202-
static class INNOCUOUS_ACC {
203-
static LazyValue<AccessControlContext> acc = new LazyValue<>(() -> new AccessControlContext(new ProtectionDomain[]{new ProtectionDomain(null, null)}));
204-
205-
static AccessControlContext get() {
206-
return acc.get();
207-
}
208-
209-
static void set(AccessControlContext ctx) {
210-
}
211-
}
212-
213-
static class NO_PERMISSIONS_CONTEXT {
214-
static LazyValue<AccessControlContext> acc = new LazyValue<>(() -> AccessControllerUtil.contextWithPermissions(new Permission[0]));
215-
216-
static AccessControlContext get() {
217-
return acc.get();
218-
}
219-
220-
static void set(AccessControlContext ctx) {
221-
}
222-
}
223-
224-
static class GET_CLASS_LOADER_CONTEXT {
225-
static LazyValue<AccessControlContext> acc = new LazyValue<>(() -> AccessControllerUtil.contextWithPermissions(new RuntimePermission("getClassLoader")));
226-
227-
static AccessControlContext get() {
228-
return acc.get();
229-
}
230-
231-
static void set(AccessControlContext ctx) {
232-
}
233-
}
234-
235-
static class GET_LOOKUP_CONTEXT {
236-
static LazyValue<AccessControlContext> acc = new LazyValue<>(() -> AccessControllerUtil.contextWithPermissions(new RuntimePermission("dynalink.getLookup")));
237-
238-
static AccessControlContext get() {
239-
return acc.get();
240-
}
241-
242-
static void set(AccessControlContext ctx) {
243-
}
244-
}
245-
246204
public static class PrivilegedStack {
247205

248206
public static class StackElement {
@@ -263,7 +221,7 @@ public Class<?> getCaller() {
263221
}
264222
}
265223

266-
@SuppressWarnings("rawtypes") private static final FastThreadLocalObject<ArrayDeque> stack = FastThreadLocalFactory.createObject(ArrayDeque.class);
224+
@SuppressWarnings("rawtypes") private static final FastThreadLocalObject<ArrayDeque> stack = FastThreadLocalFactory.createObject(ArrayDeque.class, "accStack");
267225

268226
@SuppressWarnings("unchecked")
269227
private static ArrayDeque<StackElement> getStack() {
@@ -296,14 +254,6 @@ public static int length() {
296254
}
297255
}
298256

299-
public static AccessControlContext contextWithPermissions(Permission... perms) {
300-
Permissions permissions = new Permissions();
301-
for (Permission perm : perms) {
302-
permissions.add(perm);
303-
}
304-
return new AccessControlContext(new ProtectionDomain[]{new ProtectionDomain(null, permissions)});
305-
}
306-
307257
static Throwable wrapCheckedException(Throwable ex) {
308258
if (ex instanceof Exception && !(ex instanceof RuntimeException)) {
309259
return new PrivilegedActionException((Exception) ex);
@@ -316,14 +266,78 @@ static Throwable wrapCheckedException(Throwable ex) {
316266
@AutomaticFeature
317267
@SuppressWarnings({"unused"})
318268
class AccessControlContextFeature implements Feature {
269+
270+
static List<Pair<String, AccessControlContext>> allowedContexts;
271+
272+
@Override
273+
public void beforeAnalysis(BeforeAnalysisAccess access) {
274+
// Following AccessControlContexts are allowed in the image heap since they cannot leak
275+
// sensitive information.
276+
// They mostly originate from JDK's static final fields, and they do not feature
277+
// CodeSources, DomainCombiners etc.
278+
// New JDK versions can feature new or remove old contexts, so this method should be kept
279+
// up-to-date.
280+
allowContextIfExists(access, "java.util.Calendar$CalendarAccessControlContext", "INSTANCE");
281+
allowContextIfExists(access, "javax.management.monitor.Monitor", "noPermissionsACC");
282+
283+
if (JavaVersionUtil.JAVA_SPEC < 9) {
284+
allowContextIfExists(access, "sun.misc.InnocuousThread", "ACC");
285+
}
286+
if (JavaVersionUtil.JAVA_SPEC >= 9) {
287+
allowContextIfExists(access, "java.security.AccessController$AccHolder", "innocuousAcc");
288+
allowContextIfExists(access, "java.util.concurrent.ForkJoinPool$DefaultForkJoinWorkerThreadFactory", "ACC");
289+
}
290+
if (JavaVersionUtil.JAVA_SPEC < 17) {
291+
allowContextIfExists(access, "java.util.concurrent.ForkJoinWorkerThread", "INNOCUOUS_ACC");
292+
}
293+
if (JavaVersionUtil.JAVA_SPEC >= 9 && JavaVersionUtil.JAVA_SPEC < 17) {
294+
allowContextIfExists(access, "java.util.concurrent.ForkJoinPool$InnocuousForkJoinWorkerThreadFactory", "ACC");
295+
}
296+
if (JavaVersionUtil.JAVA_SPEC >= 17) {
297+
allowContextIfExists(access, "java.util.concurrent.ForkJoinPool$WorkQueue", "INNOCUOUS_ACC");
298+
allowContextIfExists(access, "java.util.concurrent.ForkJoinPool$DefaultCommonPoolForkJoinWorkerThreadFactory", "ACC");
299+
}
300+
}
301+
302+
static void allowContextIfExists(BeforeAnalysisAccess access, String className, String fieldName) {
303+
if (allowedContexts == null) {
304+
allowedContexts = new ArrayList<>();
305+
}
306+
try {
307+
// Checkstyle: stop
308+
Class<?> clazz = Class.forName(className);
309+
// Checkstyle: resume
310+
String description = className + "." + fieldName;
311+
access.registerReachabilityHandler(access1 -> { // Use only reachable
312+
// AccessControlContexts
313+
try {
314+
AccessControlContext acc = ReflectionUtil.readStaticField(clazz, fieldName);
315+
allowedContexts.add(Pair.create(description, acc));
316+
} catch (ReflectionUtil.ReflectionUtilError e) {
317+
VMError.shouldNotReachHere("Following field isn't present in JDK" + JavaVersionUtil.JAVA_SPEC + ": " + description);
318+
}
319+
}, clazz);
320+
321+
} catch (ReflectiveOperationException e) {
322+
VMError.shouldNotReachHere("Following class isn't present in JDK" + JavaVersionUtil.JAVA_SPEC + ": " + className);
323+
}
324+
}
325+
319326
@Override
320327
public void duringSetup(DuringSetupAccess access) {
321328
access.registerObjectReplacer(AccessControlContextFeature::replaceAccessControlContext);
322329
}
323330

324331
private static Object replaceAccessControlContext(Object obj) {
325-
if (obj instanceof AccessControlContext) {
326-
return AccessControllerUtil.NO_CONTEXT_SINGLETON;
332+
if (allowedContexts == null) { // allowedContexts wasn't populated yet
333+
return obj;
334+
}
335+
if (obj instanceof AccessControlContext && obj != AccessControllerUtil.NO_CONTEXT_SINGLETON) {
336+
if (allowedContexts.stream().anyMatch((e) -> obj.equals(e.getRight()))) {
337+
return obj;
338+
} else {
339+
return AccessControllerUtil.NO_CONTEXT_SINGLETON;
340+
}
327341
}
328342
return obj;
329343
}

0 commit comments

Comments
 (0)