From 93adc344c84b5baa308aa895e924b3192904869c Mon Sep 17 00:00:00 2001 From: Jason Tedor Date: Sun, 4 Sep 2016 12:06:36 -0400 Subject: [PATCH] Handle security exception from logging stack trace When logging a stack trace, Log4j attempts to load the classes in the stack trace. Yet, it might not have permissions to load some of these classes and a security exception will be thrown. Log4j does not handle this exception and this exception can unwind to the caller. This causes the original exception to be lost, and can even unwind the JVM. This commit fixes this by treating these security exceptions as another possible reason that a class can not be loaded. --- .../logging/log4j/core/impl/ThrowableProxy.java | 4 ++ .../log4j/core/impl/ThrowableProxyTest.java | 56 ++++++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxy.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxy.java index 28f8e56..7205332 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxy.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxy.java @@ -498,6 +498,8 @@ public class ThrowableProxy implements Serializable { return initializeClass(className); } catch (final NoClassDefFoundError ignored) { return initializeClass(className); + } catch (final SecurityException ignored) { + return null; } return clazz; } @@ -509,6 +511,8 @@ public class ThrowableProxy implements Serializable { return null; } catch (final NoClassDefFoundError ignore) { return null; + } catch (final SecurityException ignore) { + return null; } } diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/ThrowableProxyTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/ThrowableProxyTest.java index 98e3ec7..3bae771 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/ThrowableProxyTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/ThrowableProxyTest.java @@ -27,6 +27,14 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; +import java.net.BindException; +import java.net.InetSocketAddress; +import java.net.SocketPermission; +import java.nio.channels.ServerSocketChannel; +import java.security.CodeSource; +import java.security.PermissionCollection; +import java.security.Permissions; +import java.security.Policy; import java.util.HashMap; import java.util.Map; import java.util.Stack; @@ -123,6 +131,54 @@ public class ThrowableProxyTest { } } + @Test + public void testLogStackTraceWithClassThatWillCauseSecurityException() throws IOException { + class SimplePolicy extends Policy { + + private final Permissions permissions; + + public SimplePolicy(Permissions permissions) { + this.permissions = permissions; + } + + @Override + public PermissionCollection getPermissions(CodeSource codesource) { + return permissions; + } + + } + + final SecurityManager sm = System.getSecurityManager(); + try { + final Permissions permissions = new Permissions(); + + // you know, for binding + permissions.add(new SocketPermission("localhost:9300", "listen,resolve")); + + /** + * the JUnit test runner uses reflection to invoke the test; while leaving this + * permission out would display the same issue, it's clearer to grant this + * permission and show the real issue that would arise + */ + // TODO: other JDKs might need a different permission here + permissions.add(new RuntimePermission("accessClassInPackage.sun.reflect")); + + // for restoring the security manager after test execution + permissions.add(new RuntimePermission("setSecurityManager")); + + Policy.setPolicy(new SimplePolicy(permissions)); + System.setSecurityManager(new SecurityManager()); + ServerSocketChannel.open().socket().bind(new InetSocketAddress("localhost", 9300)); + ServerSocketChannel.open().socket().bind(new InetSocketAddress("localhost", 9300)); + fail("expected a java.net.BindException"); + } catch (final BindException e) { + new ThrowableProxy(e); + } finally { + // restore the security manager + System.setSecurityManager(sm); + } + } + // DO NOT REMOVE THIS COMMENT: // UNCOMMENT WHEN GENERATING SERIALIZED THROWABLEPROXY FOR #testSerializationWithUnknownThrowable // public static class DeletedException extends Exception { -- 2.9.0