JDK-7068741 : Security manager uses wrong ThreadGroup when it checks applet permissions in 1.7
  • Type: Bug
  • Component: deploy
  • Sub-Component: plugin
  • Affected Version: 7
  • Priority: P2
  • Status: Resolved
  • Resolution: Fixed
  • OS: windows_xp,windows_7
  • CPU: x86
  • Submitted: 2011-07-20
  • Updated: 2013-11-01
  • Resolved: 2011-08-17
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 7 JDK 8
7u1Resolved 8Fixed
Related Reports
Duplicate :  
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.7.0"
Java(TM) SE Runtime Environment (build 1.7.0-b147)
Java HotSpot(TM) Client VM (build 21.0-b17, mixed mode, sharing)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows XP [Version 5.1.2600]

A DESCRIPTION OF THE PROBLEM :
Changes in the applet security classes made the code which worked in all previous version of JRE broken. See the code below and exception.

Detailed description:
When applet creates new Thread and the group is null, it asks a current security manager (System.getSecurityManager()) what to do:
[1.6.0_26-b03] [Applet2SecurityManager]: sun.plugin2.applet.Applet2ThreadGroup
[1.7.0-b147] [AWTAppletSecurityManager]: sun.plugin2.applet.Applet2ThreadGroup

So they both return comparable values and method ThreadGroup#checkAccess is called.
Then they do almost the same things until following point is reached:
[1.6.0_26-b03] [Applet2SecurityManager]:
protected boolean inThreadGroup(ThreadGroup g) {
    if (currentAppletClassLoader() == null)
        return false;
    else
        return getThreadGroup().parentOf(g);
}

[1.7.0-b147] [SecurityManagerHelper]:
static boolean inThreadGroup(SecurityManager securitymanager, ThreadGroup threadgroup, ClassLoader classloader, Class aclass[], Field field, Field field1) {
    if (currentAppletClassLoader(classloader, aclass, field, field1) == null) {
        return false;
    } else {
        return securitymanager.getThreadGroup().parentOf(threadgroup);
    }
}

In both situations methods currentAppletClassLoader return not null value.
The difference there is that Applet2SecurityManager calls own method getThreadGroup(), and we get the same group which we got at the beginning in the Thread constructor (System.getSecurityManager().getThreadGroup()), method parentOf returns true, and creation of new thread is allowed.

Instead of this SecurityManagerHelper calls method getThreadGroup() of passed parameter, and this param is not current security manager(System.getSecurityManager()), it���s value of field AWTAppletSecurityManager - awtSM and it���s instance of class AWTSecurityManager.
AWTSecurityManager uses default behavior of SecurityManager#getThreadGroup and returns the thread group of the current thread.
Any custom created thread group in applet can���t be parent for System.getSecurityManager().getThreadGroup() - Applet2ThreadGroup.

And an applet has no permission to modify thread group ("java.lang.RuntimePermission" "modifyThreadGroup") by default. So the check fails and exception is thrown, new thread is not created.

REGRESSION.  Last worked in version 6u25


ERROR MESSAGES/STACK TRACES THAT OCCUR :
Exception in thread "Thread-12" java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "modifyThreadGroup")
        at java.security.AccessControlContext.checkPermission(Unknown Source)
        at java.security.AccessController.checkPermission(Unknown Source)
        at java.lang.SecurityManager.checkPermission(Unknown Source)
        at sun.plugin2.applet.SecurityManagerHelper.checkAccessHelper(Unknown Source)
        at sun.plugin2.applet.AWTAppletSecurityManager.checkAccess(Unknown Source)
        at java.lang.ThreadGroup.checkAccess(Unknown Source)
        at java.lang.Thread.init(Unknown Source)
        at java.lang.Thread.<init>(Unknown Source)
        at TestApplet$1.run(TestApplet.java:44)
        at java.lang.Thread.run(Unknown Source)

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import javax.swing.*;

public class TestApplet extends JApplet {
    public void init() {
        new Thread(new ThreadGroup(Thread.currentThread().getThreadGroup().getParent(), "TestAppletGroup"), new Runnable() {
            public void run() {
                new Thread(new Runnable() {
                    public void run() {
                        System.out.println("test");
                    }
                }).start();
            }
        }).start();
    }
}
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
The simple workaround is not use custom thread groups in applet or if you started using them then you should use it everywhere.
But it���s not always possible to control new thread creation, for example following code doesn���t work too:

public class TestApplet extends JApplet {
    public void init() {
        new Thread(new ThreadGroup("TestAppletGroup"), new Runnable() {
            public void run() {
                SwingWorker worker = new SwingWorker() {
                    protected String doInBackground() throws Exception {
                        System.out.println("test");
                        return null;
                    }
                };
                worker.execute();
            }
        }).start();
    }
}

Comments
regression_test_src: http://sqe-hg.us.oracle.com/hg/index.cgi/testbase/javase/functional/8/deployment2/file/481c00290528/new_framework/tests/plugin/ThreadTests/src/ThreadTest.java
01-11-2013

EVALUATION confirmed my finding with 6u27. Thread.currentThread().getThreadGroup().getParent() should not work and will throw security exception.
25-07-2011

EVALUATION bug is in SecurityManagerHelper.inThreadGroup method. It should use getThreadGroupHelper() instead of sm.getThreadGroup() to obtain the security manager's group. (sm here will be sun.awt.SecurityManager, which will not give us the applet's threadgroup; we need to get the applet's threadgroup from the applet classloader, which is done by getThreadGroupHelper) However, I don't think this should work in sandbox applet code: Thread.currentThread().getThreadGroup().getParent() getParent() should fail in sandbox. sandbox applet have access to the current applet's threadgroup, and can create child threadgroup under it. however, you should not have access to the parent TG of the applet, which is our plugin internal system TG. will double check behavior in JRE 6 and confirm.
25-07-2011