diff --git a/CVE-2025-31651-1.patch b/CVE-2025-31651-1.patch index 820c9051c15b7154f21fbaf9dcb1e6ab92023a66..65f097999d154b9a4e4ea3e61eaf5554c6ab2ce1 100644 --- a/CVE-2025-31651-1.patch +++ b/CVE-2025-31651-1.patch @@ -4,19 +4,19 @@ Date: Thu, 13 Mar 2025 15:06:26 +0000 Subject: [PATCH] Better handling of URLs with literal ';' and '?' Origin: https://github.com/apache/tomcat/commit/ee3ab548e92345eca0cbd1f01649eb36c6f29454 - --- .../catalina/connector/CoyoteAdapter.java | 18 +-- - .../catalina/valves/rewrite/RewriteValve.java | 137 ++++++++++++++---- + .../catalina/valves/rewrite/RewriteValve.java | 136 ++++++++++++++---- .../valves/rewrite/TestRewriteValve.java | 119 ++++++++++++--- + webapps/docs/changelog.xml | 5 + webapps/docs/rewrite.xml | 22 +++ - 4 files changed, 241 insertions(+), 55 deletions(-) + 5 files changed, 246 insertions(+), 54 deletions(-) diff --git a/java/org/apache/catalina/connector/CoyoteAdapter.java b/java/org/apache/catalina/connector/CoyoteAdapter.java -index 3c09f24..00086bd 100644 +index e21fbd2c6eaf..c3b64265a113 100644 --- a/java/org/apache/catalina/connector/CoyoteAdapter.java +++ b/java/org/apache/catalina/connector/CoyoteAdapter.java -@@ -653,17 +653,17 @@ public class CoyoteAdapter implements Adapter { +@@ -653,17 +653,17 @@ protected boolean postParseRequest(org.apache.coyote.Request req, Request reques } else { /* * The URI is chars or String, and has been sent using an in-memory protocol handler. The following @@ -44,10 +44,10 @@ index 3c09f24..00086bd 100644 } diff --git a/java/org/apache/catalina/valves/rewrite/RewriteValve.java b/java/org/apache/catalina/valves/rewrite/RewriteValve.java -index 6eb01e5..d1071e9 100644 +index 2fc999ba0804..f049e5eb7e40 100644 --- a/java/org/apache/catalina/valves/rewrite/RewriteValve.java +++ b/java/org/apache/catalina/valves/rewrite/RewriteValve.java -@@ -21,6 +21,7 @@ import java.io.IOException; +@@ -21,6 +21,7 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.io.StringReader; @@ -55,7 +55,7 @@ index 6eb01e5..d1071e9 100644 import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.ArrayList; -@@ -64,6 +65,24 @@ import org.apache.tomcat.util.http.RequestUtil; +@@ -65,6 +66,24 @@ */ public class RewriteValve extends ValveBase { @@ -80,7 +80,7 @@ index 6eb01e5..d1071e9 100644 /** * The rewrite rules that the valve will use. */ -@@ -297,22 +316,51 @@ public class RewriteValve extends ValveBase { +@@ -297,22 +316,51 @@ public void invoke(Request request, Response response) throws IOException, Servl invoked.set(Boolean.TRUE); @@ -127,15 +127,15 @@ index 6eb01e5..d1071e9 100644 boolean qsd = false; boolean valveSkip = false; + -+ // Step 2. Process the URL using the re-write rules. ++ // Step 2. Process the URL using the re-write rules. for (int i = 0; i < rules.length; i++) { RewriteRule rule = rules[i]; - CharSequence test = (rule.isHost()) ? host : urlDecoded; + CharSequence test = (rule.isHost()) ? host : urlRewriteEncoded; CharSequence newtest = rule.evaluate(test, resolver); - if (newtest != null && !test.toString().equals(newtest.toString())) { + if (newtest != null && !Objects.equals(test.toString(), newtest.toString())) { if (containerLog.isTraceEnabled()) { -@@ -322,7 +370,7 @@ public class RewriteValve extends ValveBase { +@@ -322,7 +370,7 @@ public void invoke(Request request, Response response) throws IOException, Servl if (rule.isHost()) { host = newtest; } else { @@ -144,32 +144,32 @@ index 6eb01e5..d1071e9 100644 } rewritten = true; } -@@ -359,28 +407,29 @@ public class RewriteValve extends ValveBase { +@@ -359,28 +407,30 @@ public void invoke(Request request, Response response) throws IOException, Servl if (rule.isRedirect() && newtest != null) { // Append the query string to the url if there is one and it // hasn't been rewritten - String urlStringDecoded = urlDecoded.toString(); - int index = urlStringDecoded.indexOf('?'); - String rewrittenQueryStringDecoded; -+ String urlStringRewriteEncoded = urlRewriteEncoded.toString(); ++ String urlStringRewriteEncoded = urlRewriteEncoded.toString(); + int index = urlStringRewriteEncoded.indexOf('?'); + String rewrittenQueryStringRewriteEncoded; if (index == -1) { - rewrittenQueryStringDecoded = null; -+ rewrittenQueryStringRewriteEncoded = null; ++ rewrittenQueryStringRewriteEncoded = null; } else { - rewrittenQueryStringDecoded = urlStringDecoded.substring(index + 1); - urlStringDecoded = urlStringDecoded.substring(0, index); -+ rewrittenQueryStringRewriteEncoded = urlStringRewriteEncoded.substring(index + 1); ++ rewrittenQueryStringRewriteEncoded = urlStringRewriteEncoded.substring(index + 1); + urlStringRewriteEncoded = urlStringRewriteEncoded.substring(0, index); } -- StringBuilder urlStringEncoded = -- new StringBuilder(URLEncoder.DEFAULT.encode(urlStringDecoded, uriCharset)); + // Step 3. Complete the 2nd stage to encoding. -+ StringBuilder urlStringEncoded = -+ new StringBuilder(REWRITE_DEFAULT_ENCODER.encode(urlStringRewriteEncoded, uriCharset)); - if (!qsd && originalQueryStringEncoded != null && originalQueryStringEncoded.length() > 0) { + StringBuilder urlStringEncoded = +- new StringBuilder(URLEncoder.DEFAULT.encode(urlStringDecoded, uriCharset)); ++ new StringBuilder(REWRITE_DEFAULT_ENCODER.encode(urlStringRewriteEncoded, uriCharset)); ++ + if (!qsd && originalQueryStringEncoded != null && !originalQueryStringEncoded.isEmpty()) { - if (rewrittenQueryStringDecoded == null) { + if (rewrittenQueryStringRewriteEncoded == null) { urlStringEncoded.append('?'); @@ -180,12 +180,12 @@ index 6eb01e5..d1071e9 100644 urlStringEncoded.append('?'); - urlStringEncoded - .append(URLEncoder.QUERY.encode(rewrittenQueryStringDecoded, uriCharset)); -+ urlStringEncoded.append( ++ urlStringEncoded.append( + REWRITE_QUERY_ENCODER.encode(rewrittenQueryStringRewriteEncoded, uriCharset)); urlStringEncoded.append('&'); urlStringEncoded.append(originalQueryStringEncoded); } else if (index == urlStringEncoded.length() - 1) { -@@ -389,13 +438,14 @@ public class RewriteValve extends ValveBase { +@@ -389,13 +439,14 @@ public void invoke(Request request, Response response) throws IOException, Servl urlStringEncoded.deleteCharAt(index); } else { urlStringEncoded.append('?'); @@ -204,7 +204,7 @@ index 6eb01e5..d1071e9 100644 } // Insert the context if -@@ -470,12 +520,12 @@ public class RewriteValve extends ValveBase { +@@ -470,12 +521,12 @@ public void invoke(Request request, Response response) throws IOException, Servl if (rewritten) { if (!done) { // See if we need to replace the query string @@ -222,7 +222,7 @@ index 6eb01e5..d1071e9 100644 } // Save the current context path before re-writing starts String contextPath = null; -@@ -489,22 +539,24 @@ public class RewriteValve extends ValveBase { +@@ -489,22 +540,24 @@ public void invoke(Request request, Response response) throws IOException, Servl // This is neither decoded nor normalized chunk.append(contextPath); } @@ -249,10 +249,10 @@ index 6eb01e5..d1071e9 100644 chunk = request.getCoyoteRequest().queryString().getCharChunk(); - chunk.append(URLEncoder.QUERY.encode(queryStringDecoded, uriCharset)); + chunk.append(REWRITE_QUERY_ENCODER.encode(queryStringRewriteEncoded, uriCharset)); - if (qsa && originalQueryStringEncoded != null && originalQueryStringEncoded.length() > 0) { + if (qsa && originalQueryStringEncoded != null && !originalQueryStringEncoded.isEmpty()) { chunk.append('&'); chunk.append(originalQueryStringEncoded); -@@ -799,4 +851,31 @@ public class RewriteValve extends ValveBase { +@@ -799,4 +852,31 @@ protected static void parseRuleFlag(String line, RewriteRule rule, String flag) throw new IllegalArgumentException(sm.getString("rewriteValve.invalidFlags", line, flag)); } } @@ -285,10 +285,10 @@ index 6eb01e5..d1071e9 100644 + } } diff --git a/test/org/apache/catalina/valves/rewrite/TestRewriteValve.java b/test/org/apache/catalina/valves/rewrite/TestRewriteValve.java -index 3a08886..5c737ae 100644 +index 3a08886229ec..5c737ae1a536 100644 --- a/test/org/apache/catalina/valves/rewrite/TestRewriteValve.java +++ b/test/org/apache/catalina/valves/rewrite/TestRewriteValve.java -@@ -20,6 +20,7 @@ import java.io.File; +@@ -20,6 +20,7 @@ import java.io.IOException; import java.io.PrintWriter; import java.net.HttpURLConnection; @@ -296,7 +296,7 @@ index 3a08886..5c737ae 100644 import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.HashMap; -@@ -63,7 +64,7 @@ public class TestRewriteValve extends TomcatBaseTest { +@@ -63,7 +64,7 @@ public void testNoRewrite() throws Exception { @Test public void testBackslashPercentSign() throws Exception { @@ -305,7 +305,7 @@ index 3a08886..5c737ae 100644 } @Test -@@ -142,7 +143,7 @@ public class TestRewriteValve extends TomcatBaseTest { +@@ -142,7 +143,7 @@ public void testRewriteMap09() throws Exception { @Test public void testRewriteMap10() throws Exception { @@ -314,7 +314,7 @@ index 3a08886..5c737ae 100644 } @Test -@@ -346,7 +347,7 @@ public class TestRewriteValve extends TomcatBaseTest { +@@ -346,7 +347,7 @@ public void testNonAsciiQueryStringAndPathAndRedirect() throws Exception { public void testNonAsciiQueryStringWithB() throws Exception { doTestRewrite("RewriteRule ^/b/(.*)/id=(.*) /c?filename=$1&id=$2 [B]", "/b/file01/id=%E5%9C%A8%E7%BA%BF%E6%B5%8B%E8%AF%95", "/c", @@ -323,7 +323,7 @@ index 3a08886..5c737ae 100644 } -@@ -354,8 +355,8 @@ public class TestRewriteValve extends TomcatBaseTest { +@@ -354,8 +355,8 @@ public void testNonAsciiQueryStringWithB() throws Exception { public void testNonAsciiQueryStringAndPathAndRedirectWithB() throws Exception { // Note the double encoding of the result (httpd produces the same result) doTestRewrite("RewriteRule ^/b/(.*)/(.*)/id=(.*) /c/$1?filename=$2&id=$3 [B,R]", @@ -334,7 +334,7 @@ index 3a08886..5c737ae 100644 } -@@ -371,7 +372,7 @@ public class TestRewriteValve extends TomcatBaseTest { +@@ -371,7 +372,7 @@ public void testUtf8WithBothQsFlagsNone() throws Exception { public void testUtf8WithBothQsFlagsB() throws Exception { // Note %C2%A1 == \u00A1 doTestRewrite("RewriteRule ^/b/(.*)/(.*) /c/\u00A1$1?$2 [B]", "/b/%C2%A1/id=%C2%A1?di=%C2%AE", @@ -343,7 +343,7 @@ index 3a08886..5c737ae 100644 } -@@ -387,7 +388,7 @@ public class TestRewriteValve extends TomcatBaseTest { +@@ -387,7 +388,7 @@ public void testUtf8WithBothQsFlagsR() throws Exception { public void testUtf8WithBothQsFlagsRB() throws Exception { // Note %C2%A1 == \u00A1 doTestRewrite("RewriteRule ^/b/(.*)/(.*) /c/\u00A1$1?$2 [R,B]", "/b/%C2%A1/id=%C2%A1?di=%C2%AE", @@ -352,7 +352,7 @@ index 3a08886..5c737ae 100644 } -@@ -413,7 +414,7 @@ public class TestRewriteValve extends TomcatBaseTest { +@@ -413,7 +414,7 @@ public void testUtf8WithBothQsFlagsRBNE() throws Exception { public void testUtf8WithBothQsFlagsBQSA() throws Exception { // Note %C2%A1 == \u00A1 doTestRewrite("RewriteRule ^/b/(.*)/(.*) /c/\u00A1$1?$2 [B,QSA]", "/b/%C2%A1/id=%C2%A1?di=%C2%AE", @@ -361,7 +361,7 @@ index 3a08886..5c737ae 100644 } -@@ -429,7 +430,7 @@ public class TestRewriteValve extends TomcatBaseTest { +@@ -429,7 +430,7 @@ public void testUtf8WithBothQsFlagsRQSA() throws Exception { public void testUtf8WithBothQsFlagsRBQSA() throws Exception { // Note %C2%A1 == \u00A1 doTestRewrite("RewriteRule ^/b/(.*)/(.*) /c/\u00A1$1?$2 [R,B,QSA]", "/b/%C2%A1/id=%C2%A1?di=%C2%AE", @@ -370,7 +370,7 @@ index 3a08886..5c737ae 100644 } -@@ -461,7 +462,7 @@ public class TestRewriteValve extends TomcatBaseTest { +@@ -461,7 +462,7 @@ public void testUtf8WithOriginalQsFlagsNone() throws Exception { @Test public void testUtf8WithOriginalQsFlagsB() throws Exception { // Note %C2%A1 == \u00A1 @@ -379,7 +379,7 @@ index 3a08886..5c737ae 100644 "id=%C2%A1"); } -@@ -476,7 +477,7 @@ public class TestRewriteValve extends TomcatBaseTest { +@@ -476,7 +477,7 @@ public void testUtf8WithOriginalQsFlagsR() throws Exception { @Test public void testUtf8WithOriginalQsFlagsRB() throws Exception { // Note %C2%A1 == \u00A1 @@ -388,7 +388,7 @@ index 3a08886..5c737ae 100644 "id=%C2%A1"); } -@@ -510,8 +511,8 @@ public class TestRewriteValve extends TomcatBaseTest { +@@ -510,8 +511,8 @@ public void testUtf8WithRewriteQsFlagsNone() throws Exception { @Test public void testUtf8WithRewriteQsFlagsB() throws Exception { // Note %C2%A1 == \u00A1 @@ -399,7 +399,7 @@ index 3a08886..5c737ae 100644 } -@@ -534,8 +535,8 @@ public class TestRewriteValve extends TomcatBaseTest { +@@ -534,8 +535,8 @@ public void testUtf8WithBothQsFlagsQSA() throws Exception { @Test public void testUtf8WithRewriteQsFlagsRB() throws Exception { // Note %C2%A1 == \u00A1 @@ -410,7 +410,7 @@ index 3a08886..5c737ae 100644 } -@@ -575,7 +576,7 @@ public class TestRewriteValve extends TomcatBaseTest { +@@ -575,7 +576,7 @@ public void testUtf8FlagsNone() throws Exception { @Test public void testUtf8FlagsB() throws Exception { // Note %C2%A1 == \u00A1 @@ -419,7 +419,7 @@ index 3a08886..5c737ae 100644 } -@@ -589,7 +590,7 @@ public class TestRewriteValve extends TomcatBaseTest { +@@ -589,7 +590,7 @@ public void testUtf8FlagsR() throws Exception { @Test public void testUtf8FlagsRB() throws Exception { // Note %C2%A1 == \u00A1 @@ -428,7 +428,7 @@ index 3a08886..5c737ae 100644 } -@@ -784,6 +785,7 @@ public class TestRewriteValve extends TomcatBaseTest { +@@ -784,6 +785,7 @@ public void invoke(Request request, Response response) throws IOException, Servl rewriteValve.setConfiguration(config); Tomcat.addServlet(ctx, "snoop", new SnoopServlet()); @@ -436,7 +436,7 @@ index 3a08886..5c737ae 100644 ctx.addServletMappingDecoded("/a/%5A", "snoop"); ctx.addServletMappingDecoded("/c/*", "snoop"); ctx.addServletMappingDecoded("/W/*", "snoop"); -@@ -929,4 +931,87 @@ public class TestRewriteValve extends TomcatBaseTest { +@@ -929,4 +931,87 @@ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws Se } } } @@ -525,7 +525,7 @@ index 3a08886..5c737ae 100644 + } } diff --git a/webapps/docs/rewrite.xml b/webapps/docs/rewrite.xml -index f153f9d..123d215 100644 +index f153f9d01825..123d215fcab2 100644 --- a/webapps/docs/rewrite.xml +++ b/webapps/docs/rewrite.xml @@ -56,6 +56,28 @@ @@ -557,6 +557,3 @@ index f153f9d..123d215 100644

