AccessController doPrivileged 可以在 modifyThreadGroup 未授予时创建线程吗?

Posted

技术标签:

【中文标题】AccessController doPrivileged 可以在 modifyThreadGroup 未授予时创建线程吗?【英文标题】:AccessController doPrivileged can create thread when modifyThreadGroup not granted? 【发布时间】:2013-07-08 17:17:29 【问题描述】:

我试图禁止在 AccessController.doPriviliged() 方法中创建线程。下面的方法创建并运行线程。我用-Djava.security.manager 运行它。根据这个链接,如果 modifyThreadGroup 没有被授予,那么线程创建应该被禁止?

http://docs.oracle.com/javase/7/docs/technotes/guides/security/permissions.html

谁能告诉我为什么会发生这种情况以及禁止使用 AccessController 创建线程的正确方法?

// .java.policy in $UserHome:

grant codeBase "file:/C:/-" 
    permission java.security.AllPermission;
;


public class ThreadTest 
  public void testModifyThreadGroup() 

    // grant no permissions
    Permissions perms = new Permissions();

    ProtectionDomain domain = new ProtectionDomain(
            new CodeSource( null, (Certificate[]) null ), perms );
    AccessControlContext _accessControlContext = new AccessControlContext(
            new ProtectionDomain[]  domain  );

    try 
        AccessController.doPrivileged(new PrivilegedExceptionAction()
            @Override
            public Object run() 
                try 
                    // modifyThreadGroup not granted, so should not be able
                    // to call Thread constructor???
                    Thread t = new Thread(new Runnable() 
                        @Override
                        public void run() 
                            System.out.println("Thread.run()");
                        
                    );
                    t.run();
                 catch (Exception ex) 
                    System.out.println("Error running thread: " + ex);
                
                return null;
        , _accessControlContext);
     catch(Exception e) 
        System.out.println("Access Error running doPrivileged: " + e);
    
  

【问题讨论】:

【参考方案1】:

创建或启动线程时所做的唯一检查是检查调用线程是否有权修改线程组。这并不像您想象的那样检查调用线程是否具有“modifyThreadGroup”权限。

相反,它的作用 (by default) 始终授予访问权限,除非所讨论的 ThreadGroup 是系统线程组,在这种情况下会检查“modifyThreadGroup”权限。有问题的 ThreadGroup 几乎从来都不是系统线程组。

您必须使用自己的实现来扩展 SecurityManager 并自己进行某种检查。您可能应该制定自己的新权限。作为一个例子,我使用现有的权限实现了一个 hack,我知道在给定默认策略的情况下线程将拥有(exitVM):

import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.CodeSource;
import java.security.Permissions;
import java.security.PrivilegedExceptionAction;
import java.security.ProtectionDomain;
import java.security.cert.Certificate;

public class QuickTest 

    public static class NoThreadsSecurityManager extends SecurityManager 

        public void checkAccess(ThreadGroup g) 
            super.checkAccess(g);
            checkPermission(new RuntimePermission("exitVM"));
        

    

    public static class SimpleRunnable implements PrivilegedExceptionAction<Object> 
        @Override
        public Object run() 
            try 
                Thread t = new Thread(new Runnable() 
                    @Override
                    public void run() 
                        System.out.println("Thread.run()");
                    
                );
                t.start();
                t.join();
             catch (Exception ex) 
                System.out.println("Error running thread: " + ex);
            
            return null;
        
    

    public void testModifyThreadGroup() 

        // grant no permissions
        Permissions perms = new Permissions();

        ProtectionDomain domain = new ProtectionDomain(new CodeSource(null, (Certificate[]) null), perms);
        AccessControlContext _accessControlContext = new AccessControlContext(new ProtectionDomain[]  domain );

        try 
            AccessController.doPrivileged(new SimpleRunnable(), _accessControlContext);
         catch (Exception e) 
            System.out.println("Access Error running doPrivileged: " + e);
        

        new SimpleRunnable().run();

    

    public static void main(String[] args) 
        System.setSecurityManager(new NoThreadsSecurityManager());
        new QuickTest().testModifyThreadGroup();
    


【讨论】:

谢谢!从您链接的文档中:“需要更严格策略的应用程序应覆盖此方法。如果此方法被覆盖,则覆盖它的方法应另外检查调用线程是否具有 RuntimePermission("modifyThreadGroup") 权限,如果所以,静默返回。这是为了确保授予该权限的代码(例如 JDK 本身)被允许操作任何线程。我发现在相关方法中检查“modifyThread”和“modifyThreadGroup”(您检查“exitVM”的地方)给出了所需的行为。【参考方案2】:

在接受 Pace 的回复后,我发现了一些其他人可能会觉得有用的东西。从您链接的文档中:“需要更严格策略的应用程序应覆盖此方法。如果此方法被覆盖,则覆盖它的方法应另外检查调用线程是否具有 RuntimePermission("modifyThreadGroup") 权限,如果所以,静默返回。这是为了确保授予该权限的代码(例如 JDK 本身)被允许操作任何线程。我发现在相关方法中检查 'modifyThread' 和 'modifyThreadGroup' (您在其中检查了 'exitVM')给出了所需的行为。

【讨论】:

以上是关于AccessController doPrivileged 可以在 modifyThreadGroup 未授予时创建线程吗?的主要内容,如果未能解决你的问题,请参考以下文章

访问控制器使用

在 Laravel 中从同一网页发布两个表单

java之jvm学习笔记六(实践写自己的安全管理器)

HastTable源码分析

hbase笔记

NoClassDefFoundError