[#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 cb9660f83d
commit 88481131be
15 changed files with 111 additions and 29 deletions

View File

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

View File

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

View File

@ -51,9 +51,9 @@ public final class JavassistTypeParameterMatcherGenerator {
}
public static TypeParameterMatcher generate(Class<?> type) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
ClassLoader classLoader = PlatformDependent.getContextClassLoader();
if (classLoader == null) {
classLoader = ClassLoader.getSystemClassLoader();
classLoader = PlatformDependent.getSystemClassLoader();
}
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() {
boolean android;
try {
Class.forName("android.app.Application", false, ClassLoader.getSystemClassLoader());
Class.forName("android.app.Application", false, getSystemClassLoader());
android = true;
} catch (Exception e) {
// Failed to load the class uniquely available in Android.
@ -517,7 +538,7 @@ public final class PlatformDependent {
}
try {
Class.forName("java.time.Clock", false, Object.class.getClassLoader());
Class.forName("java.time.Clock", false, getClassLoader(Object.class));
javaVersion = 8;
break;
} catch (Exception e) {
@ -525,7 +546,7 @@ public final class PlatformDependent {
}
try {
Class.forName("java.util.concurrent.LinkedTransferQueue", false, BlockingQueue.class.getClassLoader());
Class.forName("java.util.concurrent.LinkedTransferQueue", false, getClassLoader(BlockingQueue.class));
javaVersion = 7;
break;
} catch (Exception e) {
@ -591,7 +612,7 @@ public final class PlatformDependent {
long maxDirectMemory = 0;
try {
// 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");
maxDirectMemory = ((Number) m.invoke(null)).longValue();
} catch (Throwable t) {
@ -606,9 +627,9 @@ public final class PlatformDependent {
// 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.
Class<?> mgmtFactoryClass = Class.forName(
"java.lang.management.ManagementFactory", true, ClassLoader.getSystemClassLoader());
"java.lang.management.ManagementFactory", true, getSystemClassLoader());
Class<?> runtimeClass = Class.forName(
"java.lang.management.RuntimeMXBean", true, ClassLoader.getSystemClassLoader());
"java.lang.management.RuntimeMXBean", true, getSystemClassLoader());
Object runtime = mgmtFactoryClass.getDeclaredMethod("getRuntimeMXBean").invoke(null);
@ -662,7 +683,7 @@ public final class PlatformDependent {
}
try {
JavassistTypeParameterMatcherGenerator.generate(Object.class, PlatformDependent.class.getClassLoader());
JavassistTypeParameterMatcherGenerator.generate(Object.class, getClassLoader(PlatformDependent.class));
logger.debug("Javassist: available");
return true;
} catch (Throwable t) {

View File

@ -26,6 +26,8 @@ import java.lang.reflect.Method;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
import java.util.concurrent.atomic.AtomicLongFieldUpdater;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
@ -50,7 +52,7 @@ final class PlatformDependent0 {
static {
boolean directBufferFreeable = false;
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");
if ("sun.misc.Cleaner".equals(method.getReturnType().getName())) {
directBufferFreeable = true;
@ -328,6 +330,45 @@ final class PlatformDependent0 {
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() {
}

View File

@ -18,6 +18,8 @@ package io.netty.util.internal;
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.logging.Level;
import java.util.logging.Logger;
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
* 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) {
throw new NullPointerException("key");
}
@ -74,7 +76,16 @@ public final class SystemPropertyUtil {
String value = null;
try {
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) {
if (!loggedException) {
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.stream.ChunkedFile;
import io.netty.util.CharsetUtil;
import io.netty.util.internal.SystemPropertyUtil;
import javax.activation.MimetypesFileTypeMap;
import java.io.File;
@ -264,7 +265,7 @@ public class HttpStaticFileServerHandler extends SimpleChannelInboundHandler<Ful
}
// 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\\.]*");

View File

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

View File

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

View File

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

View File

@ -657,7 +657,7 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH
// 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
// the impl.
Class<?> clazz = getClass().getClassLoader().loadClass(classname);
Class<?> clazz = PlatformDependent.getClassLoader(getClass()).loadClass(classname);
if (SocketChannel.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.epoll.EpollChannelOutboundBuffer.AddressEntry;
import io.netty.util.internal.NativeLibraryLoader;
import io.netty.util.internal.PlatformDependent;
import io.netty.util.internal.SystemPropertyUtil;
import java.io.IOException;
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 };
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")) {
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

View File

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

View File

@ -67,7 +67,7 @@ public final class NioEventLoop extends SingleThreadEventLoop {
static {
String key = "sun.nio.ch.bugLevel";
try {
String buglevel = System.getProperty(key);
String buglevel = SystemPropertyUtil.get(key);
if (buglevel == null) {
System.setProperty(key, "");
}
@ -136,7 +136,7 @@ public final class NioEventLoop extends SingleThreadEventLoop {
SelectedSelectionKeySet selectedKeySet = new SelectedSelectionKeySet();
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.
if (!selectorImplClass.isAssignableFrom(selector.getClass())) {

View File

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