Java 为什么我可以使用AccessController.doPrivileged脱离受限的AccessControlContext?

Java 为什么我可以使用AccessController.doPrivileged脱离受限的AccessControlContext?,java,security,access-control,Java,Security,Access Control,我正在研究如何在没有权限的情况下运行外部代码(来自不同的JAR),这样它就不会损害我自己的系统。我让它几乎可以工作,但是我发现一个奇怪的情况,调用System.exit(0)仍然会杀死整个系统 其想法是在多线程环境中加载不同的JAR,因此在服务器上的许多其他安全风险中,System.exit(0)成功大概是最糟糕的 我有以下代码(在SSCEE中): 我的想法是,我自己的代码仍然具有完全权限,但沙盒代码限制了(在本例中为:无)权限 但是,在给定的示例中,它只是存在,请注意,main方法的以下变体确

我正在研究如何在没有权限的情况下运行外部代码(来自不同的JAR),这样它就不会损害我自己的系统。我让它几乎可以工作,但是我发现一个奇怪的情况,调用
System.exit(0)
仍然会杀死整个系统

其想法是在多线程环境中加载不同的JAR,因此在服务器上的许多其他安全风险中,
System.exit(0)
成功大概是最糟糕的

我有以下代码(在SSCEE中):

我的想法是,我自己的代码仍然具有完全权限,但沙盒代码限制了(在本例中为:无)权限

但是,在给定的示例中,它只是存在,请注意,main方法的以下变体确实有效:

我在这里做错了什么,为什么可以执行一个提升权限的
AccessController.doPrivileged
调用,而这些权限以前是受限制的?我希望以下情况之一是正确的:

  • 调用
    AccessController.doPrivileged
    可能会有一个特定的权限
  • AccessController.doPrivileged
    块中,权限将是“父级”
    AccessControlContext
    和给定权限的交集

  • 这两个选项都会导致给定的代码正确地抛出一个
    AccessControlException
    ,但它不会发生,为什么会出现这种情况?

    您没有任何沙盒代码。您拥有完全权限的代码正在使用它们。没有相关权限的代码将无法退出。解决方案应该是使用不受信任的
    ProtectionDomain
    加载不受信任的代码

    拥有提升权限的权限是毫无意义的。这相当于拥有所有权限


    在OpenJDK内部,有一个
    doPrivileged
    的变体,它允许权限的交叉,但是当存在多个不信任源时,它可以降低权限。

    我已经多年没有研究过这个了,但是,IIRC,有一个可以“安装”的安全控制器在JVM中验证
    doPrivileged
    调用等。如果您没有安装自己的控制器,则此控制器的默认操作是在请求通过时挥手微笑。@Hotlick通常通过
    SecurityManager
    进行权限检查,然后将其转发到
    AccessController
    AccessController.doPrivileged
    无法将权限提升到调用类的权限之上。(处理
    DomainCombiner
    Subject
    有单独的规则)
    public class RestrictAccessControlContext {
        private static final PermissionCollection ALLOWED_PERMISSIONS = new Permissions();
        static {
            //add permissions
        }
        private static final AccessControlContext RESTRICTED_ACCESS_CONTROL_CONTEXT = 
            new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, ALLOWED_PERMISSIONS)});
    
        private static void executeSandboxed(final Runnable runnable) {
            ExecutorService executorService = Executors.newSingleThreadExecutor();
            Future<?> future = executorService.submit(() -> {
                AccessController.doPrivileged((PrivilegedAction<Void>)() -> {
                    runnable.run();
                    return null;
                }, RESTRICTED_ACCESS_CONTROL_CONTEXT);
            });
            try {
                future.get();
            } catch (InterruptedException ex) {
                Thread.currentThread().interrupt();
            } catch (ExecutionException ex) {
                throw new RuntimeException(ex.getCause());
            } finally {
                executorService.shutdown();
            }
        }
    
        public static void main(String[] args) {
            executeSandboxed(() -> {
                AccessController.doPrivileged((PrivilegedAction<Void>)() -> {
                    System.exit(0);
                    return null;
                });
            });
        }
    }
    
    grant {
        permission java.security.AllPermission;
    };
    
    public static void main(String[] args) {
        executeSandboxed(() -> System.exit(0));
    }
    
    public static void main(String[] args) {
        executeSandboxed(() -> new Thread(() -> System.exit(0)).start());
    }