8212605: Pure-Java implementation of AccessController.doPrivileged

Reviewed-by: dholmes, mullan, vlivanov, mchung, alanb, rriggs
This commit is contained in:
Dean Long 2018-11-06 16:04:50 -08:00
parent c8c41d1444
commit a9ae141836
24 changed files with 213 additions and 450 deletions

View file

@ -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 @@ public final class AccessController {
*/
@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 @@ public final class AccessController {
* @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 @@ public final class AccessController {
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 @@ public final class AccessController {
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 @@ public final class AccessController {
* @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 @@ public final class AccessController {
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 @@ public final class AccessController {
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 @@ public final class AccessController {
* @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 @@ public final class AccessController {
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 @@ public final class AccessController {
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));
}

View file

@ -394,11 +394,6 @@ public class ProtectionDomain {
return false;
}
// called by the VM -- do not remove
boolean impliesCreateAccessControlContext() {
return implies(SecurityConstants.CREATE_ACC_PERMISSION);
}
/**
* Convert a ProtectionDomain to a String.
*/