Set thread context classloader in a doPrivileged block
Motivation: In a few classes, Netty starts a thread and then sets the context classloader of these threads to prevent classloader leaks. The Thread#setContextClassLoader method is a privileged method in that it requires permissions to be executed when there is a security manager in place. Unless these calls are wrapped in a doPrivileged block, they will fail in an environment with a security manager and restrictive policy in place. Modifications: Wrap the calls to Thread#setContextClassLoader in a AccessController#doPrivileged block. Result: After this change, the threads can set the context classloader without any errors in an environment with a security manager and restrictive policy in place.
This commit is contained in:
parent
848b2b23d7
commit
0eda1fea58
@ -22,6 +22,8 @@ import io.netty.util.internal.SystemPropertyUtil;
|
||||
import io.netty.util.internal.logging.InternalLogger;
|
||||
import io.netty.util.internal.logging.InternalLoggerFactory;
|
||||
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
@ -106,13 +108,19 @@ public final class ThreadDeathWatcher {
|
||||
pendingEntries.add(new Entry(thread, task, isWatch));
|
||||
|
||||
if (started.compareAndSet(false, true)) {
|
||||
Thread watcherThread = threadFactory.newThread(watcher);
|
||||
final Thread watcherThread = threadFactory.newThread(watcher);
|
||||
// Set to null to ensure we not create classloader leaks by holds a strong reference to the inherited
|
||||
// classloader.
|
||||
// See:
|
||||
// - https://github.com/netty/netty/issues/7290
|
||||
// - https://bugs.openjdk.java.net/browse/JDK-7008595
|
||||
watcherThread.setContextClassLoader(null);
|
||||
AccessController.doPrivileged(new PrivilegedAction<Void>() {
|
||||
@Override
|
||||
public Void run() {
|
||||
watcherThread.setContextClassLoader(null);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
watcherThread.start();
|
||||
ThreadDeathWatcher.watcherThread = watcherThread;
|
||||
|
@ -18,6 +18,8 @@ package io.netty.util.concurrent;
|
||||
import io.netty.util.internal.logging.InternalLogger;
|
||||
import io.netty.util.internal.logging.InternalLoggerFactory;
|
||||
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.Executors;
|
||||
@ -218,13 +220,19 @@ public final class GlobalEventExecutor extends AbstractScheduledEventExecutor {
|
||||
|
||||
private void startThread() {
|
||||
if (started.compareAndSet(false, true)) {
|
||||
Thread t = threadFactory.newThread(taskRunner);
|
||||
final Thread t = threadFactory.newThread(taskRunner);
|
||||
// Set to null to ensure we not create classloader leaks by holds a strong reference to the inherited
|
||||
// classloader.
|
||||
// See:
|
||||
// - https://github.com/netty/netty/issues/7290
|
||||
// - https://bugs.openjdk.java.net/browse/JDK-7008595
|
||||
t.setContextClassLoader(null);
|
||||
AccessController.doPrivileged(new PrivilegedAction<Void>() {
|
||||
@Override
|
||||
public Void run() {
|
||||
t.setContextClassLoader(null);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
// Set the thread before starting it as otherwise inEventLoop() may return false and so produce
|
||||
// an assert error.
|
||||
|
@ -21,6 +21,8 @@ import io.netty.util.internal.logging.InternalLoggerFactory;
|
||||
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
@ -98,14 +100,20 @@ public final class ObjectCleaner {
|
||||
|
||||
// Check if there is already a cleaner running.
|
||||
if (CLEANER_RUNNING.compareAndSet(false, true)) {
|
||||
Thread cleanupThread = new FastThreadLocalThread(CLEANER_TASK);
|
||||
final Thread cleanupThread = new FastThreadLocalThread(CLEANER_TASK);
|
||||
cleanupThread.setPriority(Thread.MIN_PRIORITY);
|
||||
// Set to null to ensure we not create classloader leaks by holding a strong reference to the inherited
|
||||
// classloader.
|
||||
// See:
|
||||
// - https://github.com/netty/netty/issues/7290
|
||||
// - https://bugs.openjdk.java.net/browse/JDK-7008595
|
||||
cleanupThread.setContextClassLoader(null);
|
||||
AccessController.doPrivileged(new PrivilegedAction<Void>() {
|
||||
@Override
|
||||
public Void run() {
|
||||
cleanupThread.setContextClassLoader(null);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
cleanupThread.setName(CLEANER_THREAD_NAME);
|
||||
|
||||
// This Thread is not a daemon as it will die once all references to the registered Objects will go away
|
||||
|
Loading…
Reference in New Issue
Block a user