src/java.base/share/classes/java/security/AccessController.java
changeset 52431 b0af758a092c
parent 47216 71c04702a3d5
child 53068 7496df94b3b7
--- a/src/java.base/share/classes/java/security/AccessController.java	Wed Nov 07 01:04:26 2018 +0000
+++ b/src/java.base/share/classes/java/security/AccessController.java	Tue Nov 06 16:04:50 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,9 +25,18 @@
 
 package java.security;
 
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.ref.Reference;
 import sun.security.util.Debug;
+import sun.security.util.SecurityConstants;
 import jdk.internal.reflect.CallerSensitive;
 import jdk.internal.reflect.Reflection;
+import jdk.internal.vm.annotation.DontInline;
+import jdk.internal.vm.annotation.ForceInline;
+import jdk.internal.vm.annotation.ReservedStackAccess;
 
 /**
  * <p> The AccessController class is used for access control operations
@@ -296,7 +305,10 @@
      */
 
     @CallerSensitive
-    public static native <T> T doPrivileged(PrivilegedAction<T> action);
+    public static <T> T doPrivileged(PrivilegedAction<T> action)
+    {
+        return executePrivileged(action, null, Reflection.getCallerClass());
+    }
 
     /**
      * Performs the specified {@code PrivilegedAction} with privileges
@@ -369,8 +381,13 @@
      * @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext)
      */
     @CallerSensitive
-    public static native <T> T doPrivileged(PrivilegedAction<T> action,
-                                            AccessControlContext context);
+    public static <T> T doPrivileged(PrivilegedAction<T> action,
+                                     AccessControlContext context)
+    {
+        Class<?> caller = Reflection.getCallerClass();
+        context = checkContext(context, caller);
+        return executePrivileged(action, context, caller);
+    }
 
 
     /**
@@ -425,7 +442,7 @@
         if (perms == null) {
             throw new NullPointerException("null permissions parameter");
         }
-        Class <?> caller = Reflection.getCallerClass();
+        Class<?> caller = Reflection.getCallerClass();
         return AccessController.doPrivileged(action, createWrapper(null,
             caller, parent, context, perms));
     }
@@ -491,7 +508,7 @@
         if (perms == null) {
             throw new NullPointerException("null permissions parameter");
         }
-        Class <?> caller = Reflection.getCallerClass();
+        Class<?> caller = Reflection.getCallerClass();
         return AccessController.doPrivileged(action, createWrapper(dc, caller,
             parent, context, perms));
     }
@@ -524,10 +541,20 @@
      * @see java.security.DomainCombiner
      */
     @CallerSensitive
-    public static native <T> T
+    public static <T> T
         doPrivileged(PrivilegedExceptionAction<T> action)
-        throws PrivilegedActionException;
-
+        throws PrivilegedActionException
+    {
+        AccessControlContext context = null;
+        Class<?> caller = Reflection.getCallerClass();
+        try {
+            return executePrivileged(action, context, caller);
+        } catch (RuntimeException e) {
+            throw e;
+        } catch (Exception e) {
+            throw wrapException(e);
+        }
+    }
 
     /**
      * Performs the specified {@code PrivilegedExceptionAction} with
@@ -587,11 +614,11 @@
                       AccessControlContext parent, AccessControlContext context,
                       Permission[] perms)
     {
-        ProtectionDomain callerPD = getCallerPD(caller);
+        ProtectionDomain callerPD = getProtectionDomain(caller);
         // check if caller is authorized to create context
-        if (context != null && !context.isAuthorized() &&
-            System.getSecurityManager() != null &&
-            !callerPD.impliesCreateAccessControlContext())
+        if (System.getSecurityManager() != null &&
+            context != null && !context.isAuthorized() &&
+            !callerPD.implies(SecurityConstants.CREATE_ACC_PERMISSION))
         {
             return getInnocuousAcc();
         } else {
@@ -611,16 +638,7 @@
         return AccHolder.innocuousAcc;
     }
 
-    private static ProtectionDomain getCallerPD(final Class <?> caller) {
-        ProtectionDomain callerPd = doPrivileged
-            (new PrivilegedAction<>() {
-            public ProtectionDomain run() {
-                return caller.getProtectionDomain();
-            }
-        });
-
-        return callerPd;
-    }
+    private static native ProtectionDomain getProtectionDomain(final Class<?> caller);
 
     /**
      * Performs the specified {@code PrivilegedExceptionAction} with
@@ -659,11 +677,125 @@
      * @see #doPrivileged(PrivilegedAction,AccessControlContext)
      */
     @CallerSensitive