The rewrite.config file contains a list of directives which closely --- -2.48.1 - diff --git a/CVE-2025-55752-pre-Cleanups.patch b/CVE-2025-55752-pre-Cleanups.patch new file mode 100644 index 0000000000000000000000000000000000000000..613f8e193137c89b5a53dc8a4d130c987609de9e --- /dev/null +++ b/CVE-2025-55752-pre-Cleanups.patch @@ -0,0 +1,78 @@ +From 57d6010f1c520eba800f7941820c05360fd2b05e Mon Sep 17 00:00:00 2001 +From: remm +Date: Sun, 16 Mar 2025 14:20:08 +0100 +Subject: [PATCH] Cleanups + +Origin: +https://github.com/apache/tomcat/commit/57d6010f1c520eba800f7941820c05360fd2b05e +https://github.com/apache/tomcat/commit/0aadfc3c8b62c072e01b021c88e7b28b193808b5 +--- + .../catalina/valves/rewrite/RewriteValve.java | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/java/org/apache/catalina/valves/rewrite/RewriteValve.java b/java/org/apache/catalina/valves/rewrite/RewriteValve.java +index 6eb01e5..2fc999b 100644 +--- a/java/org/apache/catalina/valves/rewrite/RewriteValve.java ++++ b/java/org/apache/catalina/valves/rewrite/RewriteValve.java +@@ -26,6 +26,7 @@ import java.nio.charset.StandardCharsets; + import java.util.ArrayList; + import java.util.List; + import java.util.Map; ++import java.util.Objects; + import java.util.StringTokenizer; + import java.util.concurrent.ConcurrentHashMap; + +@@ -191,7 +192,7 @@ public class RewriteValve extends ValveBase { + for (String mapConfiguration : mapsConfiguration) { + buffer.append(mapConfiguration).append("\r\n"); + } +- if (mapsConfiguration.size() > 0) { ++ if (!mapsConfiguration.isEmpty()) { + buffer.append("\r\n"); + } + for (RewriteRule rule : rules) { +@@ -226,11 +227,10 @@ public class RewriteValve extends ValveBase { + } + for (RewriteCond condition : conditions) { + if (containerLog.isTraceEnabled()) { +- RewriteCond cond = condition; +- containerLog.trace("Add condition " + cond.getCondPattern() + " test " + +- cond.getTestString() + " to rule with pattern " + rule.getPatternString() + ++ containerLog.trace("Add condition " + condition.getCondPattern() + " test " + ++ condition.getTestString() + " to rule with pattern " + rule.getPatternString() + + " and substitution " + rule.getSubstitutionString() + +- (cond.isOrnext() ? " [OR]" : "") + (cond.isNocase() ? " [NC]" : "")); ++ (condition.isOrnext() ? " [OR]" : "") + (condition.isNocase() ? " [NC]" : "")); + } + rule.addCondition(condition); + } +@@ -314,7 +314,7 @@ public class RewriteValve extends ValveBase { + RewriteRule rule = rules[i]; + CharSequence test = (rule.isHost()) ? host : urlDecoded; + CharSequence newtest = rule.evaluate(test, resolver); +- if (newtest != null && !test.toString().equals(newtest.toString())) { ++ if (newtest != null && !Objects.equals(test.toString(), newtest.toString())) { + if (containerLog.isTraceEnabled()) { + containerLog.trace( + "Rewrote " + test + " as " + newtest + " with rule pattern " + rule.getPatternString()); +@@ -371,7 +371,7 @@ public class RewriteValve extends ValveBase { + + StringBuilder urlStringEncoded = + new StringBuilder(URLEncoder.DEFAULT.encode(urlStringDecoded, uriCharset)); +- if (!qsd && originalQueryStringEncoded != null && originalQueryStringEncoded.length() > 0) { ++ if (!qsd && originalQueryStringEncoded != null && !originalQueryStringEncoded.isEmpty()) { + if (rewrittenQueryStringDecoded == null) { + urlStringEncoded.append('?'); + urlStringEncoded.append(originalQueryStringEncoded); +@@ -505,7 +505,7 @@ public class RewriteValve extends ValveBase { + request.getCoyoteRequest().queryString().setChars(MessageBytes.EMPTY_CHAR_ARRAY, 0, 0); + chunk = request.getCoyoteRequest().queryString().getCharChunk(); + chunk.append(URLEncoder.QUERY.encode(queryStringDecoded, uriCharset)); +- if (qsa && originalQueryStringEncoded != null && originalQueryStringEncoded.length() > 0) { ++ if (qsa && originalQueryStringEncoded != null && !originalQueryStringEncoded.isEmpty()) { + chunk.append('&'); + chunk.append(originalQueryStringEncoded); + } +-- +2.51.1 + diff --git a/CVE-2025-55752.patch b/CVE-2025-55752.patch new file mode 100644 index 0000000000000000000000000000000000000000..e0e230656b6cef080c6a4e32340712ef42d3e5d4 --- /dev/null +++ b/CVE-2025-55752.patch @@ -0,0 +1,265 @@ +From b5042622b8b78340ae65403c55dcb9c7416924df Mon Sep 17 00:00:00 2001 +From: Mark Thomas +Date: Fri, 29 Aug 2025 14:42:14 +0100 +Subject: [PATCH] Fix a couple of issues with QSA/QSD handling and associated + tests + +- Original query string was incorrectly retained when there was no new + query string and QSD was set +- QSD did not take precedence when QSA and QSD were both set + +Rename variables for consistency / ease of maintenance + +Origin: https://github.com/apache/tomcat/commit/b5042622b8b78340ae65403c55dcb9c7416924df +--- + .../catalina/valves/rewrite/RewriteValve.java | 35 ++++-- + .../catalina/startup/TomcatBaseTest.java | 2 +- + .../valves/rewrite/TestRewriteValve.java | 107 +++++++++++++++++- + webapps/docs/changelog.xml | 4 + + 4 files changed, 131 insertions(+), 17 deletions(-) + +diff --git a/java/org/apache/catalina/valves/rewrite/RewriteValve.java b/java/org/apache/catalina/valves/rewrite/RewriteValve.java +index 983ded208d1f..fb184d9d696b 100644 +--- a/java/org/apache/catalina/valves/rewrite/RewriteValve.java ++++ b/java/org/apache/catalina/valves/rewrite/RewriteValve.java +@@ -326,7 +326,7 @@ public void invoke(Request request, Response response) throws IOException, Servl + + // As long as MB isn't a char sequence or affiliated, this has to be converted to a string + Charset uriCharset = request.getConnector().getURICharset(); +- String originalQueryStringEncoded = request.getQueryString(); ++ String queryStringOriginalEncoded = request.getQueryString(); + MessageBytes urlMB = context ? request.getRequestPathMB() : request.getDecodedRequestURIMB(); + urlMB.toChars(); + CharSequence urlDecoded = urlMB.getCharChunk(); +@@ -427,10 +427,10 @@ public void invoke(Request request, Response response) throws IOException, Servl + StringBuilder urlStringEncoded = + new StringBuilder(REWRITE_DEFAULT_ENCODER.encode(urlStringRewriteEncoded, uriCharset)); + +- if (!qsd && originalQueryStringEncoded != null && !originalQueryStringEncoded.isEmpty()) { ++ if (!qsd && queryStringOriginalEncoded != null && !queryStringOriginalEncoded.isEmpty()) { + if (rewrittenQueryStringRewriteEncoded == null) { + urlStringEncoded.append('?'); +- urlStringEncoded.append(originalQueryStringEncoded); ++ urlStringEncoded.append(queryStringOriginalEncoded); + } else { + if (qsa) { + // if qsa is specified append the query +@@ -438,7 +438,7 @@ public void invoke(Request request, Response response) throws IOException, Servl + urlStringEncoded.append( + REWRITE_QUERY_ENCODER.encode(rewrittenQueryStringRewriteEncoded, uriCharset)); + urlStringEncoded.append('&'); +- urlStringEncoded.append(originalQueryStringEncoded); ++ urlStringEncoded.append(queryStringOriginalEncoded); + } else if (index == urlStringEncoded.length() - 1) { + // if the ? is the last character delete it, its only purpose was to + // prevent the rewrite module from appending the query string +@@ -554,24 +554,31 @@ public void invoke(Request request, Response response) throws IOException, Servl + + // Step 3. Complete the 2nd stage to encoding. + chunk.append(REWRITE_DEFAULT_ENCODER.encode(urlStringRewriteEncoded, uriCharset)); +- // Decoded and normalized URI +- // Rewriting may have denormalized the URL +- urlStringRewriteEncoded = RequestUtil.normalize(urlStringRewriteEncoded); ++ // Rewriting may have denormalized the URL and added encoded characters ++ // Decode then normalize ++ String urlStringRewriteDecoded = URLDecoder.decode(urlStringRewriteEncoded, uriCharset.name()); ++ urlStringRewriteDecoded = RequestUtil.normalize(urlStringRewriteDecoded); + request.getCoyoteRequest().decodedURI().setChars(MessageBytes.EMPTY_CHAR_ARRAY, 0, 0); + chunk = request.getCoyoteRequest().decodedURI().getCharChunk(); + if (context) { + // This is decoded and normalized + chunk.append(request.getServletContext().getContextPath()); + } +- chunk.append(URLDecoder.decode(urlStringRewriteEncoded, uriCharset.name())); +- // Set the new Query if there is one +- if (queryStringRewriteEncoded != null) { ++ chunk.append(urlStringRewriteDecoded); ++ // Set the new Query String ++ if (queryStringRewriteEncoded == null) { ++ // No new query string. Therefore the original is retained unless QSD is defined. ++ if (qsd) { ++ request.getCoyoteRequest().queryString().setChars(MessageBytes.EMPTY_CHAR_ARRAY, 0, 0); ++ } ++ } else { ++ // New query string. Therefore the original is dropped unless QSA is defined (and QSD is not). + request.getCoyoteRequest().queryString().setChars(MessageBytes.EMPTY_CHAR_ARRAY, 0, 0); + chunk = request.getCoyoteRequest().queryString().getCharChunk(); + chunk.append(REWRITE_QUERY_ENCODER.encode(queryStringRewriteEncoded, uriCharset)); +- if (qsa && originalQueryStringEncoded != null && !originalQueryStringEncoded.isEmpty()) { ++ if (qsa && queryStringOriginalEncoded != null && !queryStringOriginalEncoded.isEmpty()) { + chunk.append('&'); +- chunk.append(originalQueryStringEncoded); ++ chunk.append(queryStringOriginalEncoded); + } + } + // Set the new host if it changed +@@ -666,6 +673,10 @@ public static Object parse(String line) { + while (flagsTokenizer.hasMoreElements()) { + parseRuleFlag(line, rule, flagsTokenizer.nextToken()); + } ++ // If QSD and QSA are present, QSD always takes precedence ++ if (rule.isQsdiscard()) { ++ rule.setQsappend(false); ++ } + } + return rule; + } else if (token.equals("RewriteMap")) { +diff --git a/test/org/apache/catalina/startup/TomcatBaseTest.java b/test/org/apache/catalina/startup/TomcatBaseTest.java +index 160360d75395..683938714dd4 100644 +--- a/test/org/apache/catalina/startup/TomcatBaseTest.java ++++ b/test/org/apache/catalina/startup/TomcatBaseTest.java +@@ -553,7 +553,7 @@ public void service(HttpServletRequest request, + value.append(';'); + } + } +- out.println("PARAM/" + name + ": " + value); ++ out.println("PARAM:" + name + ": " + value); + } + + out.println("SESSION-REQUESTED-ID: " + +diff --git a/test/org/apache/catalina/valves/rewrite/TestRewriteValve.java b/test/org/apache/catalina/valves/rewrite/TestRewriteValve.java +index 458349ce7606..7c81e9384f10 100644 +--- a/test/org/apache/catalina/valves/rewrite/TestRewriteValve.java ++++ b/test/org/apache/catalina/valves/rewrite/TestRewriteValve.java +@@ -301,17 +301,112 @@ public void testNonAsciiPathRedirect() throws Exception { + } + + @Test +- public void testQueryString() throws Exception { ++ public void testQueryStringTargetOnly() throws Exception { ++ doTestRewrite("RewriteRule ^/b/(.*) /c/$1?je=2", "/b/id=1", "/c/id=1", "je=2"); ++ } ++ ++ @Test ++ public void testQueryStringTargetOnlyQSA() throws Exception { ++ doTestRewrite("RewriteRule ^/b/(.*) /c/$1?je=2 [QSA]", "/b/id=1", "/c/id=1", "je=2"); ++ } ++ ++ @Test ++ public void testQueryStringTargetOnlyQSD() throws Exception { ++ doTestRewrite("RewriteRule ^/b/(.*) /c/$1?je=2 [QSD]", "/b/id=1", "/c/id=1", "je=2"); ++ } ++ ++ @Test ++ public void testQueryStringTargetOnlyQSAQSD() throws Exception { ++ doTestRewrite("RewriteRule ^/b/(.*) /c/$1?je=2 [QSA,QSD]", "/b/id=1", "/c/id=1", "je=2"); ++ } ++ ++ @Test ++ public void testQueryStringTargetOnlyQS() throws Exception { + doTestRewrite("RewriteRule ^/b/(.*) /c?$1", "/b/id=1", "/c", "id=1"); + } + ++ @Test ++ public void testQueryStringTargetOnlyQSAQS() throws Exception { ++ doTestRewrite("RewriteRule ^/b/(.*) /c?$1 [QSA]", "/b/id=1", "/c", "id=1"); ++ } ++ ++ @Test ++ public void testQueryStringTargetOnlyQSDQS() throws Exception { ++ doTestRewrite("RewriteRule ^/b/(.*) /c?$1 [QSD]", "/b/id=1", "/c", "id=1"); ++ } ++ ++ @Test ++ public void testQueryStringTargetOnlyQSAQSDQS() throws Exception { ++ doTestRewrite("RewriteRule ^/b/(.*) /c?$1 [QSA,QSD]", "/b/id=1", "/c", "id=1"); ++ } ++ ++ @Test ++ public void testQueryStringSourceOnly() throws Exception { ++ doTestRewrite("RewriteRule ^/b/(.*) /c/$1", "/b/d?id=1", "/c/d", "id=1"); ++ } ++ ++ @Test ++ public void testQueryStringSourceOnlyQSA() throws Exception { ++ doTestRewrite("RewriteRule ^/b/(.*) /c/$1 [QSA]", "/b/d?id=1", "/c/d", "id=1"); ++ } ++ ++ @Test ++ public void testQueryStringSourceOnlyQSD() throws Exception { ++ doTestRewrite("RewriteRule ^/b/(.*) /c/$1 [QSD]", "/b/d?id=1", "/c/d", null); ++ } ++ ++ @Test ++ public void testQueryStringSourceOnlyQSAQSD() throws Exception { ++ doTestRewrite("RewriteRule ^/b/(.*) /c/$1 [QSA,QSD]", "/b/d?id=1", "/c/d", null); ++ } ++ ++ @Test ++ public void testQueryStringSourceAndTarget() throws Exception { ++ doTestRewrite("RewriteRule ^/b/(.*) /c/$1?id=1", "/b/d?je=2", "/c/d", "id=1"); ++ } ++ ++ @Test ++ public void testQueryStringSourceAndTargetQSA() throws Exception { ++ doTestRewrite("RewriteRule ^/b/(.*) /c/$1?id=1 [QSA]", "/b/d?je=2", "/c/d", "id=1&je=2"); ++ } ++ ++ @Test ++ public void testQueryStringSourceAndTargetQSD() throws Exception { ++ doTestRewrite("RewriteRule ^/b/(.*) /c/$1?id=1 [QSD]", "/b/d?je=2", "/c/d", "id=1"); ++ } ++ ++ @Test ++ public void testQueryStringSourceAndTargetQSAQSD() throws Exception { ++ doTestRewrite("RewriteRule ^/b/(.*) /c/$1?id=1 [QSA,QSD]", "/b/d?je=2", "/c/d", "id=1"); ++ } ++ ++ @Test ++ public void testQueryStringEncoded01() throws Exception { ++ doTestRewrite("RewriteCond %{QUERY_STRING} a=(.*)\nRewriteRule ^/b.*$ /%1 [QSD]", "/b?a=c", "/c", null); ++ } ++ ++ @Test ++ public void testQueryStringEncoded02() throws Exception { ++ doTestRewrite("RewriteCond %{QUERY_STRING} a=(.*)\nRewriteRule ^/b.*$ /z/%1 [QSD]", "/b?a=%2e%2e%2fc%2faAbB", "/z/%2e%2e%2fc%2faAbB", null); ++ } ++ + @Test + public void testQueryStringRemove() throws Exception { +- doTestRewrite("RewriteRule ^/b/(.*) /c/$1?", "/b/d?=1", "/c/d", null); ++ doTestRewrite("RewriteRule ^/b/(.*) /c/$1?", "/b/d?id=1", "/c/d", null); + } + + @Test + public void testQueryStringRemove02() throws Exception { ++ doTestRewrite("RewriteRule ^/b/(.*) /c/$1 [QSD]", "/b/d?id=1", "/c/d", null); ++ } ++ ++ @Test ++ public void testQueryStringRemoveInvalid() throws Exception { ++ doTestRewrite("RewriteRule ^/b/(.*) /c/$1?", "/b/d?=1", "/c/d", null); ++ } ++ ++ @Test ++ public void testQueryStringRemoveInvalid02() throws Exception { + doTestRewrite("RewriteRule ^/b/(.*) /c/$1 [QSD]", "/b/d?=1", "/c/d", null); + } + +@@ -616,7 +711,7 @@ public void testUtf8FlagsRBNE() throws Exception { + public void testFlagsNC() throws Exception { + // https://bz.apache.org/bugzilla/show_bug.cgi?id=60116 + doTestRewrite("RewriteCond %{QUERY_STRING} a=([a-z]*) [NC]\n" + "RewriteRule .* - [E=X-Test:%1]", "/c?a=aAa", +- "/c", null, "aAa"); ++ "/c", "a=aAa", "aAa"); + } + + @Test +@@ -806,12 +901,16 @@ public void invoke(Request request, Response response) throws IOException, Servl + // were written into the request target + Assert.assertEquals(400, rc); + } else { ++ // If there is an expected URI, the request should be successful ++ Assert.assertEquals(200, rc); + String body = res.toString(); + RequestDescriptor requestDesc = SnoopResult.parse(body); + String requestURI = requestDesc.getRequestInfo("REQUEST-URI"); + Assert.assertEquals(expectedURI, requestURI); + +- if (expectedQueryString != null) { ++ if (expectedQueryString == null) { ++ Assert.assertTrue(requestDesc.getParams().isEmpty()); ++ } else { + String queryString = requestDesc.getRequestInfo("REQUEST-QUERY-STRING"); + Assert.assertEquals(expectedQueryString, queryString); + } diff --git a/CVE-2025-55754.patch b/CVE-2025-55754.patch new file mode 100644 index 0000000000000000000000000000000000000000..0383cd58aa9c9f4876848be6edfc0f0209ca9137 --- /dev/null +++ b/CVE-2025-55754.patch @@ -0,0 +1,257 @@ +From a03cabf3a36a42d27d8d997ed31f034f50ba6cd5 Mon Sep 17 00:00:00 2001 +From: Mark Thomas +Date: Mon, 18 Aug 2025 22:20:00 +0100 +Subject: [PATCH] Add escaping to logging output + +This aligns the other formatters with the JSON formatter + +Origin: https://github.com/apache/tomcat/commit/a03cabf3a36a42d27d8d997ed31f034f50ba6cd5 +--- + java/org/apache/juli/JdkLoggerFormatter.java | 4 +- + java/org/apache/juli/LogUtil.java | 64 ++++++++++++++ + java/org/apache/juli/OneLineFormatter.java | 4 +- + java/org/apache/juli/VerbatimFormatter.java | 7 +- + test/org/apache/juli/TestLogUtil.java | 93 ++++++++++++++++++++ + 5 files changed, 164 insertions(+), 8 deletions(-) + create mode 100644 java/org/apache/juli/LogUtil.java + create mode 100644 test/org/apache/juli/TestLogUtil.java + +diff --git a/java/org/apache/juli/JdkLoggerFormatter.java b/java/org/apache/juli/JdkLoggerFormatter.java +index 80489b9..65d44a4 100644 +--- a/java/org/apache/juli/JdkLoggerFormatter.java ++++ b/java/org/apache/juli/JdkLoggerFormatter.java +@@ -100,7 +100,7 @@ public class JdkLoggerFormatter extends Formatter { + } + + // Append the message +- buf.append(message); ++ buf.append(LogUtil.escape(message)); + + // Append stack trace if not null + if (t != null) { +@@ -110,7 +110,7 @@ public class JdkLoggerFormatter extends Formatter { + java.io.PrintWriter pw = new java.io.PrintWriter(sw); + t.printStackTrace(pw); + pw.close(); +- buf.append(sw.toString()); ++ buf.append(LogUtil.escape(sw.toString())); + } + + buf.append(System.lineSeparator()); +diff --git a/java/org/apache/juli/LogUtil.java b/java/org/apache/juli/LogUtil.java +new file mode 100644 +index 0000000..c7eb098 +--- /dev/null ++++ b/java/org/apache/juli/LogUtil.java +@@ -0,0 +1,64 @@ ++/* ++ * Licensed to the Apache Software Foundation (ASF) under one or more ++ * contributor license agreements. See the NOTICE file distributed with ++ * this work for additional information regarding copyright ownership. ++ * The ASF licenses this file to You under the Apache License, Version 2.0 ++ * (the "License"); you may not use this file except in compliance with ++ * the License. You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++package org.apache.juli; ++ ++public class LogUtil { ++ ++ private LogUtil() { ++ // Utility class. Hide default constructor ++ } ++ ++ ++ /** ++ * Escape a string so it can be displayed in a readable format. Characters that may not be printable in some/all of ++ * the contexts in which log messages will be viewed will be escaped using Java \\uNNNN escaping. ++ *

