4040import java .security .Provider ;
4141import java .security .SecureRandom ;
4242import java .util .ArrayDeque ;
43+ import java .util .ArrayList ;
4344import java .util .List ;
4445import java .util .Map ;
4546import java .util .Objects ;
4849
4950import jdk .vm .ci .meta .MetaAccessProvider ;
5051import jdk .vm .ci .meta .ResolvedJavaField ;
51- import org .graalvm .compiler . phases . common . LazyValue ;
52+ import org .graalvm .collections . Pair ;
5253import org .graalvm .compiler .serviceprovider .JavaVersionUtil ;
5354import org .graalvm .nativeimage .Platform ;
5455import 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" })
318268class 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