-    public static native <T> T
+    public static <T> T
         doPrivileged(PrivilegedExceptionAction<T> action,
                      AccessControlContext context)
-        throws PrivilegedActionException;
+        throws PrivilegedActionException
+    {
+        Class<?> caller = Reflection.getCallerClass();
+        context = checkContext(context, caller);
+        try {
+            return executePrivileged(action, context, caller);
+        } catch (RuntimeException e) {
+            throw e;
+        } catch (Exception e) {
+            throw wrapException(e);
+        }
+    }
+
+    private static AccessControlContext checkContext(AccessControlContext context,
+        Class<?> caller)
+    {
+        // check if caller is authorized to create context
+        if (System.getSecurityManager() != null &&
+            context != null && !context.isAuthorized() &&
+            context != getInnocuousAcc())
+        {
+            ProtectionDomain callerPD = getProtectionDomain(caller);
+            if (callerPD != null && !callerPD.implies(SecurityConstants.CREATE_ACC_PERMISSION)) {
+                return getInnocuousAcc();
+            }
+        }
+        return context;
+    }
+
+    /**
+     * Sanity check that the caller context is indeed privileged.
+     *
+     * Used by executePrivileged to make sure the frame is properly
+     * recognized by the VM.
+     */
+    private static boolean isPrivileged() {
+        AccessControlContext ctx = getStackAccessControlContext();
+        return ctx == null || ctx.isPrivileged();
+    }
+
+    /**
+     * Execute the action as privileged.
+     *
+     * The VM recognizes this method as special, so any changes to the
+     * name or signature require corresponding changes in
+     * getStackAccessControlContext().
+     */
+    @Hidden
+    @ForceInline
+    private static <T> T
+        executePrivileged(PrivilegedAction<T> action,
+                          AccessControlContext context,
+                          Class<?> caller)
+    {
+        assert isPrivileged(); // sanity check invariant
+        T result = action.run();
+        assert isPrivileged(); // sanity check invariant
 
+        // Keep these alive across the run() call so they can be
+        // retrieved by getStackAccessControlContext().
+        Reference.reachabilityFence(context);
+        Reference.reachabilityFence(caller);
+        Reference.reachabilityFence(action);
+        return result;
+    }
+
+    /**
+     * Execute the action as privileged.
+     *
+     * The VM recognizes this method as special, so any changes to the
+     * name or signature require corresponding changes in
+     * getStackAccessControlContext().
+     */
+    @Hidden
+    @ForceInline
+    private static <T> T
+        executePrivileged(PrivilegedExceptionAction<T> action,
+                          AccessControlContext context,
+                          Class<?> caller)
+        throws Exception
+    {
+        assert isPrivileged(); // sanity check invariant
+        T result = action.run();
+        assert isPrivileged(); // sanity check invariant
+
+        // Keep these alive across the run() call so they can be
+        // retrieved by getStackAccessControlContext().
+        Reference.reachabilityFence(context);
+        Reference.reachabilityFence(caller);
+        Reference.reachabilityFence(action);
+        return result;
+    }
+
+
+    /**
+     * Internal marker for hidden implementation frames.
+     */
+    /*non-public*/
+    @Target(ElementType.METHOD)
+    @Retention(RetentionPolicy.RUNTIME)
+    @interface Hidden {
+    }
+
+
+    /**
+     * Wrap an exception.  The annotations are used in a best effort to
+     * avoid StackOverflowError in the caller.  Inlining the callees as
+     * well and tail-call elimination could also help here, but are not
+     * needed for correctness, only quality of implementation.
+     */
+    @Hidden
+    @ForceInline
+    @ReservedStackAccess
+    private static PrivilegedActionException wrapException(Exception e) {
+        return new PrivilegedActionException(e);
+    }
 
     /**
      * Performs the specified {@code PrivilegedExceptionAction} with
@@ -720,7 +852,7 @@
         if (perms == null) {
             throw new NullPointerException("null permissions parameter");
         }
-        Class <?> caller = Reflection.getCallerClass();
+        Class<?> caller = Reflection.getCallerClass();
         return AccessController.doPrivileged(action, createWrapper(null, caller, parent, context, perms));
     }
 
@@ -789,7 +921,7 @@
         if (perms == null) {
             throw new NullPointerException("null permissions parameter");
         }
-        Class <?> caller = Reflection.getCallerClass();
+        Class<?> caller = Reflection.getCallerClass();
         return AccessController.doPrivileged(action, createWrapper(dc, caller,
             parent, context, perms));
     }