++ * All control characters are escaped apart from horizontal tab (\\u0009), new line (\\u000a) and carriage return ++ * (\\u000d). ++ * ++ * @param input The string to escape ++ * ++ * @return The escaped form of the input string ++ */ ++ @SuppressWarnings("null") // sb is not null when used ++ public static String escape(final String input) { ++ final int len = input.length(); ++ int i = 0; ++ int lastControl = -1; ++ StringBuilder sb = null; ++ while (i < len) { ++ char c = input.charAt(i); ++ if (Character.getType(c) == Character.CONTROL) { ++ if (!(c == '\t' || c == '\n' || c == '\r')) { ++ if (lastControl == -1) { ++ sb = new StringBuilder(len + 20); ++ } ++ sb.append(input.substring(lastControl + 1, i)); ++ sb.append(String.format("\\u%1$04x", Integer.valueOf(c))); ++ lastControl = i; ++ } ++ } ++ i++; ++ } ++ if (lastControl == -1) { ++ return input; ++ } else { ++ sb.append(input.substring(lastControl + 1, len)); ++ return sb.toString(); ++ } ++ } ++} +diff --git a/java/org/apache/juli/OneLineFormatter.java b/java/org/apache/juli/OneLineFormatter.java +index c48811a..b095d55 100644 +--- a/java/org/apache/juli/OneLineFormatter.java ++++ b/java/org/apache/juli/OneLineFormatter.java +@@ -147,7 +147,7 @@ public class OneLineFormatter extends Formatter { + + // Message + sb.append(' '); +- sb.append(formatMessage(record)); ++ sb.append(LogUtil.escape(formatMessage(record))); + + // New line for next record + sb.append(System.lineSeparator()); +@@ -158,7 +158,7 @@ public class OneLineFormatter extends Formatter { + PrintWriter pw = new IndentingPrintWriter(sw); + record.getThrown().printStackTrace(pw); + pw.close(); +- sb.append(sw.getBuffer()); ++ sb.append(LogUtil.escape(sw.toString())); + } + + return sb.toString(); +diff --git a/java/org/apache/juli/VerbatimFormatter.java b/java/org/apache/juli/VerbatimFormatter.java +index 1c90a0f..2653b18 100644 +--- a/java/org/apache/juli/VerbatimFormatter.java ++++ b/java/org/apache/juli/VerbatimFormatter.java +@@ -20,9 +20,9 @@ import java.util.logging.Formatter; + import java.util.logging.LogRecord; + + /** +- * Outputs the just the log message with no additional elements. Stack traces are not logged. Log messages are separated +- * by System.lineSeparator(). This is intended for use by access logs and the like that need complete +- * control over the output format. ++ * Outputs just the log message with no additional elements and no escaping. Stack traces are not logged. Log messages ++ * are separated by System.lineSeparator(). This is intended for use by access logs and the like that need ++ * complete control over the output format. + */ + public class VerbatimFormatter extends Formatter { + +@@ -31,5 +31,4 @@ public class VerbatimFormatter extends Formatter { + // Timestamp + New line for next record + return record.getMessage() + System.lineSeparator(); + } +- + } +diff --git a/test/org/apache/juli/TestLogUtil.java b/test/org/apache/juli/TestLogUtil.java +new file mode 100644 +index 0000000..753f7b9 +--- /dev/null ++++ b/test/org/apache/juli/TestLogUtil.java +@@ -0,0 +1,93 @@ ++/* ++ * Licensed to the Apache Software Foundation (ASF) under one or more ++ * contributor license agreements. See the NOTICE file distributed with ++ * this work for additional information regarding copyright ownership. ++ * The ASF licenses this file to You under the Apache License, Version 2.0 ++ * (the "License"); you may not use this file except in compliance with ++ * the License. You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++package org.apache.juli; ++ ++import org.junit.Assert; ++import org.junit.Test; ++ ++public class TestLogUtil { ++ ++ @Test ++ public void testEscapeForLoggingEmptyString() { ++ doTestEscapeForLogging(""); ++ } ++ ++ ++ @Test ++ public void testEscapeForLoggingNone() { ++ doTestEscapeForLogging("No escaping"); ++ } ++ ++ ++ @Test ++ public void testEscapeForLoggingControlStart() { ++ doTestEscapeForLogging("\u0006Text", "\\u0006Text"); ++ } ++ ++ ++ @Test ++ public void testEscapeForLoggingControlMiddle() { ++ doTestEscapeForLogging("Text\u0006Text", "Text\\u0006Text"); ++ } ++ ++ ++ @Test ++ public void testEscapeForLoggingControlEnd() { ++ doTestEscapeForLogging("Text\u0006", "Text\\u0006"); ++ } ++ ++ ++ @Test ++ public void testEscapeForLoggingControlOnly() { ++ doTestEscapeForLogging("\u0006", "\\u0006"); ++ } ++ ++ ++ @Test ++ public void testEscapeForLoggingControlsStart() { ++ doTestEscapeForLogging("\u0006\u0007Text", "\\u0006\\u0007Text"); ++ } ++ ++ ++ @Test ++ public void testEscapeForLoggingControlsMiddle() { ++ doTestEscapeForLogging("Text\u0006\u0007Text", "Text\\u0006\\u0007Text"); ++ } ++ ++ ++ @Test ++ public void testEscapeForLoggingControlsEnd() { ++ doTestEscapeForLogging("Text\u0006\u0007", "Text\\u0006\\u0007"); ++ } ++ ++ ++ @Test ++ public void testEscapeForLoggingControlsOnly() { ++ doTestEscapeForLogging("\u0006\u0007", "\\u0006\\u0007"); ++ } ++ ++ ++ private void doTestEscapeForLogging(String input) { ++ doTestEscapeForLogging(input, input); ++ } ++ ++ ++ private void doTestEscapeForLogging(String input, String expected) { ++ String result = LogUtil.escape(input); ++ Assert.assertEquals(expected, result); ++ } ++} +-- +2.51.1 + diff --git a/CVE-2025-61795.patch b/CVE-2025-61795.patch new file mode 100644 index 0000000000000000000000000000000000000000..a961b89a726eb3afd985eee79e5665174d9d98de --- /dev/null +++ b/CVE-2025-61795.patch @@ -0,0 +1,66 @@ +From afa422bd7ca1eef0f507259c682fd876494d9c3b Mon Sep 17 00:00:00 2001 +From: Mark Thomas +Date: Mon, 29 Sep 2025 17:50:43 +0100 +Subject: [PATCH] Explicitly clean up after failed multi-part upload + +Origin: https://github.com/apache/tomcat/commit/afa422bd7ca1eef0f507259c682fd876494d9c3b +--- + .../connector/LocalStrings.properties | 1 + + .../apache/catalina/connector/Request.java | 21 ++++++++++++++++++- + 2 files changed, 21 insertions(+), 1 deletion(-) + +diff --git a/java/org/apache/catalina/connector/LocalStrings.properties b/java/org/apache/catalina/connector/LocalStrings.properties +index c4951cf..92a1c61 100644 +--- a/java/org/apache/catalina/connector/LocalStrings.properties ++++ b/java/org/apache/catalina/connector/LocalStrings.properties +@@ -93,6 +93,7 @@ request.asyncNotSupported=A filter or servlet of the current chain does not supp + request.fragmentInDispatchPath=The fragment in dispatch path [{0}] has been removed + request.illegalWrap=The request wrapper must wrap the request obtained from getRequest() + request.notAsync=It is illegal to call this method if the current request is not in asynchronous mode (i.e. isAsyncStarted() returns false) ++request.partCleanup.failed=Unable to delete temporary file for uploaded part after multi-part processing failed + request.session.failed=Failed to load session [{0}] due to [{1}] + + requestFacade.nullRequest=The request object has been recycled and is no longer associated with this facade +diff --git a/java/org/apache/catalina/connector/Request.java b/java/org/apache/catalina/connector/Request.java +index e6168bb..acb2603 100644 +--- a/java/org/apache/catalina/connector/Request.java ++++ b/java/org/apache/catalina/connector/Request.java +@@ -2637,8 +2637,9 @@ public class Request implements HttpServletRequest { + upload.setFileCountMax(partLimit); + + parts = new ArrayList<>(); ++ List items = null; + try { +- List items = upload.parseRequest(new ServletRequestContext(this)); ++ items = upload.parseRequest(new ServletRequestContext(this)); + int maxPostSize = getConnector().getMaxPostSize(); + long postSize = 0; + Charset charset = getCharset(); +@@ -2688,6 +2689,24 @@ public class Request implements HttpServletRequest { + // addParameters() will set parseFailedReason + checkSwallowInput(); + partsParseException = e; ++ } finally { ++ /* ++ * GC will delete any temporary copies of uploaded files left in the work directory but if we know that the ++ * upload has failed then explicitly clean up now. ++ */ ++ if (!success) { ++ parts.clear(); ++ if (items != null) { ++ for (FileItem item : items) { ++ try { ++ item.delete(); ++ } catch (Throwable t) { ++ ExceptionUtils.handleThrowable(t); ++ log.warn(sm.getString("request.partCleanup.failed"), t); ++ } ++ } ++ } ++ } + } + } finally { + // This might look odd but is correct. setParseFailedReason() only +-- +2.51.1 + diff --git a/tomcat.spec b/tomcat.spec index 84c54e5d0d16b712757c127da3f2f32691f9720b..f9b1e12f9cca9fb29e4e1bb137c355849511962d 100644 --- a/tomcat.spec +++ b/tomcat.spec @@ -23,7 +23,7 @@ Name: tomcat Epoch: 1 Version: %{major_version}.%{minor_version}.%{micro_version} -Release: 8 +Release: 9 Summary: Apache Servlet/JSP Engine, RI for Servlet %{servletspec}/JSP %{jspspec} API License: Apache-2.0 @@ -54,18 +54,22 @@ Patch7: build-with-jdk-1.8.patch Patch8: CVE-2025-31650-1.patch Patch9: CVE-2025-31650-2.patch Patch10: CVE-2025-31650-3.patch -Patch11: CVE-2025-31651-1.patch -Patch12: CVE-2025-31651-2.patch -Patch13: CVE-2025-46701-1.patch -Patch14: CVE-2025-46701-2.patch -Patch15: CVE-2025-48988.patch -Patch16: CVE-2025-48976.patch -Patch17: CVE-2025-49125.patch -Patch18: CVE-2025-52434.patch -Patch19: CVE-2025-52520.patch -Patch20: CVE-2025-53506.patch -Patch21: CVE-2025-55668.patch -Patch22: CVE-2025-48989.patch +Patch11: CVE-2025-55752-pre-Cleanups.patch +Patch12: CVE-2025-31651-1.patch +Patch13: CVE-2025-31651-2.patch +Patch14: CVE-2025-46701-1.patch +Patch15: CVE-2025-46701-2.patch +Patch16: CVE-2025-48988.patch +Patch17: CVE-2025-48976.patch +Patch18: CVE-2025-49125.patch +Patch19: CVE-2025-52434.patch +Patch20: CVE-2025-52520.patch +Patch21: CVE-2025-53506.patch +Patch22: CVE-2025-55668.patch +Patch23: CVE-2025-48989.patch +Patch24: CVE-2025-55752.patch +Patch25: CVE-2025-55754.patch +Patch26: CVE-2025-61795.patch BuildArch: noarch @@ -432,6 +436,9 @@ fi %{appdir}/docs %changelog +* Tue Oct 28 2025 yaoxin <1024769339@qq.com> - 1:9.0.100-9 +- Fix CVE-2025-55752, CVE-2025-55754 and CVE-2025-61795 + * Fri Aug 15 2025 Yu Peng - 1:9.0.100-8 - Fix CVE-2025-48989