On Thu, Jan 16, 2025 at 5:42 PM Mark Thomas <ma...@apache.org> wrote:
>
> On 16/01/2025 16:38, ma...@apache.org wrote:
> > This is an automated email from the ASF dual-hosted git repository.
> >
> > markt pushed a commit to branch 9.0.x
> > in repository https://gitbox.apache.org/repos/asf/tomcat.git
> >
> >
> > The following commit(s) were added to refs/heads/9.0.x by this push:
> >       new 427732ef8e Automate protection for CVE-2024-56337
> > 427732ef8e is described below
> >
> > commit 427732ef8ee7f707a32734a13a926a2d070b8ba9
> > Author: Mark Thomas <ma...@apache.org>
> > AuthorDate: Thu Jan 16 16:37:06 2025 +0000
> >
> >      Automate protection for CVE-2024-56337
> >
> >      If there is a potentially vulnerable web application (Java < 21,
> >      WebResourceSet configured for read/write, case-insensitive file system)
> >      ensure that the JVM behaves as if sun.io.useCanonCaches is false. If
> >      that cannot be ensured, prevent the potentially vulnerable web
> >      applications from starting.
>
> I looked at various approaches for this and settled on this one after a
> few experiements. I wanted to give folks a little time for feedback
> before porting it to 10.1.x and 11.0.x. I won't port it to main since
> that requires Java 21 where the problematic JVM setting doesn't exist.

Ok, it works.

Rémy

