[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