[logback-user] SecurityManager issue using logback (LBCLASSIC-304)

Joern Huxhorn jhuxhorn at googlemail.com
Sun Nov 6 15:35:13 CET 2011


I think this is how it should be done: https://github.com/ceki/logback/tree/LBCLASSIC-304
The behavior is mostly unchanged if no SecurityManager is installed since System.getSecurityManager() is cheap.
Additional checks are only performed if that call returns a non-null result.

The fact that Permission can only be checked by catching an AccessControlException is giving me the creeps, though.
Must be rather old code...

Joern

On 06.11.2011, at 07:42, ceki wrote:

> Keep in mind that the SecurityManager is usually installed by the
> container very early in the container life cycle and one usually does
> not change security managers on the fly, but your point is a good one
> nonetheless.
> 
> On 11/6/2011 1:32 AM, Joern Huxhorn wrote:
>> There is one issue with the code in http://goo.gl/zASBm, though:
>> It checks for getClassLoader permission in a static code block only, i.e. when the class is initially loaded by the classloader,  and saves that information for later reference.
>> 
>> I don't think that this is a valid optimization for precisely the reason that this permission can change during runtime (according to http://download.oracle.com/javase/1.4.2/docs/api/java/security/AccessController.html even per thread), for example if a different SecurityManager is installed.
>> 
>> The method using the statically initialized boolean should probably look like this instead:
>> 
>> public static ClassLoader getClassLoaderAsPrivileged(final Class clazz) {
>>   try {
>>     AccessController.checkPermission(new RuntimePermission("getClassLoader"));
>>     return AccessController.doPrivileged(
>>         new PrivilegedAction<ClassLoader>() {
>>           public ClassLoader run() {
>>             return clazz.getClassLoader();
>>           }
>>         });
>>   } catch (AccessControlException e) {
>>     return null;
>>   }
>> }
>> 
>> Not sure if this would solve the problem at hand...
>> 
>> Joern.
>> 
>> On 05.11.2011, at 16:25, ceki wrote:
>> 
>>> 
>>> Thanks for the sample project. I can confirm that I observe a
>>> AccessControlException when logback is present. The
>>> AccessControlException is not thrown if slf4j-nop, slf4j-simple or
>>> slf4j-log4j are used as the slf4j binding.
>>> 
>>> Although logback does not install its own SecurityManager or modify
>>> the security configuration, it does attempt to determine whether it
>>> has "getClassLoader" permission. See http://goo.gl/zASBm
>>> 
>>> Here is the code in question:
>>> 
>>>  AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
>>>     public Boolean run() {
>>>       try {
>>>         AccessController.checkPermission(
>>>                     new RuntimePermission("getClassLoader"));
>>>         return true;
>>>       } catch (AccessControlException e) {
>>>         return false;
>>>       }
>>>     }
>>>  });
>>> 
>>> 
>>> If the privileged block above code is removed, then the
>>> AccessControlException goes away. The privileged block looks quite
>>> legitimate to me so I don't think it's a bug in logback.
>>> 
>>> To convince yourself the the privileged block is key, you can remove
>>> all logging related calls and all logging related dependencies, add
>>> the privileged block at the beginning of the test. You should observe
>>> an AccessControlException being thrown.
>>> 
>>> --
>>> Ceki
>>> http://twitter.com/#!/ceki
>>> 
>>> 
>>> 
>>> On 11/5/2011 1:42 PM, Andrew Bourgeois wrote:
>>>> Ceki,
>>>> 
>>>> I redid the test in a clean Maven project. I don't know if attachments
>>>> will pass through, so:
>>>> 
>>>> 1) pom.xml:
>>>> 
>>>> <project xmlns="http://maven.apache.org/POM/4.0.0"
>>>> xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
>>>> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
>>>> http://maven.apache.org/maven-v4_0_0.xsd">
>>>> <modelVersion>4.0.0</modelVersion>
>>>> <name>test</name>
>>>> <groupId>be.test.fun</groupId>
>>>> <artifactId>test</artifactId>
>>>> <version>0.1.0-RC1</version>
>>>> <dependencies>
>>>> <dependency>
>>>> <groupId>org.slf4j</groupId>
>>>> <artifactId>slf4j-api</artifactId>
>>>> <version>1.6.0</version>
>>>> </dependency>
>>>> 
>>>> <dependency>
>>>> <groupId>log4j</groupId>
>>>> <artifactId>log4j</artifactId>
>>>> <version>1.2.16</version>
>>>> </dependency>
>>>> <dependency>
>>>> <groupId>org.slf4j</groupId>
>>>> <artifactId>slf4j-log4j12</artifactId>
>>>> <version>1.6.0</version>
>>>> </dependency>
>>>> 
>>>> <!--dependency>
>>>> <groupId>ch.qos.logback</groupId>
>>>> <artifactId>logback-core</artifactId>
>>>> <version>1.0.0</version>
>>>> </dependency>
>>>> <dependency>
>>>> <groupId>ch.qos.logback</groupId>
>>>> <artifactId>logback-classic</artifactId>
>>>> <version>1.0.0</version>
>>>> </dependency-->
>>>> 
>>>> <dependency>
>>>> <groupId>junit</groupId>
>>>> <artifactId>junit</artifactId>
>>>> <version>4.4</version>
>>>> <scope>test</scope>
>>>> </dependency>
>>>> </dependencies>
>>>> <build>
>>>> <resources>
>>>> </resources>
>>>> <plugins>
>>>> <plugin>
>>>> <artifactId>maven-compiler-plugin</artifactId>
>>>> <configuration>
>>>> <source>1.6</source>
>>>> <target>1.6</target>
>>>> <verbose>true</verbose>
>>>> </configuration>
>>>> </plugin>
>>>> </plugins>
>>>> </build>
>>>> </project>
>>>> 
>>>> 2) The JUnit test:
>>>> 
>>>> package be.test.fun;
>>>> 
>>>> import org.junit.Test;
>>>> import java.rmi.RMISecurityManager;
>>>> import org.slf4j.Logger;
>>>> import org.slf4j.LoggerFactory;
>>>> 
>>>> public class SecurityManagerTest {
>>>> 
>>>> @Test
>>>> public void securityManagerWithLogs() {
>>>> Logger logger = LoggerFactory.getLogger(SecurityManagerTest.class);
>>>> 
>>>> System.setProperty("java.security.policy",
>>>> "./src/test/resources/java.policy");
>>>> logger.debug("Policy location: {}",
>>>> System.getProperty("java.security.policy"));
>>>> if (System.getSecurityManager() == null) {
>>>> System.setSecurityManager(new RMISecurityManager());
>>>> }
>>>> System.setProperty("java.security.policy",
>>>> "./src/test/resources/java.policy");
>>>> }
>>>> 
>>>> // @Test
>>>> // public void securityManagerWithoutLogs() {
>>>> // System.setProperty("java.security.policy",
>>>> "./src/test/resources/java.policy");
>>>> // if (System.getSecurityManager() == null) {
>>>> // System.setSecurityManager(new RMISecurityManager());
>>>> // }
>>>> // System.setProperty("java.security.policy",
>>>> "./src/test/resources/java.policy");
>>>> // }
>>>> }
>>>> 
>>>> 3) java.policy that you put into src/test.resources:
>>>> 
>>>> grant {
>>>> permission java.security.AllPermission;
>>>> };
>>>> 
>>>> So.... if you run this:
>>>> -------------------------------------------------------
>>>> T E S T S
>>>> -------------------------------------------------------
>>>> Running be.test.fun.SecurityManagerTest
>>>> 2011-11-05 13:36:33,828 [main] DEBUG - (be.test.fun.SecurityManagerTest)
>>>> - Policy location: ./src/test/resources/java.policy
>>>> Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.201 sec
>>>> 
>>>> Results :
>>>> 
>>>> Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
>>>> 
>>>> Now, comment the 2 LOG4J-related dependencies inside the POM, and
>>>> uncomment the logback ones:
>>>> -------------------------------------------------------
>>>> T E S T S
>>>> -------------------------------------------------------
>>>> Running be.test.fun.SecurityManagerTest
>>>> 13:38:04.222 [main] DEBUG be.test.fun.SecurityManagerTest - Policy
>>>> location: ./src/test/resources/java.policy
>>>> java.security.AccessControlException: access denied
>>>> (java.lang.RuntimePermission setContextClassLoader)
>>>> at
>>>> java.security.AccessControlContext.checkPermission(AccessControlContext.java:323)
>>>> 
>>>> at
>>>> java.security.AccessController.checkPermission(AccessController.java:546)
>>>> at java.lang.SecurityManager.checkPermission(SecurityManager.java:532)
>>>> at java.lang.Thread.setContextClassLoader(Thread.java:1394)
>>>> at
>>>> org.apache.maven.surefire.booter.SurefireBooter.runSuitesInProcess(SurefireBooter.java:366)
>>>> 
>>>> at
>>>> org.apache.maven.surefire.booter.SurefireBooter.main(SurefireBooter.java:1021)
>>>> 
>>>> [INFO]
>>>> ------------------------------------------------------------------------
>>>> [INFO] BUILD FAILURE
>>>> [INFO]
>>>> ------------------------------------------------------------------------
>>>> [INFO] Total time: 2.202s
>>>> 
>>>> And now comment the "securityManagerWithLogs" test method, and uncomment
>>>> the "securityManagerWithoutLogs" one:
>>>> -------------------------------------------------------
>>>> T E S T S
>>>> -------------------------------------------------------
>>>> Running be.test.fun.SecurityManagerTest
>>>> Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.105 sec
>>>> 
>>>> Results :
>>>> 
>>>> Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
>>>> 
>>>> Do you have the same output?
>>>> 
>>>> FYI:
>>>> 
>>>> [xvepak at localhost test]$ mvn -version
>>>> Apache Maven 3.0.1 (r1038046; 2010-11-23 11:58:32+0100)
>>>> Java version: 1.6.0_23
>>>> Java home: /home/xvepak/software/jdk1.6.0_23/jre
>>>> Default locale: en_US, platform encoding: UTF-8
>>>> OS name: "linux" version: "2.6.18-238.12.1.el5" arch: "i386" Family: "unix"
>>>> 
>>>> Thank you for trying to help out!!
>>>> 
>>>> Best regards
>>>> 
>>>> Andrew Bourgeois
>>>> 
>>>> -----Original Message----- From: ceki
>>>> Sent: Saturday, November 05, 2011 1:03 AM
>>>> To: logback users list
>>>> Subject: Re: [logback-user] SecurityManager issue using logback
>>>> 
>>>> On 05/11/2011 12:47 PM, Andrew Bourgeois wrote:
>>>> 
>>>>> So to reformulate:
>>>>> The exception IS thrown when we have SLF4J code
>>>>> The exception ISN'T thrown when we remove the SLF4J.
>>>> 
>>>> That's not what I observe. An exception is thrown in both cases.
>> 
> 
> 
> -- 
> Ceki
> http://twitter.com/#!/ceki
> _______________________________________________
> Logback-user mailing list
> Logback-user at qos.ch
> http://mailman.qos.ch/mailman/listinfo/logback-user



More information about the Logback-user mailing list