提交 861bd85a 编写于 作者: J jdn

8014097: add doPrivileged methods with limited privilege scope

Reviewed-by: mchung
上级 f45551af
......@@ -85,6 +85,15 @@ public final class AccessControlContext {
private DomainCombiner combiner = null;
// limited privilege scope
private Permission permissions[];
private AccessControlContext parent;
private boolean isWrapped;
// is constrained by limited privilege scope?
private boolean isLimited;
private ProtectionDomain limitedContext[];
private static boolean debugInit = false;
private static Debug debug = null;
......@@ -178,14 +187,79 @@ public final class AccessControlContext {
/**
* package private for AccessController
*
* This "argument wrapper" context will be passed as the actual context
* parameter on an internal doPrivileged() call used in the implementation.
*/
AccessControlContext(ProtectionDomain context[], DomainCombiner combiner) {
AccessControlContext(ProtectionDomain caller, DomainCombiner combiner,
AccessControlContext parent, AccessControlContext context,
Permission[] perms)
{
/*
* Combine the domains from the doPrivileged() context into our
* wrapper context, if necessary.
*/
ProtectionDomain[] callerPDs = null;
if (caller != null) {
callerPDs = new ProtectionDomain[] { caller };
}
if (context != null) {
this.context = context.clone();
if (combiner != null) {
this.context = combiner.combine(callerPDs, context.context);
} else {
this.context = combine(callerPDs, context.context);
}
} else {
/*
* Call combiner even if there is seemingly nothing to combine.
*/
if (combiner != null) {
this.context = combiner.combine(callerPDs, null);
} else {
this.context = combine(callerPDs, null);
}
}
this.combiner = combiner;
Permission[] tmp = null;
if (perms != null) {
tmp = new Permission[perms.length];
for (int i=0; i < perms.length; i++) {
if (perms[i] == null) {
throw new NullPointerException("permission can't be null");
}
/*
* An AllPermission argument is equivalent to calling
* doPrivileged() without any limit permissions.
*/
if (perms[i].getClass() == AllPermission.class) {
parent = null;
}
tmp[i] = perms[i];
}
}
/*
* For a doPrivileged() with limited privilege scope, initialize
* the relevant fields.
*
* The limitedContext field contains the union of all domains which
* are enclosed by this limited privilege scope. In other words,
* it contains all of the domains which could potentially be checked
* if none of the limiting permissions implied a requested permission.
*/
if (parent != null) {
this.limitedContext = combine(parent.context, parent.limitedContext);
this.isLimited = true;
this.isWrapped = true;
this.permissions = tmp;
this.parent = parent;
this.privilegedContext = context; // used in checkPermission2()
}
}
/**
* package private constructor for AccessController.getContext()
*/
......@@ -260,6 +334,13 @@ public final class AccessControlContext {
if (sm != null) {
sm.checkPermission(SecurityConstants.GET_COMBINER_PERMISSION);
}
return getCombiner();
}
/**
* package private for AccessController
*/
DomainCombiner getCombiner() {
return combiner;
}
......@@ -335,8 +416,10 @@ public final class AccessControlContext {
or the first domain was a Privileged system domain. This
is to make the common case for system code very fast */
if (context == null)
if (context == null) {
checkPermission2(perm);
return;
}
for (int i=0; i< context.length; i++) {
if (context[i] != null && !context[i].implies(perm)) {
......@@ -370,20 +453,108 @@ public final class AccessControlContext {
debug.println("access allowed "+perm);
}
return;
checkPermission2(perm);
}
/*
* Check the domains associated with the limited privilege scope.
*/
private void checkPermission2(Permission perm) {
if (!isLimited) {
return;
}
/*
* Check the doPrivileged() context parameter, if present.
*/
if (privilegedContext != null) {
privilegedContext.checkPermission2(perm);
}
/*
* Ignore the limited permissions and parent fields of a wrapper
* context since they were already carried down into the unwrapped
* context.
*/
if (isWrapped) {
return;
}
/*
* Try to match any limited privilege scope.
*/
if (permissions != null) {
Class<?> permClass = perm.getClass();
for (int i=0; i < permissions.length; i++) {
Permission limit = permissions[i];
if (limit.getClass().equals(permClass) && limit.implies(perm)) {
return;
}
}
}
/*
* Check the limited privilege scope up the call stack or the inherited
* parent thread call stack of this ACC.
*/
if (parent != null) {
/*
* As an optimization, if the parent context is the inherited call
* stack context from a parent thread then checking the protection
* domains of the parent context is redundant since they have
* already been merged into the child thread's context by
* optimize(). When parent is set to an inherited context this
* context was not directly created by a limited scope
* doPrivileged() and it does not have its own limited permissions.
*/
if (permissions == null) {
parent.checkPermission2(perm);
} else {
parent.checkPermission(perm);
}
}
}
/**
* Take the stack-based context (this) and combine it with the
* privileged or inherited context, if need be.
* privileged or inherited context, if need be. Any limited
* privilege scope is flagged regardless of whether the assigned
* context comes from an immediately enclosing limited doPrivileged().
* The limited privilege scope can indirectly flow from the inherited
* parent thread or an assigned context previously captured by getContext().
*/
AccessControlContext optimize() {
// the assigned (privileged or inherited) context
AccessControlContext acc;
DomainCombiner combiner = null;
AccessControlContext parent = null;
Permission[] permissions = null;
if (isPrivileged) {
acc = privilegedContext;
if (acc != null) {
/*
* If the context is from a limited scope doPrivileged() then
* copy the permissions and parent fields out of the wrapper
* context that was created to hold them.
*/
if (acc.isWrapped) {
permissions = acc.permissions;
parent = acc.parent;
}
}
} else {
acc = AccessController.getInheritedAccessControlContext();
if (acc != null) {
/*
* If the inherited context is constrained by a limited scope
* doPrivileged() then set it as our parent so we will process
* the non-domain-related state.
*/
if (acc.isLimited) {
parent = acc;
}
}
}
// this.context could be null if only system code is on the stack;
......@@ -393,53 +564,98 @@ public final class AccessControlContext {
// acc.context could be null if only system code was involved;
// in that case, ignore the assigned context
boolean skipAssigned = (acc == null || acc.context == null);
ProtectionDomain[] assigned = (skipAssigned) ? null : acc.context;
ProtectionDomain[] pd;
// if there is no enclosing limited privilege scope on the stack or
// inherited from a parent thread
boolean skipLimited = ((acc == null || !acc.isWrapped) && parent == null);
if (acc != null && acc.combiner != null) {
// let the assigned acc's combiner do its thing
return goCombiner(context, acc);
}
if (getDebug() != null) {
debug.println("AccessControlContext invoking the Combiner");
}
// optimization: if neither have contexts; return acc if possible
// rather than this, because acc might have a combiner
if (skipAssigned && skipStack) {
return this;
}
// No need to clone current and assigned.context
// combine() will not update them
combiner = acc.combiner;
pd = combiner.combine(context, assigned);
} else {
if (skipStack) {
if (skipAssigned) {
calculateFields(acc, parent, permissions);
return this;
} else if (skipLimited) {
return acc;
}
} else if (assigned != null) {
if (skipLimited) {
// optimization: if there is a single stack domain and
// that domain is already in the assigned context; no
// need to combine
if (context.length == 1 && context[0] == assigned[0]) {
return acc;
}
}
}
// optimization: if there is no stack context; there is no reason
// to compress the assigned context, it already is compressed
if (skipStack) {
return acc;
pd = combine(context, assigned);
if (skipLimited && !skipAssigned && pd == assigned) {
return acc;
} else if (skipAssigned && pd == context) {
calculateFields(acc, parent, permissions);
return this;
}
}
int slen = context.length;
// Reuse existing ACC
this.context = pd;
this.combiner = combiner;
this.isPrivileged = false;
calculateFields(acc, parent, permissions);
return this;
}
/*
* Combine the current (stack) and assigned domains.
*/
private static ProtectionDomain[] combine(ProtectionDomain[]current,
ProtectionDomain[] assigned) {
// current could be null if only system code is on the stack;
// in that case, ignore the stack context
boolean skipStack = (current == null);
// assigned could be null if only system code was involved;
// in that case, ignore the assigned context
boolean skipAssigned = (assigned == null);
int slen = (skipStack) ? 0 : current.length;
// optimization: if there is no assigned context and the stack length
// is less then or equal to two; there is no reason to compress the
// stack context, it already is
if (skipAssigned && slen <= 2) {
return this;
return current;
}
// optimization: if there is a single stack domain and that domain
// is already in the assigned context; no need to combine
if ((slen == 1) && (context[0] == acc.context[0])) {
return acc;
}
int n = (skipAssigned) ? 0 : acc.context.length;
int n = (skipAssigned) ? 0 : assigned.length;
// now we combine both of them, and create a new context
ProtectionDomain pd[] = new ProtectionDomain[slen + n];
// first copy in the assigned context domains, no need to compress
if (!skipAssigned) {
System.arraycopy(acc.context, 0, pd, 0, n);
System.arraycopy(assigned, 0, pd, 0, n);
}
// now add the stack context domains, discarding nulls and duplicates
outer:
for (int i = 0; i < context.length; i++) {
ProtectionDomain sd = context[i];
for (int i = 0; i < slen; i++) {
ProtectionDomain sd = current[i];
if (sd != null) {
for (int j = 0; j < n; j++) {
if (sd == pd[j]) {
......@@ -453,54 +669,48 @@ public final class AccessControlContext {
// if length isn't equal, we need to shorten the array
if (n != pd.length) {
// optimization: if we didn't really combine anything
if (!skipAssigned && n == acc.context.length) {
return acc;
if (!skipAssigned && n == assigned.length) {
return assigned;
} else if (skipAssigned && n == slen) {
return this;
return current;
}
ProtectionDomain tmp[] = new ProtectionDomain[n];
System.arraycopy(pd, 0, tmp, 0, n);
pd = tmp;
}
// return new AccessControlContext(pd, false);
// Reuse existing ACC
this.context = pd;
this.combiner = null;
this.isPrivileged = false;
return this;
return pd;
}
private AccessControlContext goCombiner(ProtectionDomain[] current,
AccessControlContext assigned) {
// the assigned ACC's combiner is not null --
// let the combiner do its thing
// XXX we could add optimizations to 'current' here ...
if (getDebug() != null) {
debug.println("AccessControlContext invoking the Combiner");
/*
* Calculate the additional domains that could potentially be reached via
* limited privilege scope. Mark the context as being subject to limited
* privilege scope unless the reachable domains (if any) are already
* contained in this domain context (in which case any limited
* privilege scope checking would be redundant).
*/
private void calculateFields(AccessControlContext assigned,
AccessControlContext parent, Permission[] permissions)
{
ProtectionDomain[] parentLimit = null;
ProtectionDomain[] assignedLimit = null;
ProtectionDomain[] newLimit;
parentLimit = (parent != null)? parent.limitedContext: null;
assignedLimit = (assigned != null)? assigned.limitedContext: null;
newLimit = combine(parentLimit, assignedLimit);
if (newLimit != null) {
if (context == null || !containsAllPDs(newLimit, context)) {
this.limitedContext = newLimit;
this.permissions = permissions;
this.parent = parent;
this.isLimited = true;
}
}
// No need to clone current and assigned.context
// combine() will not update them
ProtectionDomain[] combinedPds = assigned.combiner.combine(
current, assigned.context);
// return new AccessControlContext(combinedPds, assigned.combiner);
// Reuse existing ACC
this.context = combinedPds;
this.combiner = assigned.combiner;
this.isPrivileged = false;
return this;
}
/**
* Checks two AccessControlContext objects for equality.
* Checks that <i>obj</i> is
......@@ -520,31 +730,131 @@ public final class AccessControlContext {
AccessControlContext that = (AccessControlContext) obj;
if (!equalContext(that))
return false;
if (!equalLimitedContext(that))
return false;
if (context == null) {
return (that.context == null);
return true;
}
/*
* Compare for equality based on state that is free of limited
* privilege complications.
*/
private boolean equalContext(AccessControlContext that) {
if (!equalPDs(this.context, that.context))
return false;
if (this.combiner == null && that.combiner != null)
return false;
if (this.combiner != null && !this.combiner.equals(that.combiner))
return false;
return true;
}
private boolean equalPDs(ProtectionDomain[] a, ProtectionDomain[] b) {
if (a == null) {
return (b == null);
}
if (b == null)
return false;
if (!(containsAllPDs(a, b) && containsAllPDs(b, a)))
return false;
return true;
}
/*
* Compare for equality based on state that is captured during a
* call to AccessController.getContext() when a limited privilege
* scope is in effect.
*/
private boolean equalLimitedContext(AccessControlContext that) {
if (that == null)
return false;
/*
* If neither instance has limited privilege scope then we're done.
*/
if (!this.isLimited && !that.isLimited)
return true;
/*
* If only one instance has limited privilege scope then we're done.
*/
if (!(this.isLimited && that.isLimited))
return false;
/*
* Wrapped instances should never escape outside the implementation
* this class and AccessController so this will probably never happen
* but it only makes any sense to compare if they both have the same
* isWrapped state.
*/
if ((this.isWrapped && !that.isWrapped) ||
(!this.isWrapped && that.isWrapped)) {
return false;
}
if (that.context == null)
if (this.permissions == null && that.permissions != null)
return false;
if (!(this.containsAllPDs(that) && that.containsAllPDs(this)))
if (this.permissions != null && that.permissions == null)
return false;
if (!(this.containsAllLimits(that) && that.containsAllLimits(this)))
return false;
/*
* Skip through any wrapped contexts.
*/
AccessControlContext thisNextPC = getNextPC(this);
AccessControlContext thatNextPC = getNextPC(that);
/*
* The protection domains and combiner of a privilegedContext are
* not relevant because they have already been included in the context
* of this instance by optimize() so we only care about any limited
* privilege state they may have.
*/
if (thisNextPC == null && thatNextPC != null && thatNextPC.isLimited)
return false;
if (this.combiner == null)
return (that.combiner == null);
if (thisNextPC != null && !thisNextPC.equalLimitedContext(thatNextPC))
return false;
if (that.combiner == null)
if (this.parent == null && that.parent != null)
return false;
if (!this.combiner.equals(that.combiner))
if (this.parent != null && !this.parent.equals(that.parent))
return false;
return true;
}
private boolean containsAllPDs(AccessControlContext that) {
/*
* Follow the privilegedContext link making our best effort to skip
* through any wrapper contexts.
*/
private static AccessControlContext getNextPC(AccessControlContext acc) {
while (acc != null && acc.privilegedContext != null) {
acc = acc.privilegedContext;
if (!acc.isWrapped)
return acc;
}
return null;
}
private static boolean containsAllPDs(ProtectionDomain[] thisContext,
ProtectionDomain[] thatContext) {
boolean match = false;
//
// ProtectionDomains within an ACC currently cannot be null
// and this is enforced by the constructor and the various
......@@ -552,17 +862,17 @@ public final class AccessControlContext {
// to support the notion of a null PD and therefore this logic continues
// to support that notion.
ProtectionDomain thisPd;
for (int i = 0; i < context.length; i++) {
for (int i = 0; i < thisContext.length; i++) {
match = false;
if ((thisPd = context[i]) == null) {
for (int j = 0; (j < that.context.length) && !match; j++) {
match = (that.context[j] == null);
if ((thisPd = thisContext[i]) == null) {
for (int j = 0; (j < thatContext.length) && !match; j++) {
match = (thatContext[j] == null);
}
} else {
Class<?> thisPdClass = thisPd.getClass();
ProtectionDomain thatPd;
for (int j = 0; (j < that.context.length) && !match; j++) {
thatPd = that.context[j];
for (int j = 0; (j < thatContext.length) && !match; j++) {
thatPd = thatContext[j];
// Class check required to avoid PD exposure (4285406)
match = (thatPd != null &&
......@@ -573,6 +883,29 @@ public final class AccessControlContext {
}
return match;
}
private boolean containsAllLimits(AccessControlContext that) {
boolean match = false;
Permission thisPerm;
if (this.permissions == null && that.permissions == null)
return true;
for (int i = 0; i < this.permissions.length; i++) {
Permission limit = this.permissions[i];
Class <?> limitClass = limit.getClass();
match = false;
for (int j = 0; (j < that.permissions.length) && !match; j++) {
Permission perm = that.permissions[j];
match = (limitClass.equals(perm.getClass()) &&
limit.equals(perm));
}
if (!match) return false;
}
return match;
}
/**
* Returns the hash code value for this context. The hash code
* is computed by exclusive or-ing the hash code of all the protection
......@@ -591,6 +924,7 @@ public final class AccessControlContext {
if (context[i] != null)
hashCode ^= context[i].hashCode();
}
return hashCode;
}
}
......@@ -82,9 +82,15 @@ import sun.reflect.Reflection;
* else if (caller i is marked as privileged) {
* if (a context was specified in the call to doPrivileged)
* context.checkPermission(permission)
* return;
* if (limited permissions were specified in the call to doPrivileged) {
* for (each limited permission) {
* if (the limited permission implies the requested permission)
* return;
* }
* } else
* return;
* }
* };
* }
*
* // Next, check the context inherited when the thread was created.
* // Whenever a new thread is created, the AccessControlContext at
......@@ -101,11 +107,16 @@ import sun.reflect.Reflection;
* was marked as "privileged" via a <code>doPrivileged</code>
* call without a context argument (see below for information about a
* context argument). If that caller's domain has the
* specified permission, no further checking is done and
* specified permission and at least one limiting permission argument (if any)
* implies the requested permission, no further checking is done and
* <code>checkPermission</code>
* returns quietly, indicating that the requested access is allowed.
* If that domain does not have the specified permission, an exception
* is thrown, as usual.
* is thrown, as usual. If the caller's domain had the specified permission
* but it was not implied by any limiting permission arguments given in the call
* to <code>doPrivileged</code> then the permission checking continues
* until there are no more callers or another <code>doPrivileged</code>
* call matches the requested permission and returns normally.
*
* <p> The normal use of the "privileged" feature is as follows. If you
* don't need to return a value from within the "privileged" block, do
......@@ -180,6 +191,9 @@ import sun.reflect.Reflection;
*
* <p> Be *very* careful in your use of the "privileged" construct, and
* always remember to make the privileged code section as small as possible.
* You can pass <code>Permission</code> arguments to further limit the
* scope of the "privilege" (see below).
*
*
* <p> Note that <code>checkPermission</code> always performs security checks
* within the context of the currently executing thread.
......@@ -215,7 +229,9 @@ import sun.reflect.Reflection;
*
* <p> There are also times where you don't know a priori which permissions
* to check the context against. In these cases you can use the
* doPrivileged method that takes a context:
* doPrivileged method that takes a context. You can also limit the scope
* of the privileged code by passing additional <code>Permission</code>
* parameters.
*
* <pre> {@code
* somemethod() {
......@@ -223,12 +239,21 @@ import sun.reflect.Reflection;
* public Object run() {
* // Code goes here. Any permission checks within this
* // run method will require that the intersection of the
* // callers protection domain and the snapshot's
* // context have the desired permission.
* // caller's protection domain and the snapshot's
* // context have the desired permission. If a requested
* // permission is not implied by the limiting FilePermission
* // argument then checking of the thread continues beyond the
* // caller of doPrivileged.
* }
* }, acc);
* }, acc, new FilePermission("/temp/*", read));
* ...normal code here...
* }}</pre>
* <p> Passing a limiting <code>Permission</code> argument of an instance of
* <code>AllPermission</code> is equivalent to calling the equivalent
* <code>doPrivileged</code> method without limiting <code>Permission</code>
* arguments. Passing a zero length array of <code>Permission</code> disables
* the code privileges so that checking always continues beyond the caller of
* that <code>doPrivileged</code> method.
*
* @see AccessControlContext
*
......@@ -334,6 +359,112 @@ public final class AccessController {
public static native <T> T doPrivileged(PrivilegedAction<T> action,
AccessControlContext context);
/**
* Performs the specified <code>PrivilegedAction</code> with privileges
* enabled and restricted by the specified
* <code>AccessControlContext</code> and with a privilege scope limited
* by specified <code>Permission</code> arguments.
*
* The action is performed with the intersection of the permissions
* possessed by the caller's protection domain, and those possessed
* by the domains represented by the specified
* <code>AccessControlContext</code>.
* <p>
* If the action's <code>run</code> method throws an (unchecked) exception,
* it will propagate through this method.
*
* @param action the action to be performed.
* @param context an <i>access control context</i>
* representing the restriction to be applied to the
* caller's domain's privileges before performing
* the specified action. If the context is
* <code>null</code>,
* then no additional restriction is applied.
* @param perms the <code>Permission</code> arguments which limit the
* scope of the caller's privileges. The number of arguments
* is variable.
*
* @return the value returned by the action's <code>run</code> method.
*
* @throws NullPointerException if action or perms or any element of
* perms is <code>null</code>
*
* @see #doPrivileged(PrivilegedAction)
* @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext)
*
* @since 1.8
*/
@CallerSensitive
public static <T> T doPrivileged(PrivilegedAction<T> action,
AccessControlContext context, Permission... perms) {
AccessControlContext parent = getContext();
if (perms == null) {
throw new NullPointerException("null permissions parameter");
}
Class <?> caller = Reflection.getCallerClass();
return AccessController.doPrivileged(action, createWrapper(null,
caller, parent, context, perms));
}
/**
* Performs the specified <code>PrivilegedAction</code> with privileges
* enabled and restricted by the specified
* <code>AccessControlContext</code> and with a privilege scope limited
* by specified <code>Permission</code> arguments.
*
* The action is performed with the intersection of the permissions
* possessed by the caller's protection domain, and those possessed
* by the domains represented by the specified
* <code>AccessControlContext</code>.
* <p>
* If the action's <code>run</code> method throws an (unchecked) exception,
* it will propagate through this method.
*
* <p> This method preserves the current AccessControlContext's
* DomainCombiner (which may be null) while the action is performed.
*
* @param action the action to be performed.
* @param context an <i>access control context</i>
* representing the restriction to be applied to the
* caller's domain's privileges before performing
* the specified action. If the context is
* <code>null</code>,
* then no additional restriction is applied.
* @param perms the <code>Permission</code> arguments which limit the
* scope of the caller's privileges. The number of arguments
* is variable.
*
* @return the value returned by the action's <code>run</code> method.
*
* @throws NullPointerException if action or perms or any element of
* perms is <code>null</code>
*
* @see #doPrivileged(PrivilegedAction)
* @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext)
* @see java.security.DomainCombiner
*
* @since 1.8
*/
@CallerSensitive
public static <T> T doPrivilegedWithCombiner(PrivilegedAction<T> action,
AccessControlContext context, Permission... perms) {
AccessControlContext parent = getContext();
DomainCombiner dc = parent.getCombiner();
if (dc == null && context != null) {
dc = context.getCombiner();
}
if (perms == null) {
throw new NullPointerException("null permissions parameter");
}
Class <?> caller = Reflection.getCallerClass();
return AccessController.doPrivileged(action, createWrapper(dc, caller,
parent, context, perms));
}
/**
* Performs the specified <code>PrivilegedExceptionAction</code> with
* privileges enabled. The action is performed with <i>all</i> of the
......@@ -408,6 +539,22 @@ public final class AccessController {
private static AccessControlContext preserveCombiner(DomainCombiner combiner,
Class<?> caller)
{
return createWrapper(combiner, caller, null, null, null);
}
/**
* Create a wrapper to contain the limited privilege scope data.
*/
private static AccessControlContext
createWrapper(DomainCombiner combiner, Class<?> caller,
AccessControlContext parent, AccessControlContext context,
Permission[] perms)
{
return new AccessControlContext(getCallerPD(caller), combiner, parent,
context, perms);
}
private static ProtectionDomain getCallerPD(final Class <?> caller) {
ProtectionDomain callerPd = doPrivileged
(new PrivilegedAction<ProtectionDomain>() {
public ProtectionDomain run() {
......@@ -415,18 +562,9 @@ public final class AccessController {
}
});
// perform 'combine' on the caller of doPrivileged,
// even if the caller is from the bootclasspath
ProtectionDomain[] pds = new ProtectionDomain[] {callerPd};
if (combiner == null) {
return new AccessControlContext(pds);
} else {
return new AccessControlContext(combiner.combine(pds, null),
combiner);
}
return callerPd;
}
/**
* Performs the specified <code>PrivilegedExceptionAction</code> with
* privileges enabled and restricted by the specified
......@@ -454,7 +592,7 @@ public final class AccessController {
* @exception NullPointerException if the action is <code>null</code>
*
* @see #doPrivileged(PrivilegedAction)
* @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext)
* @see #doPrivileged(PrivilegedAction,AccessControlContext)
*/
@CallerSensitive
public static native <T> T
......@@ -462,6 +600,118 @@ public final class AccessController {
AccessControlContext context)
throws PrivilegedActionException;
/**
* Performs the specified <code>PrivilegedExceptionAction</code> with
* privileges enabled and restricted by the specified
* <code>AccessControlContext</code> and with a privilege scope limited by
* specified <code>Permission</code> arguments.
*
* The action is performed with the intersection of the permissions
* possessed by the caller's protection domain, and those possessed
* by the domains represented by the specified
* <code>AccessControlContext</code>.
* <p>
* If the action's <code>run</code> method throws an (unchecked) exception,
* it will propagate through this method.
*
* @param action the action to be performed.
* @param context an <i>access control context</i>
* representing the restriction to be applied to the
* caller's domain's privileges before performing
* the specified action. If the context is
* <code>null</code>,
* then no additional restriction is applied.
* @param perms the <code>Permission</code> arguments which limit the
* scope of the caller's privileges. The number of arguments
* is variable.
*
* @return the value returned by the action's <code>run</code> method.
*
* @throws PrivilegedActionException if the specified action's
* <code>run</code> method threw a <i>checked</i> exception
* @throws NullPointerException if action or perms or any element of
* perms is <code>null</code>
*
* @see #doPrivileged(PrivilegedAction)
* @see #doPrivileged(PrivilegedAction,AccessControlContext)
*
* @since 1.8
*/
@CallerSensitive
public static <T> T doPrivileged(PrivilegedExceptionAction<T> action,
AccessControlContext context, Permission... perms)
throws PrivilegedActionException
{
AccessControlContext parent = getContext();
if (perms == null) {
throw new NullPointerException("null permissions parameter");
}
Class <?> caller = Reflection.getCallerClass();
return AccessController.doPrivileged(action, createWrapper(null, caller, parent, context, perms));
}
/**
* Performs the specified <code>PrivilegedExceptionAction</code> with
* privileges enabled and restricted by the specified
* <code>AccessControlContext</code> and with a privilege scope limited by
* specified <code>Permission</code> arguments.
*
* The action is performed with the intersection of the permissions
* possessed by the caller's protection domain, and those possessed
* by the domains represented by the specified
* <code>AccessControlContext</code>.
* <p>
* If the action's <code>run</code> method throws an (unchecked) exception,
* it will propagate through this method.
*
* <p> This method preserves the current AccessControlContext's
* DomainCombiner (which may be null) while the action is performed.
*
* @param action the action to be performed.
* @param context an <i>access control context</i>
* representing the restriction to be applied to the
* caller's domain's privileges before performing
* the specified action. If the context is
* <code>null</code>,
* then no additional restriction is applied.
* @param perms the <code>Permission</code> arguments which limit the
* scope of the caller's privileges. The number of arguments
* is variable.
*
* @return the value returned by the action's <code>run</code> method.
*
* @throws PrivilegedActionException if the specified action's
* <code>run</code> method threw a <i>checked</i> exception
* @throws NullPointerException if action or perms or any element of
* perms is <code>null</code>
*
* @see #doPrivileged(PrivilegedAction)
* @see #doPrivileged(PrivilegedAction,AccessControlContext)
* @see java.security.DomainCombiner
*
* @since 1.8
*/
@CallerSensitive
public static <T> T doPrivilegedWithCombiner(PrivilegedExceptionAction<T> action,
AccessControlContext context,
Permission... perms)
throws PrivilegedActionException
{
AccessControlContext parent = getContext();
DomainCombiner dc = parent.getCombiner();
if (dc == null && context != null) {
dc = context.getCombiner();
}
if (perms == null) {
throw new NullPointerException("null permissions parameter");
}
Class <?> caller = Reflection.getCallerClass();
return AccessController.doPrivileged(action, createWrapper(dc, caller,
parent, context, perms));
}
/**
* Returns the AccessControl context. i.e., it gets
* the protection domains of all the callers on the stack,
......@@ -474,6 +724,7 @@ public final class AccessController {
private static native AccessControlContext getStackAccessControlContext();
/**
* Returns the "inherited" AccessControl context. This is the context
* that existed when the thread was created. Package private so
......@@ -484,9 +735,9 @@ public final class AccessController {
/**
* This method takes a "snapshot" of the current calling context, which
* includes the current Thread's inherited AccessControlContext,
* and places it in an AccessControlContext object. This context may then
* be checked at a later point, possibly in another thread.
* includes the current Thread's inherited AccessControlContext and any
* limited privilege scope, and places it in an AccessControlContext object.
* This context may then be checked at a later point, possibly in another thread.
*
* @see AccessControlContext
*
......@@ -524,7 +775,7 @@ public final class AccessController {
*/
public static void checkPermission(Permission perm)
throws AccessControlException
throws AccessControlException
{
//System.err.println("checkPermission "+perm);
//Thread.currentThread().dumpStack();
......
/*
* Copyright (c) 2013, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8014097
* @summary Test the limited privilege scope version of doPrivileged
*/
import java.security.*;
import java.util.*;
public class LimitedDoPrivileged {
/*
* Test variations of doPrivileged() and doPrivileged() with a limited privilege scope
* in a sandbox with the usual default permission to read the system properties for the
* file and path separators.
*
* By passing in an "assigned" AccessControlContext that has
* no default permissions we can test how code privileges are being scoped.
*/
private static final ProtectionDomain domain =
new ProtectionDomain(null, null, null, null);
private static final AccessControlContext acc =
new AccessControlContext(new ProtectionDomain[] { domain });
private static final PropertyPermission pathPerm =
new PropertyPermission("path.separator", "read");
private static final PropertyPermission filePerm =
new PropertyPermission("file.separator", "read");
public static void main(String[] args) throws Exception {
/*
* Verify that we have the usual default property read permission.
*/
AccessController.getContext().checkPermission(filePerm);
AccessController.getContext().checkPermission(pathPerm);
System.out.println("test 1 passed");
/*
* Inject the "no permission" AccessControlContext.
*/
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
/*
* Verify that we no longer have the "file.separator" permission.
*/
try {
AccessController.getContext().checkPermission(pathPerm);
} catch (AccessControlException ace) {
System.out.println("test 2 passed");
}
/*
* Verify that we can give ourselves limited privilege to read
* any system property starting with "path.".
*/
AccessController.doPrivileged
(new PrivilegedAction() {
public Object run() {
AccessController.getContext().checkPermission(pathPerm);
return null;
}
}, null, new PropertyPermission("path.*", "read"));
System.out.println("test 3 passed");
/*
* Verify that if we give ourselves limited privilege to read
* any system property starting with "path." it won't give us the
* the ability to read "file.separator".
*/
try {
AccessController.doPrivileged
(new PrivilegedAction() {
public Object run() {
AccessController.getContext().checkPermission(filePerm);
return null;
}
}, null, new PropertyPermission("path.*", "read"));
} catch (AccessControlException ace) {
System.out.println("test 4 passed");
}
/*
* Verify that capturing and passing in the context with no default
* system property permission grants will prevent access that succeeded
* earlier without the context assignment.
*/
final AccessControlContext context = AccessController.getContext();
try {
AccessController.doPrivileged
(new PrivilegedAction() {
public Object run() {
AccessController.getContext().checkPermission(pathPerm);
return null;
}
}, context, new PropertyPermission("path.*", "read"));
} catch (AccessControlException ace) {
System.out.println("test 5 passed");
}
/*
* Verify that we can give ourselves full privilege to read
* any system property starting with "path.".
*/
AccessController.doPrivileged
(new PrivilegedAction() {
public Object run() {
AccessController.getContext().checkPermission(pathPerm);
return null;
}
});
System.out.println("test 6 passed");
/*
* Verify that capturing and passing in the context with no default
* system property permission grants will prevent access that succeeded
* earlier without the context assignment.
*/
try {
AccessController.doPrivileged
(new PrivilegedAction() {
public Object run() {
AccessController.getContext().checkPermission(pathPerm);
return null;
}
}, context);
} catch (AccessControlException ace) {
System.out.println("test 7 passed");
}
/*
* Verify that we can give ourselves limited privilege to read
* any system property starting with "path." when a limited
* privilege scope context is captured and passed to a regular
* doPrivileged() as an assigned context.
*/
AccessController.doPrivileged
(new PrivilegedAction() {
public Object run() {
/*
* Capture the limited privilege scope and inject it into the
* regular doPrivileged().
*/
final AccessControlContext limitedContext = AccessController.getContext();
AccessController.doPrivileged
(new PrivilegedAction() {
public Object run() {
AccessController.getContext().checkPermission(pathPerm);
return null;
}
}, limitedContext);
return null;
}
}, null, new PropertyPermission("path.*", "read"));
System.out.println("test 8 passed");
/*
* Verify that we can give ourselves limited privilege to read
* any system property starting with "path." it won't give us the
* the ability to read "file.separator" when a limited
* privilege scope context is captured and passed to a regular
* doPrivileged() as an assigned context.
*/
AccessController.doPrivileged
(new PrivilegedAction() {
public Object run() {
/*
* Capture the limited privilege scope and inject it into the
* regular doPrivileged().
*/
final AccessControlContext limitedContext = AccessController.getContext();
try {
AccessController.doPrivileged
(new PrivilegedAction() {
public Object run() {
AccessController.getContext().checkPermission(filePerm);
return null;
}
}, limitedContext);
} catch (AccessControlException ace) {
System.out.println("test 9 passed");
}
return null;
}
}, null, new PropertyPermission("path.*", "read"));
return null;
}
}, acc);
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册