[#2353] Use a privileged block to get ClassLoader and System property if needed

Motivation:
When using System.getProperty(...) and various methods to get a ClassLoader it will fail when a SecurityManager is in place.

Modifications:
Use a priveled block if needed. This work is based in the PR #2353 done by @anilsaldhana .

Result:
Code works also when SecurityManager is present
This commit is contained in:
Norman Maurer 2014-04-08 13:56:14 +02:00
parent 69826637a8
commit 31a36e09ad
15 changed files with 111 additions and 29 deletions

View File

@ -90,12 +90,12 @@ public final class ClassResolvers {
return classLoader; return classLoader;
} }
final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); final ClassLoader contextClassLoader = PlatformDependent.getContextClassLoader();
if (contextClassLoader != null) { if (contextClassLoader != null) {
return contextClassLoader; return contextClassLoader;
} }
return ClassResolvers.class.getClassLoader(); return PlatformDependent.getClassLoader(ClassResolvers.class);
} }
private ClassResolvers() { private ClassResolvers() {

View File

@ -16,6 +16,8 @@
package io.netty.util; package io.netty.util;
import io.netty.util.internal.PlatformDependent;
import java.io.InputStream; import java.io.InputStream;
import java.net.URL; import java.net.URL;
import java.text.ParseException; import java.text.ParseException;
@ -61,7 +63,7 @@ public final class Version {
*/ */
public static Map<String, Version> identify(ClassLoader classLoader) { public static Map<String, Version> identify(ClassLoader classLoader) {
if (classLoader == null) { if (classLoader == null) {
classLoader = Thread.currentThread().getContextClassLoader(); classLoader = PlatformDependent.getContextClassLoader();
} }
// Collect all properties. // Collect all properties.

View File

@ -51,9 +51,9 @@ public final class JavassistTypeParameterMatcherGenerator {
} }
public static TypeParameterMatcher generate(Class<?> type) { public static TypeParameterMatcher generate(Class<?> type) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); ClassLoader classLoader = PlatformDependent.getContextClassLoader();
if (classLoader == null) { if (classLoader == null) {
classLoader = ClassLoader.getSystemClassLoader(); classLoader = PlatformDependent.getSystemClassLoader();
} }
return generate(type, classLoader); return generate(type, classLoader);
} }

View File

@ -387,10 +387,31 @@ public final class PlatformDependent {
} }
} }
/**
* Return the {@link ClassLoader} for the given {@link Class}.
*/
public static ClassLoader getClassLoader(final Class<?> clazz) {
return PlatformDependent0.getClassLoader(clazz);
}
/**
* Return the context {@link ClassLoader} for the current {@link Thread}.
*/
public static ClassLoader getContextClassLoader() {
return PlatformDependent0.getContextClassLoader();
}
/**
* Return the system {@link ClassLoader}.
*/
public static ClassLoader getSystemClassLoader() {
return PlatformDependent0.getSystemClassLoader();
}
private static boolean isAndroid0() { private static boolean isAndroid0() {
boolean android; boolean android;
try { try {
Class.forName("android.app.Application", false, ClassLoader.getSystemClassLoader()); Class.forName("android.app.Application", false, getSystemClassLoader());
android = true; android = true;
} catch (Exception e) { } catch (Exception e) {
// Failed to load the class uniquely available in Android. // Failed to load the class uniquely available in Android.
@ -517,7 +538,7 @@ public final class PlatformDependent {
} }
try { try {
Class.forName("java.time.Clock", false, Object.class.getClassLoader()); Class.forName("java.time.Clock", false, getClassLoader(Object.class));
javaVersion = 8; javaVersion = 8;
break; break;
} catch (Exception e) { } catch (Exception e) {
@ -525,7 +546,7 @@ public final class PlatformDependent {
} }
try { try {
Class.forName("java.util.concurrent.LinkedTransferQueue", false, BlockingQueue.class.getClassLoader()); Class.forName("java.util.concurrent.LinkedTransferQueue", false, getClassLoader(BlockingQueue.class));
javaVersion = 7; javaVersion = 7;
break; break;
} catch (Exception e) { } catch (Exception e) {
@ -591,7 +612,7 @@ public final class PlatformDependent {
long maxDirectMemory = 0; long maxDirectMemory = 0;
try { try {
// Try to get from sun.misc.VM.maxDirectMemory() which should be most accurate. // Try to get from sun.misc.VM.maxDirectMemory() which should be most accurate.
Class<?> vmClass = Class.forName("sun.misc.VM", true, ClassLoader.getSystemClassLoader()); Class<?> vmClass = Class.forName("sun.misc.VM", true, getSystemClassLoader());
Method m = vmClass.getDeclaredMethod("maxDirectMemory"); Method m = vmClass.getDeclaredMethod("maxDirectMemory");
maxDirectMemory = ((Number) m.invoke(null)).longValue(); maxDirectMemory = ((Number) m.invoke(null)).longValue();
} catch (Throwable t) { } catch (Throwable t) {
@ -606,9 +627,9 @@ public final class PlatformDependent {
// Now try to get the JVM option (-XX:MaxDirectMemorySize) and parse it. // Now try to get the JVM option (-XX:MaxDirectMemorySize) and parse it.
// Note that we are using reflection because Android doesn't have these classes. // Note that we are using reflection because Android doesn't have these classes.
Class<?> mgmtFactoryClass = Class.forName( Class<?> mgmtFactoryClass = Class.forName(
"java.lang.management.ManagementFactory", true, ClassLoader.getSystemClassLoader()); "java.lang.management.ManagementFactory", true, getSystemClassLoader());
Class<?> runtimeClass = Class.forName( Class<?> runtimeClass = Class.forName(
"java.lang.management.RuntimeMXBean", true, ClassLoader.getSystemClassLoader()); "java.lang.management.RuntimeMXBean", true, getSystemClassLoader());
Object runtime = mgmtFactoryClass.getDeclaredMethod("getRuntimeMXBean").invoke(null); Object runtime = mgmtFactoryClass.getDeclaredMethod("getRuntimeMXBean").invoke(null);
@ -662,7 +683,7 @@ public final class PlatformDependent {
} }
try { try {
JavassistTypeParameterMatcherGenerator.generate(Object.class, PlatformDependent.class.getClassLoader()); JavassistTypeParameterMatcherGenerator.generate(Object.class, getClassLoader(PlatformDependent.class));
logger.debug("Javassist: available"); logger.debug("Javassist: available");
return true; return true;
} catch (Throwable t) { } catch (Throwable t) {

View File

@ -26,6 +26,8 @@ import java.lang.reflect.Method;
import java.nio.Buffer; import java.nio.Buffer;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder; import java.nio.ByteOrder;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
import java.util.concurrent.atomic.AtomicLongFieldUpdater; import java.util.concurrent.atomic.AtomicLongFieldUpdater;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
@ -50,7 +52,7 @@ final class PlatformDependent0 {
static { static {
boolean directBufferFreeable = false; boolean directBufferFreeable = false;
try { try {
Class<?> cls = Class.forName("sun.nio.ch.DirectBuffer", false, PlatformDependent0.class.getClassLoader()); Class<?> cls = Class.forName("sun.nio.ch.DirectBuffer", false, getClassLoader(PlatformDependent0.class));
Method method = cls.getMethod("cleaner"); Method method = cls.getMethod("cleaner");
if ("sun.misc.Cleaner".equals(method.getReturnType().getName())) { if ("sun.misc.Cleaner".equals(method.getReturnType().getName())) {
directBufferFreeable = true; directBufferFreeable = true;
@ -328,6 +330,45 @@ final class PlatformDependent0 {
return new UnsafeAtomicLongFieldUpdater<T>(UNSAFE, tclass, fieldName); return new UnsafeAtomicLongFieldUpdater<T>(UNSAFE, tclass, fieldName);
} }
static ClassLoader getClassLoader(final Class<?> clazz) {
if (System.getSecurityManager() == null) {
return clazz.getClassLoader();
} else {
return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
@Override
public ClassLoader run() {
return clazz.getClassLoader();
}
});
}
}
static ClassLoader getContextClassLoader() {
if (System.getSecurityManager() == null) {
return Thread.currentThread().getContextClassLoader();
} else {
return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
@Override
public ClassLoader run() {
return Thread.currentThread().getContextClassLoader();
}
});
}
}
static ClassLoader getSystemClassLoader() {
if (System.getSecurityManager() == null) {
return ClassLoader.getSystemClassLoader();
} else {
return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
@Override
public ClassLoader run() {
return ClassLoader.getSystemClassLoader();
}
});
}
}
private PlatformDependent0() { private PlatformDependent0() {
} }

View File

@ -18,6 +18,8 @@ package io.netty.util.internal;
import io.netty.util.internal.logging.InternalLogger; import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory; import io.netty.util.internal.logging.InternalLoggerFactory;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -64,7 +66,7 @@ public final class SystemPropertyUtil {
* {@code def} if there's no such property or if an access to the * {@code def} if there's no such property or if an access to the
* specified property is not allowed. * specified property is not allowed.
*/ */
public static String get(String key, String def) { public static String get(final String key, String def) {
if (key == null) { if (key == null) {
throw new NullPointerException("key"); throw new NullPointerException("key");
} }
@ -74,7 +76,16 @@ public final class SystemPropertyUtil {
String value = null; String value = null;
try { try {
value = System.getProperty(key); if (System.getSecurityManager() == null) {
value = System.getProperty(key);
} else {
value = AccessController.doPrivileged(new PrivilegedAction<String>() {
@Override
public String run() {
return System.getProperty(key);
}
});
}
} catch (Exception e) { } catch (Exception e) {
if (!loggedException) { if (!loggedException) {
log("Unable to retrieve a system property '" + key + "'; default values will be used.", e); log("Unable to retrieve a system property '" + key + "'; default values will be used.", e);

View File

@ -34,6 +34,7 @@ import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.LastHttpContent; import io.netty.handler.codec.http.LastHttpContent;
import io.netty.handler.stream.ChunkedFile; import io.netty.handler.stream.ChunkedFile;
import io.netty.util.CharsetUtil; import io.netty.util.CharsetUtil;
import io.netty.util.internal.SystemPropertyUtil;
import javax.activation.MimetypesFileTypeMap; import javax.activation.MimetypesFileTypeMap;
import java.io.File; import java.io.File;
@ -264,7 +265,7 @@ public class HttpStaticFileServerHandler extends SimpleChannelInboundHandler<Ful
} }
// Convert to absolute path. // Convert to absolute path.
return System.getProperty("user.dir") + File.separator + uri; return SystemPropertyUtil.get("user.dir") + File.separator + uri;
} }
private static final Pattern ALLOWED_FILE_NAME = Pattern.compile("[A-Za-z0-9][-_A-Za-z0-9\\.]*"); private static final Pattern ALLOWED_FILE_NAME = Pattern.compile("[A-Za-z0-9][-_A-Za-z0-9\\.]*");

View File

@ -20,6 +20,7 @@ import io.netty.channel.Channel;
import io.netty.channel.EventLoopGroup; import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.util.internal.SystemPropertyUtil;
/** /**
* A HTTP server which serves Web Socket requests at: * A HTTP server which serves Web Socket requests at:
@ -74,13 +75,13 @@ public class WebSocketSslServer {
port = 8443; port = 8443;
} }
String keyStoreFilePath = System.getProperty("keystore.file.path"); String keyStoreFilePath = SystemPropertyUtil.get("keystore.file.path");
if (keyStoreFilePath == null || keyStoreFilePath.isEmpty()) { if (keyStoreFilePath == null || keyStoreFilePath.isEmpty()) {
System.out.println("ERROR: System property keystore.file.path not set. Exiting now!"); System.out.println("ERROR: System property keystore.file.path not set. Exiting now!");
System.exit(1); System.exit(1);
} }
String keyStoreFilePassword = System.getProperty("keystore.file.password"); String keyStoreFilePassword = SystemPropertyUtil.get("keystore.file.password");
if (keyStoreFilePassword == null || keyStoreFilePassword.isEmpty()) { if (keyStoreFilePassword == null || keyStoreFilePassword.isEmpty()) {
System.out.println("ERROR: System property keystore.file.password not set. Exiting now!"); System.out.println("ERROR: System property keystore.file.password not set. Exiting now!");
System.exit(1); System.exit(1);

View File

@ -15,6 +15,8 @@
*/ */
package io.netty.example.http.websocketx.sslserver; package io.netty.example.http.websocketx.sslserver;
import io.netty.util.internal.SystemPropertyUtil;
import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext; import javax.net.ssl.SSLContext;
import java.io.FileInputStream; import java.io.FileInputStream;
@ -56,14 +58,14 @@ public final class WebSocketSslServerSslContext {
SSLContext serverContext = null; SSLContext serverContext = null;
try { try {
// Key store (Server side certificate) // Key store (Server side certificate)
String algorithm = Security.getProperty("ssl.KeyManagerFactory.algorithm"); String algorithm = SystemPropertyUtil.get("ssl.KeyManagerFactory.algorithm");
if (algorithm == null) { if (algorithm == null) {
algorithm = "SunX509"; algorithm = "SunX509";
} }
try { try {
String keyStoreFilePath = System.getProperty("keystore.file.path"); String keyStoreFilePath = SystemPropertyUtil.get("keystore.file.path");
String keyStoreFilePassword = System.getProperty("keystore.file.password"); String keyStoreFilePassword = SystemPropertyUtil.get("keystore.file.password");
KeyStore ks = KeyStore.getInstance("JKS"); KeyStore ks = KeyStore.getInstance("JKS");
FileInputStream fin = new FileInputStream(keyStoreFilePath); FileInputStream fin = new FileInputStream(keyStoreFilePath);

View File

@ -16,6 +16,7 @@
package io.netty.example.securechat; package io.netty.example.securechat;
import io.netty.handler.ssl.SslHandler; import io.netty.handler.ssl.SslHandler;
import io.netty.util.internal.SystemPropertyUtil;
import java.security.KeyStore; import java.security.KeyStore;
import java.security.SecureRandom; import java.security.SecureRandom;
@ -57,7 +58,7 @@ public final class SecureChatSslContextFactory {
private static final SSLContext CLIENT_CONTEXT; private static final SSLContext CLIENT_CONTEXT;
static { static {
String algorithm = Security.getProperty("ssl.KeyManagerFactory.algorithm"); String algorithm = SystemPropertyUtil.get("ssl.KeyManagerFactory.algorithm");
if (algorithm == null) { if (algorithm == null) {
algorithm = "SunX509"; algorithm = "SunX509";
} }

View File

@ -625,7 +625,7 @@ public class SslHandler extends ByteToMessageDecoder {
// No match by now.. Try to load the class via classloader and inspect it. // No match by now.. Try to load the class via classloader and inspect it.
// This is mainly done as other JDK implementations may differ in name of // This is mainly done as other JDK implementations may differ in name of
// the impl. // the impl.
Class<?> clazz = getClass().getClassLoader().loadClass(classname); Class<?> clazz = PlatformDependent.getClassLoader(getClass()).loadClass(classname);
if (SocketChannel.class.isAssignableFrom(clazz) if (SocketChannel.class.isAssignableFrom(clazz)
|| DatagramChannel.class.isAssignableFrom(clazz)) { || DatagramChannel.class.isAssignableFrom(clazz)) {

View File

@ -19,6 +19,8 @@ package io.netty.channel.epoll;
import io.netty.channel.DefaultFileRegion; import io.netty.channel.DefaultFileRegion;
import io.netty.channel.epoll.EpollChannelOutboundBuffer.AddressEntry; import io.netty.channel.epoll.EpollChannelOutboundBuffer.AddressEntry;
import io.netty.util.internal.NativeLibraryLoader; import io.netty.util.internal.NativeLibraryLoader;
import io.netty.util.internal.PlatformDependent;
import io.netty.util.internal.SystemPropertyUtil;
import java.io.IOException; import java.io.IOException;
import java.net.Inet6Address; import java.net.Inet6Address;
@ -37,11 +39,11 @@ final class Native {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (byte) 0xff, (byte) 0xff }; 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (byte) 0xff, (byte) 0xff };
static { static {
String name = System.getProperty("os.name").toLowerCase(Locale.UK).trim(); String name = SystemPropertyUtil.get("os.name").toLowerCase(Locale.UK).trim();
if (!name.startsWith("linux")) { if (!name.startsWith("linux")) {
throw new IllegalStateException("Only supported on Linux"); throw new IllegalStateException("Only supported on Linux");
} }
NativeLibraryLoader.load("netty-transport-native-epoll", Native.class.getClassLoader()); NativeLibraryLoader.load("netty-transport-native-epoll", PlatformDependent.getClassLoader(Native.class));
} }
// EventLoop operations and constants // EventLoop operations and constants

View File

@ -302,7 +302,7 @@ final class DefaultChannelId implements ChannelId {
} }
private static int defaultProcessId() { private static int defaultProcessId() {
final ClassLoader loader = ClassLoader.getSystemClassLoader(); final ClassLoader loader = PlatformDependent.getSystemClassLoader();
String value; String value;
try { try {
// Invoke java.lang.management.ManagementFactory.getRuntimeMXBean().getName() // Invoke java.lang.management.ManagementFactory.getRuntimeMXBean().getName()

View File

@ -67,7 +67,7 @@ public final class NioEventLoop extends SingleThreadEventLoop {
static { static {
String key = "sun.nio.ch.bugLevel"; String key = "sun.nio.ch.bugLevel";
try { try {
String buglevel = System.getProperty(key); String buglevel = SystemPropertyUtil.get(key);
if (buglevel == null) { if (buglevel == null) {
System.setProperty(key, ""); System.setProperty(key, "");
} }
@ -136,7 +136,7 @@ public final class NioEventLoop extends SingleThreadEventLoop {
SelectedSelectionKeySet selectedKeySet = new SelectedSelectionKeySet(); SelectedSelectionKeySet selectedKeySet = new SelectedSelectionKeySet();
Class<?> selectorImplClass = Class<?> selectorImplClass =
Class.forName("sun.nio.ch.SelectorImpl", false, ClassLoader.getSystemClassLoader()); Class.forName("sun.nio.ch.SelectorImpl", false, PlatformDependent.getSystemClassLoader());
// Ensure the current selector implementation is what we can instrument. // Ensure the current selector implementation is what we can instrument.
if (!selectorImplClass.isAssignableFrom(selector.getClass())) { if (!selectorImplClass.isAssignableFrom(selector.getClass())) {

View File

@ -40,7 +40,7 @@ class NioDatagramChannelConfig extends DefaultDatagramChannelConfig {
private static final Method SET_OPTION; private static final Method SET_OPTION;
static { static {
ClassLoader classLoader = DatagramChannel.class.getClassLoader(); ClassLoader classLoader = PlatformDependent.getClassLoader(DatagramChannel.class);
Class<?> socketOptionType = null; Class<?> socketOptionType = null;
try { try {
socketOptionType = Class.forName("java.net.SocketOption", true, classLoader); socketOptionType = Class.forName("java.net.SocketOption", true, classLoader);