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

8014097: add doPrivileged methods with limited privilege scope

Reviewed-by: mchung
上级 f45551af
......@@ -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.
先完成此消息的编辑!
想要评论请 注册