From f9258ed237c00b92236066fce8ab1b3839f5780f Mon Sep 17 00:00:00 2001 From: pmeloni Date: Tue, 9 Jun 2026 16:16:58 +0200 Subject: [PATCH] Resolves: RHEL-168577 Remove tomcat clustering JAR from RPM builds Resolves: CVE-2026-29146 tomcat: Apache Tomcat: Information disclosure via Padding Oracle vulnerability in EncryptInterceptor Resolves: CVE-2026-34486 tomcat: Apache Tomcat: Missing Encryption of Sensitive Data due to EncryptInterceptor bypass Exclude i686 architecture from build Co-authored-by: @eabdullin1 (cherry picked from commit d35685dd1b35c58b008e8f0164d1e59e91b5ffb4) --- rhbz-1857043.patch | 38 +++----- rhel-168577.patch | 235 +++++++++++++++++++++++++++++++++++++++++++++ sources | 2 +- tomcat.spec | 29 ++++-- 4 files changed, 273 insertions(+), 31 deletions(-) create mode 100644 rhel-168577.patch diff --git a/rhbz-1857043.patch b/rhbz-1857043.patch index 31ca1df..862675b 100644 --- a/rhbz-1857043.patch +++ b/rhbz-1857043.patch @@ -1,6 +1,6 @@ --- build.xml.orig +++ build.xml -@@ -1124,7 +1124,7 @@ +@@ -1138,7 +1138,7 @@ filesDir="${tomcat.classes}" filesId="files.annotations-api" manifest="${tomcat.manifests}/annotations-api.jar.manifest" @@ -9,7 +9,7 @@ + addOSGi="false" /> - - -+ addOSGi="false" /> - - + + +@@ -1258,7 +1258,7 @@ + addOSGi="false" /> - - -+ addOSGi="false" /> - - + + +@@ -1279,7 +1279,7 @@ clusterValveClass; +- static { +- Class clazz = null; +- try { +- clazz = Class.forName("org.apache.catalina.ha.ClusterValve"); +- } catch (ClassNotFoundException e) { +- // Expected when clustering JARs are not present +- } +- clusterValveClass = clazz; +- } +- + /** + * Store the specified Engine properties. + *

+@@ -74,7 +64,7 @@ + if (valves != null && valves.length > 0) { + List engineValves = new ArrayList<>(); + for (Valve valve : valves) { +- if (clusterValveClass == null || !clusterValveClass.isInstance(valve)) { ++ if (!(valve instanceof ClusterValve)) { + engineValves.add(valve); + } + } +diff --git a/java/org/apache/catalina/storeconfig/StandardHostSF.java b/java/org/apache/catalina/storeconfig/StandardHostSF.java +index 60d473982b..1e8f2d3a58 100644 +--- a/java/org/apache/catalina/storeconfig/StandardHostSF.java ++++ b/java/org/apache/catalina/storeconfig/StandardHostSF.java +@@ -26,23 +26,13 @@ + import org.apache.catalina.Realm; + import org.apache.catalina.Valve; + import org.apache.catalina.core.StandardHost; ++import org.apache.catalina.ha.ClusterValve; + + /** + * Store server.xml Element Host + */ + public class StandardHostSF extends StoreFactoryBase { + +- private static final Class clusterValveClass; +- static { +- Class clazz = null; +- try { +- clazz = Class.forName("org.apache.catalina.ha.ClusterValve"); +- } catch (ClassNotFoundException e) { +- // Expected when clustering JARs are not present +- } +- clusterValveClass = clazz; +- } +- + /** + * Store the specified Host properties and children (Listener,Alias,Realm,Valve,Cluster, Context) + *

+@@ -78,7 +68,7 @@ + if (valves != null && valves.length > 0) { + List hostValves = new ArrayList<>(); + for (Valve valve : valves) { +- if (clusterValveClass == null || !clusterValveClass.isInstance(valve)) { ++ if (!(valve instanceof ClusterValve)) { + hostValves.add(valve); + } + } +diff --git a/java/org/apache/catalina/storeconfig/StoreRegistry.java b/java/org/apache/catalina/storeconfig/StoreRegistry.java +index c17dd3817e..ee803abe36 100644 +--- a/java/org/apache/catalina/storeconfig/StoreRegistry.java ++++ b/java/org/apache/catalina/storeconfig/StoreRegistry.java +@@ -16,9 +16,7 @@ + */ + package org.apache.catalina.storeconfig; + +-import java.util.ArrayList; + import java.util.HashMap; +-import java.util.List; + import java.util.Map; + + import javax.naming.directory.DirContext; +@@ -30,6 +28,17 @@ + import org.apache.catalina.Valve; + import org.apache.catalina.WebResourceRoot; + import org.apache.catalina.WebResourceSet; ++import org.apache.catalina.ha.CatalinaCluster; ++import org.apache.catalina.ha.ClusterDeployer; ++import org.apache.catalina.ha.ClusterListener; ++import org.apache.catalina.tribes.Channel; ++import org.apache.catalina.tribes.ChannelInterceptor; ++import org.apache.catalina.tribes.ChannelReceiver; ++import org.apache.catalina.tribes.ChannelSender; ++import org.apache.catalina.tribes.Member; ++import org.apache.catalina.tribes.MembershipService; ++import org.apache.catalina.tribes.MessageListener; ++import org.apache.catalina.tribes.transport.DataSender; + import org.apache.coyote.UpgradeProtocol; + import org.apache.juli.logging.Log; + import org.apache.juli.logging.LogFactory; +@@ -52,74 +61,11 @@ + private String version; + + // Access Information +- // Lazily initialized to gracefully handle optional features like clustering +- private static volatile Class[] interfaces = null; +- +- /** +- * Initialize the interfaces array with all available classes. +- * Uses dynamic loading for optional classes (e.g., clustering) to avoid +- * ClassNotFoundException when those JARs are not present. This approach +- * is consistent with how Catalina.addClusterRuleSet() handles clustering. +- */ +- private static Class[] getInterfaces() { +- if (interfaces == null) { +- synchronized (StoreRegistry.class) { +- if (interfaces == null) { +- // Required interfaces - always present +- List> list = new ArrayList<>(); +- list.add(Realm.class); +- list.add(Manager.class); +- list.add(DirContext.class); +- list.add(LifecycleListener.class); +- list.add(Valve.class); +- list.add(WebResourceRoot.class); +- list.add(WebResourceSet.class); +- list.add(CredentialHandler.class); +- list.add(UpgradeProtocol.class); +- list.add(CookieProcessor.class); +- +- // Optional clustering interfaces - load dynamically to support +- // deployments where clustering JARs may not be present +- tryAddClass(list, "org.apache.catalina.ha.CatalinaCluster"); +- tryAddClass(list, "org.apache.catalina.tribes.ChannelSender"); +- tryAddClass(list, "org.apache.catalina.tribes.ChannelReceiver"); +- tryAddClass(list, "org.apache.catalina.tribes.Channel"); +- tryAddClass(list, "org.apache.catalina.tribes.MembershipService"); +- tryAddClass(list, "org.apache.catalina.ha.ClusterDeployer"); +- tryAddClass(list, "org.apache.catalina.ha.ClusterListener"); +- tryAddClass(list, "org.apache.catalina.tribes.MessageListener"); +- tryAddClass(list, "org.apache.catalina.tribes.transport.DataSender"); +- tryAddClass(list, "org.apache.catalina.tribes.ChannelInterceptor"); +- tryAddClass(list, "org.apache.catalina.tribes.Member"); +- +- interfaces = list.toArray(new Class[0]); +- +- if (log.isDebugEnabled()) { +- log.debug(sm.getString("registry.interfacesLoaded", Integer.valueOf(interfaces.length))); +- } +- } +- } +- } +- return interfaces; +- } +- +- /** +- * Try to load a class by name and add it to the list if successful. +- * Logs at TRACE level if the class is not available. +- */ +- private static void tryAddClass(List> list, String className) { +- try { +- Class clazz = Class.forName(className, false, StoreRegistry.class.getClassLoader()); +- list.add(clazz); +- if (log.isTraceEnabled()) { +- log.trace(sm.getString("registry.optionalClassLoaded", className)); +- } +- } catch (ClassNotFoundException | NoClassDefFoundError e) { +- if (log.isTraceEnabled()) { +- log.trace(sm.getString("registry.optionalClassNotFound", className)); +- } +- } +- } ++ private static final Class[] interfaces = { CatalinaCluster.class, ChannelSender.class, ChannelReceiver.class, ++ Channel.class, MembershipService.class, ClusterDeployer.class, Realm.class, Manager.class, DirContext.class, ++ LifecycleListener.class, Valve.class, ClusterListener.class, MessageListener.class, DataSender.class, ++ ChannelInterceptor.class, Member.class, WebResourceRoot.class, WebResourceSet.class, ++ CredentialHandler.class, UpgradeProtocol.class, CookieProcessor.class }; + + /** + * @return the name +@@ -170,10 +116,9 @@ + } + if (aClass != null) { + desc = descriptors.get(aClass.getName()); +- Class[] availableInterfaces = getInterfaces(); +- for (int i = 0; desc == null && i < availableInterfaces.length; i++) { +- if (availableInterfaces[i].isAssignableFrom(aClass)) { +- desc = descriptors.get(availableInterfaces[i].getName()); ++ for (int i = 0; desc == null && i < interfaces.length; i++) { ++ if (interfaces[i].isAssignableFrom(aClass)) { ++ desc = descriptors.get(interfaces[i].getName()); + } + } + } +diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml +index 012b607f18..17f639d669 100644 +--- a/webapps/docs/changelog.xml ++++ b/webapps/docs/changelog.xml +@@ -2830,6 +2830,13 @@ + The rewrite valve should not do a rewrite if the output is identical + to the input. (remm) + ++ ++ Update StoreRegistry to dynamically load optional clustering ++ classes rather than statically referencing them. This matches the pattern ++ used in Catalina.addClusterRuleSet() and prevents ++ NoClassDefFoundError when StoreConfigLifecycleListener ++ is configured but clustering classes are not available. (csutherl) ++ + + Add a new valveSkip (or VS) rule flag to the + rewrite valve to allow skipping over the next valve in the Catalina + diff --git a/sources b/sources index ba9a607..736eeb7 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (tomcat-10.1.49.redhat-00007-src.zip) = f72bf5cb755e14a0c4555bcdc3db6bef64c8353339699fc321d6ec2162c72b6999807ddbf3910d9a3217c20df7e94baf5b2c9bb5da7e143c776d01589a41dc4a +SHA512 (tomcat-10.1.49.redhat-00011-src.zip) = ddb3f1e9f601d23752d81f9495a645f31cb47f86f741f75d22695ebedd2a1da952c59ec99acf160cb2df122765ab1821cb95b00773c22ccc8662192fcc2d220b diff --git a/tomcat.spec b/tomcat.spec index 35b3460..2b14df9 100644 --- a/tomcat.spec +++ b/tomcat.spec @@ -32,7 +32,7 @@ %global major_version 10 %global minor_version 1 %global micro_version 49 -%global packdname %{name}-%{major_version}.%{minor_version}.%{micro_version}.redhat-00007-src +%global packdname %{name}-%{major_version}.%{minor_version}.%{micro_version}.redhat-00011-src %global servletspec 6.0 %global elspec 5.0 %global tcuid 53 @@ -54,7 +54,7 @@ Name: tomcat Epoch: 1 Version: %{major_version}.%{minor_version}.%{micro_version} -Release: 1%{?dist}.1 +Release: 2%{?dist} Summary: Apache Servlet/JSP Engine, RI for Servlet %{servletspec}/JSP %{jspspec} API License: Apache-2.0 @@ -81,8 +81,10 @@ Patch5: %{name}-%{major_version}.%{minor_version}-JDTCompiler.patch Patch6: rhbz-1857043.patch # Patch 7 can be dropped when ECJ is updated to a newer version Patch7: build-with-java-25.patch +patch8: rhel-168577.patch BuildArch: noarch +ExclusiveArch: %{java_arches} noarch BuildRequires: ant >= 1.10.2 BuildRequires: ecj >= 4.20 @@ -207,6 +209,7 @@ find . -type f \( -name "*.bat" -o -name "*.class" -o -name Thumbs.db -o -name " %patch 5 -p0 %patch 6 -p0 %patch 7 -p0 +%patch 8 -p1 # Remove webservices naming resources as it's generally unused %{__rm} -rf java/org/apache/naming/factory/webservices @@ -218,6 +221,9 @@ find . -type f \( -name "*.bat" -o -name "*.class" -o -name Thumbs.db -o -name " %mvn_alias "org.apache.tomcat:tomcat-jsp-api" "jakarta.servlet:jakarta.servlet.jsp" %mvn_package ":tomcat-servlet-api" tomcat-servlet-api +%pom_remove_dep org.apache.tomcat:tomcat-tribes res/maven/tomcat-storeconfig.pom +%pom_remove_dep org.apache.tomcat:tomcat-catalina-ha res/maven/tomcat-storeconfig.pom + %build # we don't care about the tarballs and we're going to replace jars @@ -285,6 +291,10 @@ pushd output/build %{__cp} -a webapps/* ${RPM_BUILD_ROOT}%{appdir} popd +# Clustering is unsupported in RHEL +rm -f ${RPM_BUILD_ROOT}%{libdir}/catalina-ha.jar +rm -f ${RPM_BUILD_ROOT}%{libdir}/catalina-tribes.jar + %{__sed} -e "s|\@\@\@TCHOME\@\@\@|%{homedir}|g" \ -e "s|\@\@\@TCTEMP\@\@\@|%{tempdir}|g" \ -e "s|\@\@\@LIBDIR\@\@\@|%{_libdir}|g" %{SOURCE1} \ @@ -386,8 +396,6 @@ popd %mvn_artifact res/maven/tomcat-api.pom ${RPM_BUILD_ROOT}%{libdir}/tomcat-api.jar %mvn_file org.apache.tomcat:tomcat-catalina-ant tomcat/catalina-ant %mvn_artifact res/maven/tomcat-catalina-ant.pom ${RPM_BUILD_ROOT}%{libdir}/catalina-ant.jar -%mvn_file org.apache.tomcat:tomcat-catalina-ha tomcat/catalina-ha -%mvn_artifact res/maven/tomcat-catalina-ha.pom ${RPM_BUILD_ROOT}%{libdir}/catalina-ha.jar %mvn_file org.apache.tomcat:tomcat-catalina tomcat/catalina %mvn_artifact res/maven/tomcat-catalina.pom ${RPM_BUILD_ROOT}%{libdir}/catalina.jar %mvn_artifact res/maven/tomcat-coyote.pom ${RPM_BUILD_ROOT}%{libdir}/tomcat-coyote.jar @@ -415,8 +423,6 @@ popd %mvn_artifact res/maven/tomcat-ssi.pom ${RPM_BUILD_ROOT}%{libdir}/catalina-ssi.jar %mvn_file org.apache.tomcat:tomcat-storeconfig tomcat/catalina-storeconfig %mvn_artifact res/maven/tomcat-storeconfig.pom ${RPM_BUILD_ROOT}%{libdir}/catalina-storeconfig.jar -%mvn_file org.apache.tomcat:tomcat-tribes tomcat/catalina-tribes -%mvn_artifact res/maven/tomcat-tribes.pom ${RPM_BUILD_ROOT}%{libdir}/catalina-tribes.jar %mvn_artifact res/maven/tomcat-util-scan.pom ${RPM_BUILD_ROOT}%{libdir}/tomcat-util-scan.jar %mvn_artifact res/maven/tomcat-util.pom ${RPM_BUILD_ROOT}%{libdir}/tomcat-util.jar %mvn_file org.apache.tomcat:tomcat-websocket-api tomcat/websocket-api @@ -551,6 +557,14 @@ exit 0 %{appdir}/ROOT %changelog +* Thu Jun 4 2026 Pietro Meloni - 1:10.1.49-2 +- Resolves: RHEL-168577 Remove tomcat clustering JAR from RPM builds + Resolves: CVE-2026-29146 + tomcat: Apache Tomcat: Information disclosure via Padding Oracle vulnerability in EncryptInterceptor + Resolves: CVE-2026-34486 + tomcat: Apache Tomcat: Missing Encryption of Sensitive Data due to EncryptInterceptor bypass + + * Wed Apr 22 2026 Pietro Meloni - 1:10.1.36-3.el10_1.1 - Resolves: RHEL-150719 Certificate revocation bypass due to improper OCSP response validation (CVE-2026-24734) @@ -566,6 +580,9 @@ exit 0 - Resolves: RHEL-132526 tomcat: Denial of service (CVE-2025-61795) +* Mon Dec 15 2025 Eduard Abdullin - 1:10.1.36-4 +- Exclude i686 architecture from build + * Thu Aug 14 2025 Adam Krajcik - 1:10.1.36-3 - Resolves: RHEL-102184 tomcat: http/2 "MadeYouReset" DoS attack through HTTP/2 control frames (CVE-2025-48989)