Question

I am trying to prohibit thread creation in an AccessController.doPriviliged() method. The method below creates and runs the thread. I run this with -Djava.security.manager. According to this link, if modifyThreadGroup is not granted, then Thread creation should be disallowed?

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

Can anyone enlighten me as to why this is happening and the correct way to disallow Thread creation using 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);
    }
  }
}
Was it helpful?

Solution

The only check done when a thread is created or started is to check and see if the calling thread has permission to modify the thread group. This does not, as you might think, check to see if the calling thread has the permission "modifyThreadGroup".

Instead what it does (by default) is to always grant access unless the ThreadGroup in question is the system thread group in which case the "modifyThreadGroup" permission is checked. The ThreadGroup in question is almost never the system thread group.

You will have to extend SecurityManager with your own implementation and do some kind of check of your own. You should probably make up your own new permission. As an example I implemented a hack using an existing permission I knew threads would have (exitVM) given the default policy:

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();
    }

}

OTHER TIPS

After accepting the response of Pace, I found something that others may find useful. From the doc you linked: "Applications that want a stricter policy should override this method. If this method is overridden, the method that overrides it should additionally check to see if the calling thread has the RuntimePermission("modifyThreadGroup") permission, and if so, return silently. This is to ensure that code granted that permission (such as the JDK itself) is allowed to manipulate any thread." I found that checking for 'modifyThread' and 'modifyThreadGroup' in the relative methods (where you checked for 'exitVM') gave the desired behavior.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top