Uploaded image for project: 'logback'
  1. logback
  2. LOGBACK-869

File rolling causes SecurityException if the caller stack contains unstrusted domains

    XMLWordPrintable

Details

    • Icon: Bug Bug
    • Resolution: Unresolved
    • Icon: Major Major
    • None
    • None
    • logback-core
    • None

    Description

      If Java-Security is enabled and the log message that triggers the file rolling (e.g. because the file size limit has been reached) has been written by code from an untrusted domain, an AccessControlException is thrown if the callers domain does not have the necessary privileges to rollover the logfile (read, write). That's because every domain in the call stack must have the required privileges.

      Example:

      • Security is enabled.
      • A log message is written (or an ILoggingEvent is fired) by unstrusted code.
      • This event causes the file rollover.
      • SecurityException is thrown, because the logger call is in the rollover call stack.
      Excerpt from StatusPrinter
      ERROR in ch.qos.logback.core.rolling.RollingFileAppender[FOO] - Appender [FOO] failed to append. java.security.AccessControlException: access denied ("java.io.FilePermission" "/home/christian/foo/bar/logs/foo.log" "read")
      	at java.security.AccessControlException: access denied ("java.io.FilePermission" "/home/christian/foo/bar/logs/foo.log" "read")
      	at 	at java.security.AccessControlContext.checkPermission(AccessControlContext.java:366)
      	at 	at org.eclipse.osgi.internal.permadmin.EquinoxSecurityManager.internalCheckPermission(EquinoxSecurityManager.java:117)
      	at 	at org.eclipse.osgi.internal.permadmin.EquinoxSecurityManager$CheckPermissionAction.run(EquinoxSecurityManager.java:60)
      	at 	at java.security.AccessController.doPrivileged(Native Method)
      	at 	at org.eclipse.osgi.internal.permadmin.EquinoxSecurityManager.checkPermission(EquinoxSecurityManager.java:88)
      	at 	at org.eclipse.osgi.internal.permadmin.EquinoxSecurityManager.checkPermission(EquinoxSecurityManager.java:186)
      	at 	at java.lang.SecurityManager.checkRead(SecurityManager.java:888)
      	at 	at java.io.File.length(File.java:910)
      	at 	at ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy.isTriggeringEvent(SizeBasedTriggeringPolicy.java:59)
      	at 	at ch.qos.logback.core.rolling.RollingFileAppender.subAppend(RollingFileAppender.java:170)
      	at 	at ch.qos.logback.core.OutputStreamAppender.append(OutputStreamAppender.java:103)
      	at 	at ch.qos.logback.core.UnsynchronizedAppenderBase.doAppend(UnsynchronizedAppenderBase.java:88)
      	at 	at ch.qos.logback.core.spi.AppenderAttachableImpl.appendLoopOnAppenders(AppenderAttachableImpl.java:48)
      	at 	at ch.qos.logback.classic.Logger.appendLoopOnAppenders(Logger.java:272)
      	at 	at ch.qos.logback.classic.Logger.callAppenders(Logger.java:259)
      	at 	at ch.qos.logback.classic.Logger.buildLoggingEventAndAppend(Logger.java:441)
      	at 	at ch.qos.logback.classic.Logger.filterAndLog_1(Logger.java:413)
      	at 	at ch.qos.logback.classic.Logger.info(Logger.java:603)
      	at 	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      	at 	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
      	at 	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      	at 	at java.lang.reflect.Method.invoke(Method.java:601)
      	at 	at org.jruby.javasupport.JavaMethod.invokeDirectWithExceptionHandling(JavaMethod.java:425)
      	at 	at org.jruby.javasupport.JavaMethod.invokeDirect(JavaMethod.java:292)
      ...
      

      In this example the untrusted code domain is JRuby, which has evaluated a script that wrote a log message.

      This issue can be solved by marking the rollover call from within the LOGBack domain as privileged using AccessController.doPrivileged(). As the rollover is actually triggered in RollingFileAppender#subAppend(E event) this should be straightforward. Instead of

      if (triggeringPolicy.isTriggeringEvent(currentlyActiveFile, event)) {
        rollover();
      }
      

      we could use

      AccessController.doPrivileged(new PrivilegedAction<Void>() {
        @Override
        public Void run() {
          if (triggeringPolicy.isTriggeringEvent(currentlyActiveFile, event)) {
            rollover();
          }
          return null;
        }
      });
      

      to mark both the file read access in triggeringPolicy.isTriggeringEvent() as well as the write access in rollover() as privileged.

      I will provide a simple pull request to fix this issue.

      Attachments

        Activity

          People

            logback-dev Logback dev list
            christian Christian Brensing
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

              Created:
              Updated: