L̲̳*_*̲̳̳ 16 java security securitymanager jsr166
在默认的安全管理器下,如果我创建一个ExecutorService(在这种情况下是ThreadPoolExecutor),我无法关闭它,shutdown()只是调用checkPermission("modifyThread")并因此立即死掉:
import java.util.concurrent.*;
class A {
public static void main( String[] args) {
Thread ct = Thread.currentThread();
System.out.println("current thread: " + ct);
ct.checkAccess(); // we have access to our own thread...
ThreadPoolExecutor tpe = new ThreadPoolExecutor(
1, // one core thread
1, // doesn't matter because queue is unbounded
0, TimeUnit.SECONDS, // doesn't matter in this case
new LinkedBlockingQueue<Runnable>(), /* unbound queue for
* our single thread */
new ThreadFactory() {
public Thread newThread(Runnable r) {
// obviously never gets called as we don't add any work
System.out.println("making thread");
return new Thread(r);
}
}
);
tpe.shutdown(); // raises security exception
}
}
Run Code Online (Sandbox Code Playgroud)
Sun JDK:
$ java -Djava.security.manager当前线程:Thread [main,5,main]线程中的异常"main"java.security.AccessControlException:java.security.AccessControlContext.checkPermission中的access denied(java.lang.RuntimePermission modifyThread) (AccessControlContext.java:323)java.security.AccessController.checkPermission(AccessController.java:546)java.lang.SecurityManager.checkPermission(SecurityManager.java:532)java.util.concurrent.ThreadPoolExecutor.shutdown(ThreadPoolExecutor. java:1094)在A.main(A.java:22)
OpenJDK的:
$ java -Djava.security.manager当前线程:Thread [main,5,main]线程中的异常"main"java.security.AccessControlException:java.security.AccessControlContext.checkPermission中的access denied(java.lang.RuntimePermission modifyThread) (AccessControlContext.java:342)java.security.AccessController.checkPermission(AccessController.java:553)java.lang.SecurityManager.checkPermission(SecurityManager.java:549)java.util.concurrent.ThreadPoolExecutor.checkShutdownAccess(ThreadPoolExecutor. java:711)在A.main的java.util.concurrent.ThreadPoolExecutor.shutdown(ThreadPoolExecutor.java:1351)(A.java:22)
为什么???????创建只有您控制并关闭它的线程池有什么安全隐患?这是实施中的错误,还是我遗漏了什么?
让我们看看ExecutorService.shutdown的规范是什么......
启动有序关闭,其中先前提交的任务将被执行,但不会接受任何新任务.如果已经关闭,调用没有其他影响.
抛出:SecurityException - 如果存在安全管理器并且关闭此ExecutorService可能会操纵不允许调用者修改的线程,因为它不包含RuntimePermission("modifyThread"),或者安全管理器的checkAccess方法拒绝访问.
这......就像它变得模糊一样.细则中指出没有任何"系统线程"一个ExecutorService的生命周期的过程中进行,此外,它可以让你提供你自己的线程这是证明应该有没有 "系统线程"参与,当你做到这一点.(正如我上面的示例源中所做的那样)
感觉就像Java SE实现者看到它可以shutdown提升SecurityException,所以他们就像是,"哦,好吧,我只是在这里添加随机安全检查以确保合规性"......
通过阅读OpenJDK源代码(openjdk-6-src-b20-21_jun_2010),事实证明,创建任何线程的唯一方法是调用你提供的ThreadFactory(因为我不在我的测试用例中调用它) "产生任何工作,我不叫prestartCoreThread或preStartAllCoreThreads).因此,在OpenJDK的ThreadPoolExecutor中没有明显的原因进行安全检查(就像在sun-jdk-1.6中完成的那样,但是我没有源代码):
/**
* Initiates an orderly shutdown in which previously submitted
* tasks are executed, but no new tasks will be accepted.
* Invocation has no additional effect if already shut down.
*
* @throws SecurityException {@inheritDoc}
*/
public void shutdown() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
checkShutdownAccess();
advanceRunState(SHUTDOWN);
interruptIdleWorkers();
onShutdown(); // hook for ScheduledThreadPoolExecutor
} finally {
mainLock.unlock();
}
tryTerminate();
}
Run Code Online (Sandbox Code Playgroud)
checkShutdownAccess 在做任何事之前被召唤......
/**
* If there is a security manager, makes sure caller has
* permission to shut down threads in general (see shutdownPerm).
* If this passes, additionally makes sure the caller is allowed
* to interrupt each worker thread. This might not be true even if
* first check passed, if the SecurityManager treats some threads
* specially.
*/
private void checkShutdownAccess() {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkPermission(shutdownPerm);
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (Worker w : workers)
security.checkAccess(w.thread);
} finally {
mainLock.unlock();
}
}
}
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,它无条件地checkPermission(shutdownPerm)在安全管理器上调用.... shutdownPerm定义为... private static final RuntimePermission shutdownPerm = new RuntimePermission("modifyThread");
......这使得完全没有意义,因为据我可以告诉,因为modifyThread意味着进入系统线程,并有是在游戏中没有系统的线程在这里,其实,有没有线程,因为在所有我没有提交任何工作或起动前,即使有线程,它们也是我的线程,因为我传入了一个ThreadFactory.该规范没有说明神奇的死亡,除了涉及系统线程(它们不是),可能有一个SecurityException.
基本上,为什么我不能删除检查系统线程访问权限的行?我认为没有安全隐含要求它.怎么没有其他人遇到这个问题?我已经看到了问题跟踪后,他们通过改变调用"解决"这个问题shutdownNow来shutdown,很显然,这并没有为他们解决.
这很简单:你不能在主线程组中执行此操作。它部分是为小程序设计的。复制关闭方法的想法为什么?如果出现问题,您可以自由地使用 PrivilegedAction 来调用关闭。请记住,Thread.interrupt() 看起来也很无辜throws SecurityException。
回答这个问题:只要确保您授予自己的代码权限,您就很高兴。另外,“modifyThread”也可以自由授予,它主要由小程序使用。
至于不受信任的代码:嗯,不受信任的代码甚至不应该处理其 ThreadGroup 之外的线程,因此提供 API 来创建 ThreadPool,并允许关闭调用者创建的线程。您可以根据调用者授予权限。
希望这能有所帮助(不过,问号的数量清楚地表明了绝望和最大的烦恼)
/*
* Conceptually, shutdown is just a matter of changing the
* runState to SHUTDOWN, and then interrupting any worker
* threads that might be blocked in getTask() to wake them up
* so they can exit. Then, if there happen not to be any
* threads or tasks, we can directly terminate pool via
* tryTerminate. Else, the last worker to leave the building
* turns off the lights (in workerDone).
*
* But this is made more delicate because we must cooperate
* with the security manager (if present), which may implement
* policies that make more sense for operations on Threads
* than they do for ThreadPools. This requires 3 steps:
*
* 1. Making sure caller has permission to shut down threads
* in general (see shutdownPerm).
*
* 2. If (1) passes, making sure the caller is allowed to
* modify each of our threads. This might not be true even if
* first check passed, if the SecurityManager treats some
* threads specially. If this check passes, then we can try
* to set runState.
*
* 3. If both (1) and (2) pass, dealing with inconsistent
* security managers that allow checkAccess but then throw a
* SecurityException when interrupt() is invoked. In this
* third case, because we have already set runState, we can
* only try to back out from the shutdown as cleanly as
* possible. Some workers may have been killed but we remain
* in non-shutdown state (which may entail tryTerminate from
* workerDone starting a new worker to maintain liveness.)
*/
Run Code Online (Sandbox Code Playgroud)