> Mark
>
> > ---
> >   bin/catalina.bat                                   |  7 +++
> >   bin/catalina.sh                                    |  7 +++
> >   .../catalina/webresources/DirResourceSet.java      | 29 +++++++++
> >   .../catalina/webresources/LocalStrings.properties  |  2 +
> >   .../org/apache/tomcat/util/compat/Jre21Compat.java | 14 +++++
> >   java/org/apache/tomcat/util/compat/JreCompat.java  | 69 
> > +++++++++++++++++++++-
> >   .../tomcat/util/compat/LocalStrings.properties     |  3 +
> >   webapps/docs/changelog.xml                         |  9 +++
> >   8 files changed, 139 insertions(+), 1 deletion(-)
> >
> > diff --git a/bin/catalina.bat b/bin/catalina.bat
> > index 05704d6115..9fc3da0369 100755
> > --- a/bin/catalina.bat
> > +++ b/bin/catalina.bat
> > @@ -219,6 +219,13 @@ rem Register custom URL handlers
> >   rem Do this here so custom URL handles (specifically 'war:...') can be 
> > used in the security policy
> >   set "JAVA_OPTS=%JAVA_OPTS% 
> > -Djava.protocol.handler.pkgs=org.apache.catalina.webresources"
> >
> > +rem Disable the global canonical file name cache to protect against 
> > CVE-2024-56337
> > +rem Note: The cache is disabled by default in Java 12 to 20 inclusive
> > +rem       The cache is removed in Java 21 onwards
> > +rem Need to set this here as java.io.FileSystem caches this in a static 
> > field during class
> > +rem initialisation so it needs to be set before any file system access
> > +set "JAVA_OPTS=%JAVA_OPTS% -Dsun.io.useCanonCaches=false"
> > +
> >   rem Check for the deprecated LOGGING_CONFIG
> >   rem Only use it if CATALINA_LOGGING_CONFIG is not set and LOGGING_CONFIG 
> > starts with "-D..."
> >   if not "%LOGGING_CONFIG:~0,2%"=="-D" goto noLoggingDeprecation
> > diff --git a/bin/catalina.sh b/bin/catalina.sh
> > index 3a2ffdafa0..8d07001214 100755
> > --- a/bin/catalina.sh
> > +++ b/bin/catalina.sh
> > @@ -268,6 +268,13 @@ JAVA_OPTS="$JAVA_OPTS $JSSE_OPTS"
> >   # Do this here so custom URL handles (specifically 'war:...') can be used 
> > in the security policy
> >   JAVA_OPTS="$JAVA_OPTS 
> > -Djava.protocol.handler.pkgs=org.apache.catalina.webresources"
> >
> > +# Disable the global canonical file name cache to protect against 
> > CVE-2024-56337
> > +# Note: The cache is disabled by default in Java 12 to 20 inclusive
> > +#       The cache is removed in Java 21 onwards
> > +# Need to set this here as java.io.FileSystem caches this in a static 
> > field during class
> > +# initialisation so it needs to be set before any file system access
> > +JAVA_OPTS="$JAVA_OPTS -Dsun.io.useCanonCaches=false"
> > +
> >   # Check for the deprecated LOGGING_CONFIG
> >   # Only use it if CATALINA_LOGGING_CONFIG is not set and LOGGING_CONFIG 
> > starts with "-D..."
> >   if [ -z "$CATALINA_LOGGING_CONFIG" ]; then
> > diff --git a/java/org/apache/catalina/webresources/DirResourceSet.java 
> > b/java/org/apache/catalina/webresources/DirResourceSet.java
> > index 512adf8b8a..4f39e87378 100644
> > --- a/java/org/apache/catalina/webresources/DirResourceSet.java
> > +++ b/java/org/apache/catalina/webresources/DirResourceSet.java
> > @@ -36,6 +36,7 @@ import 
> > org.apache.catalina.WebResourceRoot.ResourceSetType;
> >   import org.apache.catalina.util.ResourceSet;
> >   import org.apache.juli.logging.Log;
> >   import org.apache.juli.logging.LogFactory;
> > +import org.apache.tomcat.util.compat.JreCompat;
> >   import org.apache.tomcat.util.http.RequestUtil;
> >
> >   /**
> > @@ -335,6 +336,34 @@ public class DirResourceSet extends 
> > AbstractFileResourceSet implements WebResour
> >                   }
> >               }
> >           }
> > +        // Check for exposure to CVE-2024-56337
> > +        if (caseSensitive) {
> > +            // CVE-2024-56337 (nor CVE-2024-50379) is not exploitable on a 
> > case sensitive file system
> > +            return;
> > +        }
> > +        if (isReadOnly()) {
> > +            // CVE-2024-56337 (nor CVE-2024-50379) is not exploitable on a 
> > read-only ResourceSet
> > +            return;
> > +        }
> > +        if (JreCompat.getInstance().isCanonCachesDisabled()) {
> > +            // CVE-2024-56337 (nor CVE-2024-50379) is not exploitable if 
> > the canonical file name cache is disabled
> > +            return;
> > +        }
> > +        // This ResourceSet may be exposed to CVE-2024-56337.
> > +        if (JreCompat.getInstance().disableCanonCaches()) {
> > +            /*
> > +             * The canonical file name cache was enabled and is now 
> > disabled.
> > +             */
> > +            log.warn(sm.getString("dirResourceSet.canonCaches.disabled", 
> > getFileBase(),
> > +                    getRoot().getContext().getName()));
> > +        } else {
> > +            /*
> > +             * The canonical file name cache could not be disabled (or 
> > Tomcat cannot confirm it has been disabled). This
> > +             * ResourceSet may be exposed to CVE-2024-56337.
> > +             */
> > +            throw new 
> > IllegalStateException(sm.getString("dirResourceSet.canonCaches.enabled", 
> > getFileBase(),
> > +                    getRoot().getContext().getName()));
> > +        }
> >       }
> >
> >
> > diff --git a/java/org/apache/catalina/webresources/LocalStrings.properties 
> > b/java/org/apache/catalina/webresources/LocalStrings.properties
> > index 20bcdf5330..2590428e09 100644
> > --- a/java/org/apache/catalina/webresources/LocalStrings.properties
> > +++ b/java/org/apache/catalina/webresources/LocalStrings.properties
> > @@ -36,6 +36,8 @@ cachedResource.invalidURL=Unable to create an instance of 
> > CachedResourceURLStrea
> >
> >   classpathUrlStreamHandler.notFound=Unable to load the resource [{0}] 
> > using the thread context class loader or the current class''s class loader
> >
> > +dirResourceSet.canonCaches.disabled=Disabled the global canonical file 
> > name cache to protect against CVE-2024-56337 when starting the 
> > WebResourceSet at [{0}] which is part of the web application [{1}]
> > +dirResourceSet.canonCaches.enabled=Unable to disable the global canonical 
> > file name cache or confirm that it is disabled when starting the 
> > WebResourceSet at [{0}] which is part of the web application [{1}]. The 
> > WebResourceSet may be exposed to CVE-2024-56337.
> >   dirResourceSet.isCaseSensitive.fail=Error trying to determine if file 
> > system at [{0}] is case sensitive so assuming it is not case sensitive
> >   dirResourceSet.manifestFail=Failed to read manifest from [{0}]
> >   dirResourceSet.notDirectory=The directory specified by base and internal 
> > path [{0}]{1}[{2}] does not exist.
> > diff --git a/java/org/apache/tomcat/util/compat/Jre21Compat.java 
> > b/java/org/apache/tomcat/util/compat/Jre21Compat.java
> > index c534ea4e2d..ee01f3e28e 100644
> > --- a/java/org/apache/tomcat/util/compat/Jre21Compat.java
> > +++ b/java/org/apache/tomcat/util/compat/Jre21Compat.java
> > @@ -104,4 +104,18 @@ public class Jre21Compat extends Jre19Compat {
> >               throw new CompletionException(e);
> >           }
> >       }
> > +
> > +
> > +    @Override
> > +    public boolean isCanonCachesDisabled() {
> > +        // The cache has been removed in Java 21
> > +        return true;
> > +    }
> > +
> > +
> > +    @Override
> > +    public boolean disableCanonCaches() {
> > +        // The cache has been removed in Java 21
> > +        return true;
> > +    }
> >   }
> > diff --git a/java/org/apache/tomcat/util/compat/JreCompat.java 
> > b/java/org/apache/tomcat/util/compat/JreCompat.java
> > index 66b11684c7..135b7bc21c 100644
> > --- a/java/org/apache/tomcat/util/compat/JreCompat.java
> > +++ b/java/org/apache/tomcat/util/compat/JreCompat.java
> > @@ -37,6 +37,8 @@ import javax.net.ssl.SSLEngine;
> >   import javax.net.ssl.SSLParameters;
> >   import javax.security.auth.Subject;
> >
> > +import org.apache.juli.logging.Log;
> > +import org.apache.juli.logging.LogFactory;
> >   import org.apache.tomcat.util.res.StringManager;
> >
> >   /**
> > @@ -45,6 +47,9 @@ import org.apache.tomcat.util.res.StringManager;
> >    */
> >   public class JreCompat {
> >
> > +    private static final Log log = LogFactory.getLog(Jre21Compat.class);
> > +    private static final StringManager sm = 
> > StringManager.getManager(JreCompat.class);
> > +
> >       private static final int RUNTIME_MAJOR_VERSION = 8;
> >
> >       private static final JreCompat instance;
> > @@ -55,8 +60,8 @@ public class JreCompat {
> >       private static final boolean jre19Available;
> >       private static final boolean jre21Available;
> >       private static final boolean jre22Available;
> > -    private static final StringManager sm = 
> > StringManager.getManager(JreCompat.class);
> >
> > +    private static final Field useCanonCachesField;
> >       protected static final Method setApplicationProtocolsMethod;
> >       protected static final Method getApplicationProtocolMethod;
> >
> > @@ -119,6 +124,21 @@ public class JreCompat {
> >           }
> >           jre11Available = instance.jarFileRuntimeMajorVersion() >= 11;
> >
> > +        Field f1 = null;
> > +        try {
> > +            Class<?> clazz = Class.forName("java.io.FileSystem");
> > +            f1 = clazz.getDeclaredField("useCanonCaches");
> > +            f1.setAccessible(true);
> > +        } catch (ReflectiveOperationException | IllegalArgumentException 
> > e) {
> > +            /*
> > +             * Log at debug level as this will only be an issue if the 
> > field needs to be accessed and most
> > +             * configurations will not need to do so. Appropriate warnings 
> > will be logged if an attempt is made to use
> > +             * the field when it could not be found/accessed.
> > +             */
> > +            log.debug(sm.getString("jreCompat.useCanonCaches.init"), e);
> > +        }
> > +        useCanonCachesField = f1;
> > +
> >           Method m1 = null;
> >           Method m2 = null;
> >           try {
> > @@ -482,4 +502,51 @@ public class JreCompat {
> >               throw new CompletionException(e);
> >           }
> >       }
> > +
> > +
> > +    /*
> > +     * The behaviour of the canonical file cache varies by Java version.
> > +     *
> > +     * The cache was removed in Java 21 so these methods and the 
> > associated code can be removed once the minimum Java
> > +     * version is 21.
> > +     *
> > +     * For 12 <= Java <= 20, the cache was present but disabled by 
> > default. Since the user may have changed the default
> > +     * Tomcat has to assume the cache is enabled unless proven otherwise.
> > +     *
> > +     * For Java < 12, the cache was enabled by default. Tomcat assumes the 
> > cache is enabled unless proven otherwise.
> > +     */
> > +    public boolean isCanonCachesDisabled() {
> > +        if (useCanonCachesField == null) {
> > +            // No need to log a warning. The warning will be logged when 
> > trying to disable the cache.
> > +            return false;
> > +        }
> > +        boolean result = false;
> > +        try {
> > +            result = !((Boolean) 
> > useCanonCachesField.get(null)).booleanValue();
> > +        } catch (ReflectiveOperationException e) {
> > +            // No need to log a warning. The warning will be logged when 
> > trying to disable the cache.
> > +        }
> > +        return result;
> > +    }
> > +
> > +
> > +    /**
> > +     * Disable the global canonical file cache.
> > +     *
> > +     * @return {@code true} if the global canonical file cache was already 
> > disabled prior to this call or was disabled
> > +     *             as a result of this call, otherwise {@code false}
> > +     */
> > +    public boolean disableCanonCaches() {
> > +        if (useCanonCachesField == null) {
> > +            log.warn(sm.getString("jreCompat.useCanonCaches.none"));
> > +            return false;
> > +        }
> > +        try {
> > +            useCanonCachesField.set(null, Boolean.TRUE);
> > +        } catch (ReflectiveOperationException | IllegalArgumentException 
> > e) {
> > +            log.warn(sm.getString("jreCompat.useCanonCaches.failed"), e);
> > +            return false;
> > +        }
> > +        return true;
> > +    }
> >   }
> > diff --git a/java/org/apache/tomcat/util/compat/LocalStrings.properties 
> > b/java/org/apache/tomcat/util/compat/LocalStrings.properties
> > index ad858297e9..4b33b7a4aa 100644
> > --- a/java/org/apache/tomcat/util/compat/LocalStrings.properties
> > +++ b/java/org/apache/tomcat/util/compat/LocalStrings.properties
> > @@ -37,3 +37,6 @@ jreCompat.noApplicationProtocol=Java Runtime does not 
> > support SSLEngine.getAppli
> >   jreCompat.noApplicationProtocols=Java Runtime does not support 
> > SSLParameters.setApplicationProtocols(). You must use Java 9 to use this 
> > feature.
> >   jreCompat.noUnixDomainSocket=Java Runtime does not support Unix domain 
> > sockets. You must use Java 16 or later to use this feature.
> >   jreCompat.noVirtualThreads=Java Runtime does not support virtual threads. 
> > You must use Java 21 or later to use this feature.
> > +jreCompat.useCanonCaches.failed=Failed to set the 
> > java.io.FileSystem.useCanonCaches static field
> > +jreCompat.useCanonCaches.init=Unable to create a reference to the 
> > java.io.FileSystem.useCanonCaches static field
> > +jreCompat.useCanonCaches.none=No reference to the 
> > java.io.FileSystem.useCanonCaches static field available. Enable debug 
> > logging for more information.
> > diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
> > index 4c54b39903..1861714fcc 100644
> > --- a/webapps/docs/changelog.xml
> > +++ b/webapps/docs/changelog.xml
> > @@ -140,6 +140,15 @@
> >           Improve checks for <code>WEB-INF</code> and <code>META-INF</code> 
> > in
> >           the WebDAV servlet. Based on a patch submitted by Chenjp. (remm)
> >         </fix>
> > +      <add>
> > +        Add a check to ensure that, if one or more web applications are
> > +        potentially vulnerable to CVE-2024-56337, the JVM has been 
> > configured to
> > +        protect against the vulnerability and to configure the JVM 
> > correctly if
> > +        not. Where one or more web applications are potentially vulnerable 
> > to
> > +        CVE-2004-56337 and the JVM cannot be correctly configured or it 
> > cannot
> > +        be confirmed that the JVM has been correctly configured, prevent 
> > the
> > +        impacted web applications from starting. (markt)
> > +      </add>
> >       </changelog>
> >     </subsection>
> >     <subsection name="Coyote">
> >
> >
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
> > For additional commands, e-mail: dev-h...@tomcat.apache.org
> >
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
> For additional commands, e-mail: dev-h...@tomcat.apache.org
>

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to