Uwe Schindler commented on LOG4J2-2761:

this issue hurted us several times with Solr (but also Elasticsearch). See 
SOLR-14362 for an example.

Apache Lucene/Solr tests run inside a security manager, Apache Solr also and 
Elasticsearch has a security manager and policy for every plugin. The policy is 
very restrictive and does not allow any read/write access outside the home 
folder of Solr/Elasticsearch and while running tests, every test is completely 
restricted to its working directory.

In most cases you can work around that issue by explicitely passing a 
-Dlog4j.configurationFile with a real filename (no URI or whatever). But as 
soon as you have something like a URI from ClassLoader (because by default 
log4j is searching for the config file in classpath, you are lost:

If the classes (that's usual in tests) are in a file system folder which has a 
whitespace in the name, log4j does the following:
- It calls {{classloader.getResource("log4j2.xml")}} this returns an URL
- It reads the URL using its InputStream (which is all fine), but for some 
reason it also calls the method FileUtils#fileFromUri() using a fully valid 
resource URL.
- The correct way would be to throw away that method and just use {{new 
File(url.toURI())}}. E.g. see a nice comment in the Maven docu about this: 

Sorry to be a bit harsh here: fileFromUri() looks like a method from the early 
days of Java and Log4j1, never touched and broken to hell (to hell to hell!!!). 
It does so many shitty things, which is against all standards, just to try to 
convert an URL to a File object. I agree that some parts of the code should be 
OK to do when parsing user-supplied URLs (e.g. if you have just a relative path 
name or relative file URI), but all this JBOSS and escaping/unescaping to try 
to do file.exist() is - sorry - not acceptable and breaks too easy.

In short:
- Nuke most of that method and only use it to parse URLs coming from config 
files. The part with relative paths at begin is OK, but when you detected that 
it's a valid absolute URL it should not try to be clever - especially it should 
never do I/O with File.exist()! You need to catch SecurityException(), as 
calling exists() may not be allowed. But to make it easy, use the "official" 
way shown below.
- When loading the log4j from the classpath (ConfigurationSource.fromResource) 
don't call this method at all. You can 100% be sure that the URL is correctly 
formatted. Maybe just check that it's a "file"-URL.

The only correct way to convert an URL to a file is new File(url.toURI()).

FYI, URL#getFile() is a "forbidden method" in code from the Lucene community. 
We disallow any class we compile to call it really anywhere! The problem with 
this method is that it DOES NOT convert an URL to a File, its name is 

> log4j2 fails when a whitespace is in the file path and Java security manager 
> is used
> ------------------------------------------------------------------------------------
>                 Key: LOG4J2-2761
>                 URL: https://issues.apache.org/jira/browse/LOG4J2-2761
>             Project: Log4j 2
>          Issue Type: Bug
>    Affects Versions: 2.13.0
>         Environment: Windows 7/10, Java 8/11/13 with configured Java Security 
> Manager
>            Reporter: Yury Molchan
>            Priority: Major
> {code}
> SEVERE: Error configuring application listener of class 
> [org.yurkom.navigator.web.servlet.StartupListener]
> java.security.AccessControlException: access denied ("java.io.FilePermission" 
> "C:\My%20Space\apache-tomcat-9.0.30\webapps\navigator\WEB-INF\classes\log4j2.properties"
>  "read")
>         at 
> java.security.AccessControlContext.checkPermission(AccessControlContext.java:472)
>         at 
> java.security.AccessController.checkPermission(AccessController.java:884)
>         at java.lang.SecurityManager.checkPermission(SecurityManager.java:549)
>         at java.lang.SecurityManager.checkRead(SecurityManager.java:888)
>         at java.io.File.exists(File.java:814)
>         at 
> org.apache.logging.log4j.core.util.FileUtils.fileFromUri(FileUtils.java:88)
>         at 
> org.apache.logging.log4j.core.config.ConfigurationSource.fromResource(ConfigurationSource.java:360)
>         at 
> org.apache.logging.log4j.core.config.ConfigurationFactory$Factory.getConfiguration(ConfigurationFactory.java:527)
>         at 
> org.apache.logging.log4j.core.config.ConfigurationFactory$Factory.getConfiguration(ConfigurationFactory.java:456)
>         at 
> org.apache.logging.log4j.core.config.ConfigurationFactory.getConfiguration(ConfigurationFactory.java:318)
>         at 
> org.apache.logging.log4j.core.LoggerContext.reconfigure(LoggerContext.java:687)
>         at 
> org.apache.logging.log4j.core.LoggerContext.reconfigure(LoggerContext.java:708)
>         at 
> org.apache.logging.log4j.core.LoggerContext.start(LoggerContext.java:263)
>         at 
> org.apache.logging.log4j.core.impl.Log4jContextFactory.getContext(Log4jContextFactory.java:153)
>         at 
> org.apache.logging.log4j.core.impl.Log4jContextFactory.getContext(Log4jContextFactory.java:45)
>         at org.apache.logging.log4j.LogManager.getContext(LogManager.java:194)
>         at 
> org.apache.logging.log4j.spi.AbstractLoggerAdapter.getContext(AbstractLoggerAdapter.java:138)
> {code}
> policy file contains the following permissions:
> {code}
> grant codeBase "file:${catalina.home}/webapps/navigator/-" {
>         permission java.io.FilePermission "${catalina.home}/-", "read";
>         permission java.io.FilePermission "${catalina.home}/", "read";
> };
> {code}
> where catalina.home is "C:\My Space\apache-tomcat-9.0.30"
> It is related to LOG4J2-466

This message was sent by Atlassian Jira

Reply via email to