From 88481131be5bc565335a37081c17fb62d023f923 Mon Sep 17 00:00:00 2001 From: Norman Maurer Date: Tue, 8 Apr 2014 13:56:14 +0200 Subject: [PATCH] [#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 --- .../codec/serialization/ClassResolvers.java | 4 +- .../src/main/java/io/netty/util/Version.java | 4 +- ...avassistTypeParameterMatcherGenerator.java | 4 +- .../util/internal/PlatformDependent.java | 35 ++++++++++++--- .../util/internal/PlatformDependent0.java | 43 ++++++++++++++++++- .../util/internal/SystemPropertyUtil.java | 15 ++++++- .../file/HttpStaticFileServerHandler.java | 3 +- .../sslserver/WebSocketSslServer.java | 5 ++- .../WebSocketSslServerSslContext.java | 8 ++-- .../SecureChatSslContextFactory.java | 3 +- .../java/io/netty/handler/ssl/SslHandler.java | 2 +- .../java/io/netty/channel/epoll/Native.java | 6 ++- .../io/netty/channel/DefaultChannelId.java | 2 +- .../io/netty/channel/nio/NioEventLoop.java | 4 +- .../socket/nio/NioDatagramChannelConfig.java | 2 +- 15 files changed, 111 insertions(+), 29 deletions(-) diff --git a/codec/src/main/java/io/netty/handler/codec/serialization/ClassResolvers.java b/codec/src/main/java/io/netty/handler/codec/serialization/ClassResolvers.java index 9c7bee5f1a..0d8c11f2f9 100644 --- a/codec/src/main/java/io/netty/handler/codec/serialization/ClassResolvers.java +++ b/codec/src/main/java/io/netty/handler/codec/serialization/ClassResolvers.java @@ -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() { diff --git a/common/src/main/java/io/netty/util/Version.java b/common/src/main/java/io/netty/util/Version.java index 7de1582398..22941a0dd6 100644 --- a/common/src/main/java/io/netty/util/Version.java +++ b/common/src/main/java/io/netty/util/Version.java @@ -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 identify(ClassLoader classLoader) { if (classLoader == null) { - classLoader = Thread.currentThread().getContextClassLoader(); + classLoader = PlatformDependent.getContextClassLoader(); } // Collect all properties. diff --git a/common/src/main/java/io/netty/util/internal/JavassistTypeParameterMatcherGenerator.java b/common/src/main/java/io/netty/util/internal/JavassistTypeParameterMatcherGenerator.java index 85f5c2ad6a..37ef6ea39a 100644 --- a/common/src/main/java/io/netty/util/internal/JavassistTypeParameterMatcherGenerator.java +++ b/common/src/main/java/io/netty/util/internal/JavassistTypeParameterMatcherGenerator.java @@ -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); } diff --git a/common/src/main/java/io/netty/util/internal/PlatformDependent.java b/common/src/main/java/io/netty/util/internal/PlatformDependent.java index 16cfc7c51c..f34d5877aa 100644 --- a/common/src/main/java/io/netty/util/internal/PlatformDependent.java +++ b/common/src/main/java/io/netty/util/internal/PlatformDependent.java @@ -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) { diff --git a/common/src/main/java/io/netty/util/internal/PlatformDependent0.java b/common/src/main/java/io/netty/util/internal/PlatformDependent0.java index 048ef4d6e0..9c4ca1cf72 100644 --- a/common/src/main/java/io/netty/util/internal/PlatformDependent0.java +++ b/common/src/main/java/io/netty/util/internal/PlatformDependent0.java @@ -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(UNSAFE, tclass, fieldName); } + static ClassLoader getClassLoader(final Class clazz) { + if (System.getSecurityManager() == null) { + return clazz.getClassLoader(); + } else { + return AccessController.doPrivileged(new PrivilegedAction() { + @Override + public ClassLoader run() { + return clazz.getClassLoader(); + } + }); + } + } + + static ClassLoader getContextClassLoader() { + if (System.getSecurityManager() == null) { + return Thread.currentThread().getContextClassLoader(); + } else { + return AccessController.doPrivileged(new PrivilegedAction() { + @Override + public ClassLoader run() { + return Thread.currentThread().getContextClassLoader(); + } + }); + } + } + + static ClassLoader getSystemClassLoader() { + if (System.getSecurityManager() == null) { + return ClassLoader.getSystemClassLoader(); + } else { + return AccessController.doPrivileged(new PrivilegedAction() { + @Override + public ClassLoader run() { + return ClassLoader.getSystemClassLoader(); + } + }); + } + } + private PlatformDependent0() { } diff --git a/common/src/main/java/io/netty/util/internal/SystemPropertyUtil.java b/common/src/main/java/io/netty/util/internal/SystemPropertyUtil.java index 2877648d01..4801ad28d3 100644 --- a/common/src/main/java/io/netty/util/internal/SystemPropertyUtil.java +++ b/common/src/main/java/io/netty/util/internal/SystemPropertyUtil.java @@ -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 { - value = System.getProperty(key); + if (System.getSecurityManager() == null) { + value = System.getProperty(key); + } else { + value = AccessController.doPrivileged(new PrivilegedAction() { + @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); diff --git a/example/src/main/java/io/netty/example/http/file/HttpStaticFileServerHandler.java b/example/src/main/java/io/netty/example/http/file/HttpStaticFileServerHandler.java index 948cc45461..8c8f3ae0ae 100644 --- a/example/src/main/java/io/netty/example/http/file/HttpStaticFileServerHandler.java +++ b/example/src/main/java/io/netty/example/http/file/HttpStaticFileServerHandler.java @@ -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 clazz = getClass().getClassLoader().loadClass(classname); + Class clazz = PlatformDependent.getClassLoader(getClass()).loadClass(classname); if (SocketChannel.class.isAssignableFrom(clazz) || DatagramChannel.class.isAssignableFrom(clazz)) { diff --git a/transport-native-epoll/src/main/java/io/netty/channel/epoll/Native.java b/transport-native-epoll/src/main/java/io/netty/channel/epoll/Native.java index 74a85e9c1e..43f7cfeebb 100644 --- a/transport-native-epoll/src/main/java/io/netty/channel/epoll/Native.java +++ b/transport-native-epoll/src/main/java/io/netty/channel/epoll/Native.java @@ -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 diff --git a/transport/src/main/java/io/netty/channel/DefaultChannelId.java b/transport/src/main/java/io/netty/channel/DefaultChannelId.java index 8b38bf7b37..5c6dcf4ed1 100644 --- a/transport/src/main/java/io/netty/channel/DefaultChannelId.java +++ b/transport/src/main/java/io/netty/channel/DefaultChannelId.java @@ -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() diff --git a/transport/src/main/java/io/netty/channel/nio/NioEventLoop.java b/transport/src/main/java/io/netty/channel/nio/NioEventLoop.java index 936f840110..34c00a8cd5 100644 --- a/transport/src/main/java/io/netty/channel/nio/NioEventLoop.java +++ b/transport/src/main/java/io/netty/channel/nio/NioEventLoop.java @@ -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())) { diff --git a/transport/src/main/java/io/netty/channel/socket/nio/NioDatagramChannelConfig.java b/transport/src/main/java/io/netty/channel/socket/nio/NioDatagramChannelConfig.java index 349dcbf235..0401db8184 100644 --- a/transport/src/main/java/io/netty/channel/socket/nio/NioDatagramChannelConfig.java +++ b/transport/src/main/java/io/netty/channel/socket/nio/NioDatagramChannelConfig.java @@ -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);