!118 Fix CVE-2024-21733,CVE-2023-24998,CVE-2023-28709,CVE-2023-42795

From: @wk333 
Reviewed-by: @starlet-dx 
Signed-off-by: @starlet-dx
This commit is contained in:
openeuler-ci-bot 2024-01-23 06:35:33 +00:00 committed by Gitee
commit c299570657
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
5 changed files with 1126 additions and 1 deletions

253
CVE-2023-24998.patch Normal file
View File

@ -0,0 +1,253 @@
From cf77cc545de0488fb89e24294151504a7432df74 Mon Sep 17 00:00:00 2001
From: Mark Thomas <markt@apache.org>
Date: Tue, 13 Dec 2022 17:55:34 +0000
Subject: [PATCH] Update packaged renamed fork of Commons File Upload
Origin: https://github.com/apache/tomcat/commit/cf77cc545de0488fb89e24294151504a7432df74
---
.../apache/catalina/connector/Request.java | 12 ++++-
.../apache/tomcat/util/http/Parameters.java | 4 ++
.../util/http/fileupload/FileUploadBase.java | 29 +++++++++++
.../impl/FileCountLimitExceededException.java | 50 +++++++++++++++++++
webapps/docs/changelog.xml | 8 +++
webapps/docs/config/ajp.xml | 15 +++---
webapps/docs/config/http.xml | 15 +++---
7 files changed, 119 insertions(+), 14 deletions(-)
create mode 100644 java/org/apache/tomcat/util/http/fileupload/impl/FileCountLimitExceededException.java
diff --git a/java/org/apache/catalina/connector/Request.java b/java/org/apache/catalina/connector/Request.java
index 889d5e7..87ab732 100644
--- a/java/org/apache/catalina/connector/Request.java
+++ b/java/org/apache/catalina/connector/Request.java
@@ -2769,8 +2769,9 @@ public class Request implements HttpServletRequest {
}
}
- Parameters parameters = coyoteRequest.getParameters();
- parameters.setLimit(getConnector().getMaxParameterCount());
+ int maxParameterCount = getConnector().getMaxParameterCount();
+ Parameters parameters = coyoteRequest.getParameters();
+ parameters.setLimit(maxParameterCount);
boolean success = false;
try {
@@ -2814,6 +2815,13 @@ public class Request implements HttpServletRequest {
upload.setFileItemFactory(factory);
upload.setFileSizeMax(mce.getMaxFileSize());
upload.setSizeMax(mce.getMaxRequestSize());
+ if (maxParameterCount > -1) {
+ // There is a limit. The limit for parts needs to be reduced by
+ // the number of parameters we have already parsed.
+ // Must be under the limit else parsing parameters would have
+ // triggered an exception.
+ upload.setFileCountMax(maxParameterCount - parameters.size());
+ }
parts = new ArrayList<>();
try {
diff --git a/java/org/apache/tomcat/util/http/Parameters.java b/java/org/apache/tomcat/util/http/Parameters.java
index 5bd9ba7..08c6ffd 100644
--- a/java/org/apache/tomcat/util/http/Parameters.java
+++ b/java/org/apache/tomcat/util/http/Parameters.java
@@ -124,6 +124,10 @@ public final class Parameters {
}
}
+ public int size() {
+ return parameterCount;
+ }
+
public void recycle() {
parameterCount = 0;
diff --git a/java/org/apache/tomcat/util/http/fileupload/FileUploadBase.java b/java/org/apache/tomcat/util/http/fileupload/FileUploadBase.java
index eb5a487..5506754 100644
--- a/java/org/apache/tomcat/util/http/fileupload/FileUploadBase.java
+++ b/java/org/apache/tomcat/util/http/fileupload/FileUploadBase.java
@@ -26,6 +26,7 @@ import java.util.Locale;
import java.util.Map;
import java.util.NoSuchElementException;
+import org.apache.tomcat.util.http.fileupload.impl.FileCountLimitExceededException;
import org.apache.tomcat.util.http.fileupload.MultipartStream.ItemInputStream;
import org.apache.tomcat.util.http.fileupload.util.Closeable;
import org.apache.tomcat.util.http.fileupload.util.FileItemHeadersImpl;
@@ -131,6 +132,12 @@ public abstract class FileUploadBase {
* to {@link #sizeMax}. A value of -1 indicates no maximum.
*/
private long fileSizeMax = -1;
+
+ /**
+ * The maximum permitted number of files that may be uploaded in a single
+ * request. A value of -1 indicates no maximum.
+ */
+ private long fileCountMax = -1;
/**
* The content encoding to use when reading part headers.
@@ -208,6 +215,24 @@ public abstract class FileUploadBase {
this.fileSizeMax = fileSizeMax;
}
+ /**
+ * Returns the maximum number of files allowed in a single request.
+ *
+ * @return The maximum number of files allowed in a single request.
+ */
+ public long getFileCountMax() {
+ return fileCountMax;
+ }
+
+ /**
+ * Sets the maximum number of files allowed per request/
+ *
+ * @param fileCountMax The new limit. {@code -1} means no limit.
+ */
+ public void setFileCountMax(long fileCountMax) {
+ this.fileCountMax = fileCountMax;
+ }
+
/**
* Retrieves the character encoding used when reading the headers of an
* individual part. When not specified, or <code>null</code>, the request
@@ -283,6 +308,10 @@ public abstract class FileUploadBase {
throw new NullPointerException("No FileItemFactory has been set.");
}
while (iter.hasNext()) {
+ if (items.size() == fileCountMax) {
+ // The next item will exceed the limit.
+ throw new FileCountLimitExceededException(ATTACHMENT, getFileCountMax());
+ }
final FileItemStream item = iter.next();
// Don't use getName() here to prevent an InvalidFileNameException.
final String fileName = ((FileItemIteratorImpl.FileItemStreamImpl) item).name;
diff --git a/java/org/apache/tomcat/util/http/fileupload/impl/FileCountLimitExceededException.java b/java/org/apache/tomcat/util/http/fileupload/impl/FileCountLimitExceededException.java
new file mode 100644
index 0000000..958f681
--- /dev/null
+++ b/java/org/apache/tomcat/util/http/fileupload/impl/FileCountLimitExceededException.java
@@ -0,0 +1,50 @@
+/*
+ * 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.tomcat.util.http.fileupload.impl;
+
+import org.apache.tomcat.util.http.fileupload.FileUploadException;
+
+/**
+ * This exception is thrown if a request contains more files than the specified
+ * limit.
+ */
+public class FileCountLimitExceededException extends FileUploadException {
+
+ private static final long serialVersionUID = 2408766352570556046L;
+
+ private final long limit;
+
+ /**
+ * Creates a new instance.
+ *
+ * @param message The detail message
+ * @param limit The limit that was exceeded
+ */
+ public FileCountLimitExceededException(final String message, final long limit) {
+ super(message);
+ this.limit = limit;
+ }
+
+ /**
+ * Retrieves the limit that was exceeded.
+ *
+ * @return The limit that was exceeded by the request
+ */
+ public long getLimit() {
+ return limit;
+ }
+}
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 835b0d0..0268d87 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -44,6 +44,14 @@
They eventually become mixed with the numbered issues. (I.e., numbered
issues do not "pop up" wrt. others).
-->
+ <subsection name="Other">
+ <changelog>
+ <update>
+ Update the internal fork of Apache Commons FileUpload to 34eb241
+ (2023-01-03, 2.0-SNAPSHOT). (markt)
+ </update>
+ </changelog>
+ </subsection>
<section name="Tomcat 9.0.10 (markt)">
<subsection name="Catalina">
<changelog>
diff --git a/webapps/docs/config/ajp.xml b/webapps/docs/config/ajp.xml
index 622e7ca..38c5269 100644
--- a/webapps/docs/config/ajp.xml
+++ b/webapps/docs/config/ajp.xml
@@ -114,12 +114,15 @@
</attribute>
<attribute name="maxParameterCount" required="false">
- <p>The maximum number of parameter and value pairs (GET plus POST) which
- will be automatically parsed by the container. Parameter and value pairs
- beyond this limit will be ignored. A value of less than 0 means no limit.
- If not specified, a default of 10000 is used. Note that
- <code>FailedRequestFilter</code> <a href="filter.html">filter</a> can be
- used to reject requests that hit the limit.</p>
+ <p>The maximum total number of request parameters (including uploaded
+ files) obtained from the query string and, for POST requests, the request
+ body if the content type is
+ <code>application/x-www-form-urlencoded</code> or
+ <code>multipart/form-data</code>. Request parameters beyond this limit
+ will be ignored. A value of less than 0 means no limit. If not specified,
+ a default of 10000 is used. Note that <code>FailedRequestFilter</code>
+ <a href="filter.html">filter</a> can be used to reject requests that
+ exceed the limit.</p>
</attribute>
<attribute name="maxPostSize" required="false">
diff --git a/webapps/docs/config/http.xml b/webapps/docs/config/http.xml
index 3902c9a..52ad063 100644
--- a/webapps/docs/config/http.xml
+++ b/webapps/docs/config/http.xml
@@ -111,12 +111,15 @@
</attribute>
<attribute name="maxParameterCount" required="false">
- <p>The maximum number of parameter and value pairs (GET plus POST) which
- will be automatically parsed by the container. Parameter and value pairs
- beyond this limit will be ignored. A value of less than 0 means no limit.
- If not specified, a default of 10000 is used. Note that
- <code>FailedRequestFilter</code> <a href="filter.html">filter</a> can be
- used to reject requests that hit the limit.</p>
+ <p>The maximum total number of request parameters (including uploaded
+ files) obtained from the query string and, for POST requests, the request
+ body if the content type is
+ <code>application/x-www-form-urlencoded</code> or
+ <code>multipart/form-data</code>. Request parameters beyond this limit
+ will be ignored. A value of less than 0 means no limit. If not specified,
+ a default of 10000 is used. Note that <code>FailedRequestFilter</code>
+ <a href="filter.html">filter</a> can be used to reject requests that
+ exceed the limit.</p>
</attribute>
<attribute name="maxPostSize" required="false">
--
2.33.0

35
CVE-2023-28709.patch Normal file
View File

@ -0,0 +1,35 @@
From fbd81421629afe8b8a3922d59020cde81caea861 Mon Sep 17 00:00:00 2001
From: Mark Thomas <markt@apache.org>
Date: Tue, 11 Apr 2023 16:41:44 +0100
Subject: [PATCH] Fix parameter counting logic
Origin: https://github.com/apache/tomcat/commit/fbd81421629afe8b8a3922d59020cde81caea861
---
java/org/apache/tomcat/util/http/Parameters.java | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/java/org/apache/tomcat/util/http/Parameters.java b/java/org/apache/tomcat/util/http/Parameters.java
index 08c6ffd..a19453d 100644
--- a/java/org/apache/tomcat/util/http/Parameters.java
+++ b/java/org/apache/tomcat/util/http/Parameters.java
@@ -205,14 +205,14 @@ public final class Parameters {
return;
}
- parameterCount ++;
- if (limit > -1 && parameterCount > limit) {
+ if (limit > -1 && parameterCount >= limit) {
// Processing this parameter will push us over the limit. ISE is
// what Request.parseParts() uses for requests that are too big
setParseFailedReason(FailReason.TOO_MANY_PARAMETERS);
throw new IllegalStateException(sm.getString(
"parameters.maxCountFail", Integer.valueOf(limit)));
}
+ parameterCount ++;
ArrayList<String> values = paramHashValues.get(key);
if (values == null) {
--
2.33.0

251
CVE-2023-42795.patch Normal file
View File

@ -0,0 +1,251 @@
From 44d05d75d696ca10ce251e4e370511e38f20ae75 Mon Sep 17 00:00:00 2001
From: Mark Thomas <markt@apache.org>
Date: Thu, 5 Oct 2023 20:52:46 +0100
Subject: [PATCH] Improve handling of failures during recycle() methods
Origin: https://github.com/apache/tomcat/commit/44d05d75d696ca10ce251e4e370511e38f20ae75
---
.../catalina/connector/LocalStrings.properties | 1 +
java/org/apache/catalina/connector/Request.java | 7 ++++---
.../catalina/core/ApplicationHttpRequest.java | 16 ++++++++++++----
.../apache/catalina/core/LocalStrings.properties | 1 +
.../catalina/core/LocalStrings_es.properties | 2 ++
.../catalina/core/LocalStrings_fr.properties | 1 +
.../catalina/core/LocalStrings_ja.properties | 1 +
.../org/apache/tomcat/util/buf/B2CConverter.java | 11 ++++++++++-
.../org/apache/tomcat/util/buf/C2BConverter.java | 15 ++++++++++++++-
.../tomcat/util/buf/LocalStrings.properties | 3 +++
10 files changed, 49 insertions(+), 9 deletions(-)
diff --git a/java/org/apache/catalina/connector/LocalStrings.properties b/java/org/apache/catalina/connector/LocalStrings.properties
index 86c6487..596805b 100644
--- a/java/org/apache/catalina/connector/LocalStrings.properties
+++ b/java/org/apache/catalina/connector/LocalStrings.properties
@@ -47,6 +47,7 @@ coyoteRequest.setAttribute.namenull=Cannot call setAttribute with a null name
coyoteRequest.attributeEvent=Exception thrown by attributes event listener
coyoteRequest.parseParameters=Exception thrown whilst processing POSTed parameters
coyoteRequest.postTooLarge=Parameters were not parsed because the size of the posted data was too big. Use the maxPostSize attribute of the connector to resolve this if the application should accept large POSTs.
+coyoteRequest.deletePartFailed=Failed to deleted temporary file used for part [{0}]
coyoteRequest.chunkedPostTooLarge=Parameters were not parsed because the size of the posted data was too big. Because this request was a chunked request, it could not be processed further. Use the maxPostSize attribute of the connector to resolve this if the application should accept large POSTs.
coyoteRequest.alreadyAuthenticated=This request has already been authenticated
coyoteRequest.authenticate.ise=Cannot call authenticate() after the response has been committed
diff --git a/java/org/apache/catalina/connector/Request.java b/java/org/apache/catalina/connector/Request.java
index 889d5e7..de53769 100644
--- a/java/org/apache/catalina/connector/Request.java
+++ b/java/org/apache/catalina/connector/Request.java
@@ -465,8 +465,9 @@ public class Request implements HttpServletRequest {
for (Part part: parts) {
try {
part.delete();
- } catch (IOException ignored) {
- // ApplicationPart.delete() never throws an IOEx
+ } catch (Throwable t) {
+ ExceptionUtils.handleThrowable(t);
+ log.warn(sm.getString("coyoteRequest.deletePartFailed", part.getName()), t);
}
}
parts = null;
@@ -518,8 +519,8 @@ public class Request implements HttpServletRequest {
asyncSupported = null;
if (asyncContext!=null) {
asyncContext.recycle();
+ asyncContext = null;
}
- asyncContext = null;
}
diff --git a/java/org/apache/catalina/core/ApplicationHttpRequest.java b/java/org/apache/catalina/core/ApplicationHttpRequest.java
index fc3a1d6..0b5b4f5 100644
--- a/java/org/apache/catalina/core/ApplicationHttpRequest.java
+++ b/java/org/apache/catalina/core/ApplicationHttpRequest.java
@@ -29,6 +29,8 @@ import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
+import java.util.Arrays;
+import java.util.HashMap;
import javax.servlet.DispatcherType;
import javax.servlet.RequestDispatcher;
@@ -48,9 +50,12 @@ import org.apache.catalina.Session;
import org.apache.catalina.connector.RequestFacade;
import org.apache.catalina.util.ParameterMap;
import org.apache.catalina.util.RequestUtil;
+import org.apache.catalina.util.URLEncoder;
+import org.apache.tomcat.util.ExceptionUtils;
import org.apache.tomcat.util.buf.B2CConverter;
import org.apache.tomcat.util.buf.MessageBytes;
import org.apache.tomcat.util.http.Parameters;
+import org.apache.tomcat.util.res.StringManager;
/**
@@ -70,9 +75,7 @@ import org.apache.tomcat.util.http.Parameters;
*/
class ApplicationHttpRequest extends HttpServletRequestWrapper {
-
- // ------------------------------------------------------- Static Variables
-
+ private static final StringManager sm = StringManager.getManager(ApplicationHttpRequest.class);
/**
* The set of attribute names that are special for request dispatchers.
@@ -626,7 +629,12 @@ class ApplicationHttpRequest extends HttpServletRequestWrapper {
*/
public void recycle() {
if (session != null) {
- session.endAccess();
+ try {
+ session.endAccess();
+ } catch (Throwable t) {
+ ExceptionUtils.handleThrowable(t);
+ context.getLogger().warn(sm.getString("applicationHttpRequest.sessionEndAccessFail"), t);
+ }
}
}
diff --git a/java/org/apache/catalina/core/LocalStrings.properties b/java/org/apache/catalina/core/LocalStrings.properties
index c5b55b1..0e17e3c 100644
--- a/java/org/apache/catalina/core/LocalStrings.properties
+++ b/java/org/apache/catalina/core/LocalStrings.properties
@@ -55,6 +55,7 @@ applicationFilterConfig.release=Failed to destroy the filter named [{0}] of type
applicationFilterRegistration.nullInitParam=Unable to set initialisation parameter for filter due to null name and/or value. Name [{0}], Value [{1}]
applicationFilterRegistration.nullInitParams=Unable to set initialisation parameters for filter due to null name and/or value. Name [{0}], Value [{1}]
+applicationHttpRequest.sessionEndAccessFail=Exception triggered ending access to session while recycling request
applicationPushBuilder.methodInvalid=The HTTP method for a push request must be both cacheable and safe but [{0}] is not
applicationPushBuilder.methodNotToken=HTTP methods must be tokens but [{0}] contains a non-token character
applicationPushBuilder.noCoyoteRequest=Unable to find the underlying Coyote request object (which is required to create a push request) from the request of type [{0}]
diff --git a/java/org/apache/catalina/core/LocalStrings_es.properties b/java/org/apache/catalina/core/LocalStrings_es.properties
index f138d17..e6a9ab2 100644
--- a/java/org/apache/catalina/core/LocalStrings_es.properties
+++ b/java/org/apache/catalina/core/LocalStrings_es.properties
@@ -43,6 +43,8 @@ applicationFilterConfig.jmxUnregister = Se ha completado el desregistro JMX para
applicationFilterConfig.jmxUnregisterFail = Ha fallado el desregistro JMX para el filtro del tipo [{0}] y nombre [{1}]
applicationFilterRegistration.nullInitParam = No puedo poner el par\u00E1metro de inicializaci\u00F3n para el filtro debido a un nombre nulo y/o valor. Nombre [{0}], Valor [{1}]
applicationFilterRegistration.nullInitParams = No puedo poner los par\u00E1metros de inicializaci\u00F3n para el filtro debido a un nombre nulo y/o valor. Nombre [{0}], Valor [{1}]
+applicationHttpRequest.sessionEndAccessFail=Excepción disparada acabando acceso a sesión mientras se reciclaba el requerimiento
+
applicationServletRegistration.setServletSecurity.iae = Se ha especificado restricci\u00F3n Null para el servlet [{0}] desplegado en el contexto con el nombre [{1}]
applicationServletRegistration.setServletSecurity.ise = No se pueden a\u00F1adir restricciones de seguridad al servlet [{0}] desplegado en el contexto con el nombre [{1}] ya que el contexto ya ha sido inicializado.
aprListener.aprInit = La biblioteca nativa de Apache Tomcat basada en ARP que permite un rendimiento \u00F3ptimo en entornos de desarrollo no ha sido hallada en java.library.path: [{0}]
diff --git a/java/org/apache/catalina/core/LocalStrings_fr.properties b/java/org/apache/catalina/core/LocalStrings_fr.properties
index dfc1cf7..91ead47 100644
--- a/java/org/apache/catalina/core/LocalStrings_fr.properties
+++ b/java/org/apache/catalina/core/LocalStrings_fr.properties
@@ -59,6 +59,7 @@ standardContext.startFailed=Erreur de d\u00e9marrage du contexte [{0}] suite aux
standardContext.startingContext=Exception lors du d\u00e9marrage du contexte [{0}]
standardContext.stoppingContext=Exception \u00e0 l''arr\u00eat du Context [{0}]
standardContext.resourcesStart=Erreur lors du d\u00e9marrage des ressources statiques
+applicationHttpRequest.sessionEndAccessFail=Exception lancée durant l'arrêt de l'accès à la session durant le recyclage de la requête
standardContext.urlPattern.patternWarning=ATTENTION: Le mod\u00e8le (pattern) URL [{0}] doit commencer par un ''/'' dans l''API Servlet 2.4
standardEngine.noHost=Aucune h\u00f4te (host) ne correspond au nom de serveur [{0}]
standardEngine.notHost=Le fils d''un moteur (child of an Engine) doit \u00eatre un h\u00f4te
diff --git a/java/org/apache/catalina/core/LocalStrings_ja.properties b/java/org/apache/catalina/core/LocalStrings_ja.properties
index d34d598..ae85dd4 100644
--- a/java/org/apache/catalina/core/LocalStrings_ja.properties
+++ b/java/org/apache/catalina/core/LocalStrings_ja.properties
@@ -66,6 +66,7 @@ standardEngine.notParent=\u30a8\u30f3\u30b8\u30f3\u306f\u89aa\u306e\u30b3\u30f3\
standardHost.clientAbort=\u30ea\u30e2\u30fc\u30c8\u30af\u30e9\u30a4\u30a2\u30f3\u30c8\u304c\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u4e2d\u6b62\u3057\u307e\u3057\u305f, IOException: [{0}]
standardHost.invalidErrorReportValveClass=\u6307\u5b9a\u3055\u308c\u305f\u30a8\u30e9\u30fc\u30ea\u30dd\u30fc\u30c8\u30d0\u30eb\u30d6\u30af\u30e9\u30b9\u3092\u30ed\u30fc\u30c9\u3067\u304d\u307e\u305b\u3093: [{0}]
standardHost.noContext=\u3053\u306e\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u51e6\u7406\u3059\u308b\u305f\u3081\u306b\u8a2d\u5b9a\u3055\u308c\u305f\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u304c\u3042\u308a\u307e\u305b\u3093
+applicationHttpRequest.sessionEndAccessFail=リクエストの再利用中に行ったセッションへのアクセス終了処理で例外が送出されました。
standardHost.notContext=\u30db\u30b9\u30c8\u306e\u5b50\u4f9b\u306f\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u3067\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093
standardHost.nullName=\u30db\u30b9\u30c8\u540d\u304c\u5fc5\u8981\u3067\u3059
standardService.start.name=\u30b5\u30fc\u30d3\u30b9 [{0}] \u3092\u8d77\u52d5\u3057\u307e\u3059
diff --git a/java/org/apache/tomcat/util/buf/B2CConverter.java b/java/org/apache/tomcat/util/buf/B2CConverter.java
index f046ad7..1e3e1f4 100644
--- a/java/org/apache/tomcat/util/buf/B2CConverter.java
+++ b/java/org/apache/tomcat/util/buf/B2CConverter.java
@@ -27,6 +27,9 @@ import java.nio.charset.CodingErrorAction;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Locale;
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.util.ExceptionUtils;
import java.util.Map;
import org.apache.tomcat.util.res.StringManager;
@@ -35,6 +38,7 @@ import org.apache.tomcat.util.res.StringManager;
* NIO based character decoder.
*/
public class B2CConverter {
+ private static final Log log = LogFactory.getLog(B2CConverter.class);
private static final StringManager sm = StringManager.getManager(B2CConverter.class);
@@ -120,7 +124,12 @@ public class B2CConverter {
* Reset the decoder state.
*/
public void recycle() {
- decoder.reset();
+ try {
+ decoder.reset();
+ } catch (Throwable t) {
+ ExceptionUtils.handleThrowable(t);
+ log.warn(sm.getString("b2cConverter.decoderResetFail", decoder.charset()), t);
+ }
leftovers.position(0);
}
diff --git a/java/org/apache/tomcat/util/buf/C2BConverter.java b/java/org/apache/tomcat/util/buf/C2BConverter.java
index e5062de..f3b4dd7 100644
--- a/java/org/apache/tomcat/util/buf/C2BConverter.java
+++ b/java/org/apache/tomcat/util/buf/C2BConverter.java
@@ -24,11 +24,19 @@ import java.nio.charset.CharsetEncoder;
import java.nio.charset.CoderResult;
import java.nio.charset.CodingErrorAction;
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.util.ExceptionUtils;
+import org.apache.tomcat.util.res.StringManager;
+
/**
* NIO based character encoder.
*/
public final class C2BConverter {
+ private static final Log log = LogFactory.getLog(C2BConverter.class);
+ private static final StringManager sm = StringManager.getManager(C2BConverter.class);
+
private final CharsetEncoder encoder;
private ByteBuffer bb = null;
private CharBuffer cb = null;
@@ -50,7 +58,12 @@ public final class C2BConverter {
* Reset the encoder state.
*/
public void recycle() {
- encoder.reset();
+ try {
+ encoder.reset();
+ } catch (Throwable t) {
+ ExceptionUtils.handleThrowable(t);
+ log.warn(sm.getString("c2bConverter.decoderResetFail", encoder.charset()), t);
+ }
leftovers.position(0);
}
diff --git a/java/org/apache/tomcat/util/buf/LocalStrings.properties b/java/org/apache/tomcat/util/buf/LocalStrings.properties
index c8a8d3b..574f6c2 100644
--- a/java/org/apache/tomcat/util/buf/LocalStrings.properties
+++ b/java/org/apache/tomcat/util/buf/LocalStrings.properties
@@ -13,9 +13,12 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+b2cConverter.decoderResetFail=Failed to reset instance of decoder for character set [{0}]
b2cConverter.unknownEncoding=The character encoding [{0}] is not supported
c2bConverter.recycleFailed=Failed to recycle the C2B Converter. Creating new BufferedWriter, WriteConvertor and IntermediateOutputStream.
+c2bConverter.encoderResetFail=Failed to reset instance of encoder for character set [{0}]
+
hexUtils.fromHex.oddDigits=The input must consist of an even number of hex digits
hexUtils.fromHex.nonHex=The input must consist only of hex digits
--
2.33.0

579
CVE-2024-21733.patch Normal file
View File

@ -0,0 +1,579 @@
From ce4b154e7b48f66bd98858626347747cd2514311 Mon Sep 17 00:00:00 2001
From: Mark Thomas <markt@apache.org>
Date: Thu, 18 Feb 2021 16:41:57 +0000
Subject: [PATCH] Ensure ReadListener.onError() is fired if client drops the
connection
Origin:
https://github.com/apache/tomcat/commit/659b28c00d94e2a9049e0a8ac1e02bd4d36dd005
https://github.com/apache/tomcat/commit/f562edd3302866f34c0ca9fa97f6ff414450f1ae
https://github.com/apache/tomcat/commit/918146f9d04af67d904b47c440acaab14380521b
https://github.com/apache/tomcat/commit/504445cd2c618fb1edbfeda62e07e1c29b4d285c
https://github.com/apache/tomcat/commit/ce4b154e7b48f66bd98858626347747cd2514311
---
.../catalina/core/StandardWrapperValve.java | 2 +
.../coyote/http11/Http11InputBuffer.java | 43 +++-
.../coyote/http11/Http11OutputBuffer.java | 15 +-
.../catalina/core/TestAsyncContextImpl.java | 172 +++++++++++++++-
.../nonblocking/TestNonBlockingAPI.java | 192 ++++++++++++++++++
5 files changed, 412 insertions(+), 12 deletions(-)
diff --git a/java/org/apache/catalina/core/StandardWrapperValve.java b/java/org/apache/catalina/core/StandardWrapperValve.java
index 27f136a..89f5915 100644
--- a/java/org/apache/catalina/core/StandardWrapperValve.java
+++ b/java/org/apache/catalina/core/StandardWrapperValve.java
@@ -29,6 +29,7 @@ import javax.servlet.ServletException;
import javax.servlet.UnavailableException;
import javax.servlet.http.HttpServletResponse;
+import org.apache.catalina.Container;
import org.apache.catalina.Context;
import org.apache.catalina.Globals;
import org.apache.catalina.LifecycleException;
@@ -174,6 +175,7 @@ final class StandardWrapperValve
// Call the filter chain for this request
// NOTE: This also calls the servlet's service() method
+ Container container = this.container;
try {
if ((servlet != null) && (filterChain != null)) {
// Swallow output if needed
diff --git a/java/org/apache/coyote/http11/Http11InputBuffer.java b/java/org/apache/coyote/http11/Http11InputBuffer.java
index 27392d4..db596b4 100644
--- a/java/org/apache/coyote/http11/Http11InputBuffer.java
+++ b/java/org/apache/coyote/http11/Http11InputBuffer.java
@@ -22,6 +22,7 @@ import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
+import org.apache.coyote.CloseNowException;
import org.apache.coyote.InputBuffer;
import org.apache.coyote.Request;
import org.apache.juli.logging.Log;
@@ -382,10 +383,6 @@ public class Http11InputBuffer implements InputBuffer, ApplicationBufferHandler
parsingRequestLineStart = byteBuffer.position();
parsingRequestLinePhase = 2;
- if (log.isDebugEnabled()) {
- log.debug("Received ["
- + new String(byteBuffer.array(), byteBuffer.position(), byteBuffer.remaining(), StandardCharsets.ISO_8859_1) + "]");
- }
}
if (parsingRequestLinePhase == 2) {
//
@@ -709,6 +706,16 @@ public class Http11InputBuffer implements InputBuffer, ApplicationBufferHandler
*/
private boolean fill(boolean block) throws IOException {
+ if (log.isDebugEnabled()) {
+ log.debug("Before fill(): parsingHeader: [" + parsingHeader +
+ "], parsingRequestLine: [" + parsingRequestLine +
+ "], parsingRequestLinePhase: [" + parsingRequestLinePhase +
+ "], parsingRequestLineStart: [" + parsingRequestLineStart +
+ "], byteBuffer.position(): [" + byteBuffer.position() +
+ "], byteBuffer.limit(): [" + byteBuffer.limit() +
+ "], end: [" + end + "]");
+ }
+
if (parsingHeader) {
if (byteBuffer.limit() >= headerBufferSize) {
if (parsingRequestLine) {
@@ -721,13 +728,31 @@ public class Http11InputBuffer implements InputBuffer, ApplicationBufferHandler
byteBuffer.limit(end).position(end);
}
+ int nRead = -1;
byteBuffer.mark();
- if (byteBuffer.position() < byteBuffer.limit()) {
- byteBuffer.position(byteBuffer.limit());
+ try {
+ if (byteBuffer.position() < byteBuffer.limit()) {
+ byteBuffer.position(byteBuffer.limit());
+ }
+ byteBuffer.limit(byteBuffer.capacity());
+ SocketWrapperBase<?> socketWrapper = this.wrapper;
+ if (socketWrapper != null) {
+ nRead = socketWrapper.read(block, byteBuffer);
+ } else {
+ throw new CloseNowException(sm.getString("iib.eof.error"));
+ }
+ } finally {
+ // Ensure that the buffer limit and position are returned to a
+ // consistent "ready for read" state if an error occurs during in
+ // the above code block.
+ byteBuffer.limit(byteBuffer.position()).reset();
}
- byteBuffer.limit(byteBuffer.capacity());
- int nRead = wrapper.read(block, byteBuffer);
- byteBuffer.limit(byteBuffer.position()).reset();
+
+ if (log.isDebugEnabled()) {
+ log.debug("Received ["
+ + new String(byteBuffer.array(), byteBuffer.position(), byteBuffer.remaining(), StandardCharsets.ISO_8859_1) + "]");
+ }
+
if (nRead > 0) {
return true;
} else if (nRead == -1) {
diff --git a/java/org/apache/coyote/http11/Http11OutputBuffer.java b/java/org/apache/coyote/http11/Http11OutputBuffer.java
index aa5ad48..c369837 100644
--- a/java/org/apache/coyote/http11/Http11OutputBuffer.java
+++ b/java/org/apache/coyote/http11/Http11OutputBuffer.java
@@ -21,6 +21,7 @@ import java.nio.ByteBuffer;
import java.util.Arrays;
import org.apache.coyote.ActionCode;
+import org.apache.coyote.CloseNowException;
import org.apache.coyote.Response;
import org.apache.tomcat.util.buf.ByteChunk;
import org.apache.tomcat.util.buf.MessageBytes;
@@ -303,7 +304,12 @@ public class Http11OutputBuffer implements HttpOutputBuffer {
// Sending the response header buffer
headerBuffer.flip();
try {
- socketWrapper.write(isBlocking(), headerBuffer);
+ SocketWrapperBase<?> socketWrapper = this.socketWrapper;
+ if (socketWrapper != null) {
+ socketWrapper.write(isBlocking(), headerBuffer);
+ } else {
+ throw new CloseNowException(sm.getString("iob.failedwrite"));
+ }
} finally {
headerBuffer.position(0).limit(headerBuffer.capacity());
}
@@ -527,7 +533,12 @@ public class Http11OutputBuffer implements HttpOutputBuffer {
public int doWrite(ByteBuffer chunk) throws IOException {
try {
int len = chunk.remaining();
- socketWrapper.write(isBlocking(), chunk);
+ SocketWrapperBase<?> socketWrapper = Http11OutputBuffer.this.socketWrapper;
+ if (socketWrapper != null) {
+ socketWrapper.write(isBlocking(), chunk);
+ } else {
+ throw new CloseNowException(sm.getString("iob.failedwrite"));
+ }
len -= chunk.remaining();
byteCount += len;
return len;
diff --git a/test/org/apache/catalina/core/TestAsyncContextImpl.java b/test/org/apache/catalina/core/TestAsyncContextImpl.java
index 3f6524b..4023a74 100644
--- a/test/org/apache/catalina/core/TestAsyncContextImpl.java
+++ b/test/org/apache/catalina/core/TestAsyncContextImpl.java
@@ -17,6 +17,7 @@
package org.apache.catalina.core;
import java.io.IOException;
+import java.io.InputStream;
import java.io.PrintWriter;
import java.net.URI;
import java.net.URISyntaxException;
@@ -819,7 +820,7 @@ public class TestAsyncContextImpl extends TomcatBaseTest {
}
}
- private static class TrackingListener implements AsyncListener {
+ public static class TrackingListener implements AsyncListener {
private final boolean completeOnError;
private final boolean completeOnTimeout;
@@ -2653,4 +2654,173 @@ public class TestAsyncContextImpl extends TomcatBaseTest {
}
}
+
+
+
+ /*
+ * Tests an error on an async thread when the client closes the connection
+ * before fully writing the request body.
+ *
+ * Required sequence is:
+ * - enter Servlet's service() method
+ * - startAsync()
+ * - start async thread
+ * - read partial body
+ * - close client connection
+ * - read on async thread -> I/O error
+ * - exit Servlet's service() method
+ *
+ * This test makes extensive use of instance fields in the Servlet that
+ * would normally be considered very poor practice. It is only safe in this
+ * test as the Servlet only processes a single request.
+ */
+ @Test
+ public void testCanceledPost() throws Exception {
+ CountDownLatch partialReadLatch = new CountDownLatch(1);
+ CountDownLatch clientCloseLatch = new CountDownLatch(1);
+ CountDownLatch threadCompleteLatch = new CountDownLatch(1);
+
+ AtomicBoolean testFailed = new AtomicBoolean(true);
+
+ // Setup Tomcat instance
+ Tomcat tomcat = getTomcatInstance();
+
+ // No file system docBase required
+ Context ctx = tomcat.addContext("", null);
+
+ PostServlet postServlet = new PostServlet(partialReadLatch, clientCloseLatch, threadCompleteLatch, testFailed);
+ Wrapper wrapper = Tomcat.addServlet(ctx, "postServlet", postServlet);
+ wrapper.setAsyncSupported(true);
+ ctx.addServletMappingDecoded("/*", "postServlet");
+
+ tomcat.start();
+
+ PostClient client = new PostClient();
+ client.setPort(getPort());
+ client.setRequest(new String[] { "POST / HTTP/1.1" + SimpleHttpClient.CRLF +
+ "Host: localhost:" + SimpleHttpClient.CRLF +
+ "Content-Length: 100" + SimpleHttpClient.CRLF +
+ SimpleHttpClient.CRLF +
+ "This is 16 bytes"
+ });
+ client.connect();
+ client.sendRequest();
+
+ // Wait server to read partial request body
+ partialReadLatch.await();
+
+ client.disconnect();
+
+ clientCloseLatch.countDown();
+
+ threadCompleteLatch.await();
+
+ Assert.assertFalse(testFailed.get());
+ }
+
+
+ private static final class PostClient extends SimpleHttpClient {
+
+ @Override
+ public boolean isResponseBodyOK() {
+ return true;
+ }
+ }
+
+
+ private static final class PostServlet extends HttpServlet {
+
+ private static final long serialVersionUID = 1L;
+
+ private final transient CountDownLatch partialReadLatch;
+ private final transient CountDownLatch clientCloseLatch;
+ private final transient CountDownLatch threadCompleteLatch;
+ private final AtomicBoolean testFailed;
+
+ public PostServlet(CountDownLatch doPostLatch, CountDownLatch clientCloseLatch,
+ CountDownLatch threadCompleteLatch, AtomicBoolean testFailed) {
+ this.partialReadLatch = doPostLatch;
+ this.clientCloseLatch = clientCloseLatch;
+ this.threadCompleteLatch = threadCompleteLatch;
+ this.testFailed = testFailed;
+ }
+
+ @Override
+ protected void doPost(HttpServletRequest req, HttpServletResponse resp)
+ throws ServletException, IOException {
+
+ AsyncContext ac = req.startAsync();
+ Thread t = new PostServletThread(ac, partialReadLatch, clientCloseLatch, threadCompleteLatch, testFailed);
+ t.start();
+
+ try {
+ threadCompleteLatch.await();
+ } catch (InterruptedException e) {
+ // Ignore
+ }
+ }
+ }
+
+
+ private static final class PostServletThread extends Thread {
+
+ private final AsyncContext ac;
+ private final CountDownLatch partialReadLatch;
+ private final CountDownLatch clientCloseLatch;
+ private final CountDownLatch threadCompleteLatch;
+ private final AtomicBoolean testFailed;
+
+ public PostServletThread(AsyncContext ac, CountDownLatch partialReadLatch, CountDownLatch clientCloseLatch,
+ CountDownLatch threadCompleteLatch, AtomicBoolean testFailed) {
+ this.ac = ac;
+ this.partialReadLatch = partialReadLatch;
+ this.clientCloseLatch = clientCloseLatch;
+ this.threadCompleteLatch = threadCompleteLatch;
+ this.testFailed = testFailed;
+ }
+
+ @Override
+ public void run() {
+ try {
+ int bytesRead = 0;
+ byte[] buffer = new byte[32];
+ InputStream is = null;
+
+ try {
+ is = ac.getRequest().getInputStream();
+
+ // Read the partial request body
+ while (bytesRead < 16) {
+ int read = is.read(buffer);
+ if (read == -1) {
+ // Error condition
+ return;
+ }
+ bytesRead += read;
+ }
+ } catch (IOException ioe) {
+ // Error condition
+ return;
+ } finally {
+ partialReadLatch.countDown();
+ }
+
+ // Wait for client to close connection
+ clientCloseLatch.await();
+
+ // Read again
+ try {
+ is.read();
+ } catch (IOException e) {
+ e.printStackTrace();
+ // Required. Clear the error marker.
+ testFailed.set(false);
+ }
+ } catch (InterruptedException e) {
+ // Ignore
+ } finally {
+ threadCompleteLatch.countDown();
+ }
+ }
+ }
}
diff --git a/test/org/apache/catalina/nonblocking/TestNonBlockingAPI.java b/test/org/apache/catalina/nonblocking/TestNonBlockingAPI.java
index 7130b11..6868375 100644
--- a/test/org/apache/catalina/nonblocking/TestNonBlockingAPI.java
+++ b/test/org/apache/catalina/nonblocking/TestNonBlockingAPI.java
@@ -32,6 +32,9 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.logging.Level;
+import java.util.logging.LogManager;
import javax.net.SocketFactory;
import javax.servlet.AsyncContext;
@@ -44,6 +47,7 @@ import javax.servlet.ServletInputStream;
import javax.servlet.ServletOutputStream;
import javax.servlet.WriteListener;
import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@@ -52,7 +56,9 @@ import org.junit.Ignore;
import org.junit.Test;
import org.apache.catalina.Context;
+import org.apache.catalina.Wrapper;
import org.apache.catalina.startup.BytesStreamer;
+import org.apache.catalina.startup.SimpleHttpClient;
import org.apache.catalina.startup.TesterServlet;
import org.apache.catalina.startup.Tomcat;
import org.apache.catalina.startup.TomcatBaseTest;
@@ -997,4 +1003,190 @@ public class TestNonBlockingAPI extends TomcatBaseTest {
}
}
+
+
+ /*
+ * Tests an error on an non-blocking read when the client closes the
+ * connection before fully writing the request body.
+ *
+ * Required sequence is:
+ * - enter Servlet's service() method
+ * - startAsync()
+ * - configure non-blocking read
+ * - read partial body
+ * - close client connection
+ * - error is triggered
+ * - exit Servlet's service() method
+ *
+ * This test makes extensive use of instance fields in the Servlet that
+ * would normally be considered very poor practice. It is only safe in this
+ * test as the Servlet only processes a single request.
+ */
+ @Test
+ public void testCanceledPost() throws Exception {
+
+ LogManager.getLogManager().getLogger("org.apache.coyote").setLevel(Level.ALL);
+ LogManager.getLogManager().getLogger("org.apache.tomcat.util.net").setLevel(Level.ALL);
+
+ CountDownLatch partialReadLatch = new CountDownLatch(1);
+ CountDownLatch completeLatch = new CountDownLatch(1);
+
+ AtomicBoolean testFailed = new AtomicBoolean(true);
+
+ // Setup Tomcat instance
+ Tomcat tomcat = getTomcatInstance();
+
+ // No file system docBase required
+ Context ctx = tomcat.addContext("", null);
+
+ PostServlet postServlet = new PostServlet(partialReadLatch, completeLatch, testFailed);
+ Wrapper wrapper = Tomcat.addServlet(ctx, "postServlet", postServlet);
+ wrapper.setAsyncSupported(true);
+ ctx.addServletMappingDecoded("/*", "postServlet");
+
+ tomcat.start();
+
+ PostClient client = new PostClient();
+ client.setPort(getPort());
+ client.setRequest(new String[] { "POST / HTTP/1.1" + SimpleHttpClient.CRLF +
+ "Host: localhost:" + SimpleHttpClient.CRLF +
+ "Content-Length: 100" + SimpleHttpClient.CRLF +
+ SimpleHttpClient.CRLF +
+ "This is 16 bytes"
+ });
+ client.connect();
+ client.sendRequest();
+
+ // Wait server to read partial request body
+ partialReadLatch.await();
+
+ client.disconnect();
+
+ completeLatch.await();
+
+ Assert.assertFalse(testFailed.get());
+ }
+
+
+ private static final class PostClient extends SimpleHttpClient {
+
+ @Override
+ public boolean isResponseBodyOK() {
+ return true;
+ }
+ }
+
+
+ private static final class PostServlet extends HttpServlet {
+
+ private static final long serialVersionUID = 1L;
+
+ private final transient CountDownLatch partialReadLatch;
+ private final transient CountDownLatch completeLatch;
+ private final AtomicBoolean testFailed;
+
+ public PostServlet(CountDownLatch doPostLatch, CountDownLatch completeLatch, AtomicBoolean testFailed) {
+ this.partialReadLatch = doPostLatch;
+ this.completeLatch = completeLatch;
+ this.testFailed = testFailed;
+ }
+
+ @Override
+ protected void doPost(HttpServletRequest req, HttpServletResponse resp)
+ throws ServletException, IOException {
+
+ AsyncContext ac = req.startAsync();
+ ac.setTimeout(-1);
+ CanceledPostAsyncListener asyncListener = new CanceledPostAsyncListener(completeLatch);
+ ac.addListener(asyncListener);
+
+ CanceledPostReadListener readListener = new CanceledPostReadListener(ac, partialReadLatch, testFailed);
+ req.getInputStream().setReadListener(readListener);
+ }
+ }
+
+
+ private static final class CanceledPostAsyncListener implements AsyncListener {
+
+ private final transient CountDownLatch completeLatch;
+
+ public CanceledPostAsyncListener(CountDownLatch completeLatch) {
+ this.completeLatch = completeLatch;
+ }
+
+ @Override
+ public void onComplete(AsyncEvent event) throws IOException {
+ System.out.println("complete");
+ completeLatch.countDown();
+ }
+
+ @Override
+ public void onTimeout(AsyncEvent event) throws IOException {
+ System.out.println("onTimeout");
+ }
+
+ @Override
+ public void onError(AsyncEvent event) throws IOException {
+ System.out.println("onError-async");
+ }
+
+ @Override
+ public void onStartAsync(AsyncEvent event) throws IOException {
+ System.out.println("onStartAsync");
+ }
+ }
+
+ private static final class CanceledPostReadListener implements ReadListener {
+
+ private final AsyncContext ac;
+ private final CountDownLatch partialReadLatch;
+ private final AtomicBoolean testFailed;
+ private int totalRead = 0;
+
+ public CanceledPostReadListener(AsyncContext ac, CountDownLatch partialReadLatch, AtomicBoolean testFailed) {
+ this.ac = ac;
+ this.partialReadLatch = partialReadLatch;
+ this.testFailed = testFailed;
+ }
+
+ @Override
+ public void onDataAvailable() throws IOException {
+ ServletInputStream sis = ac.getRequest().getInputStream();
+ boolean isReady;
+
+ byte[] buffer = new byte[32];
+ do {
+ if (partialReadLatch.getCount() == 0) {
+ System.out.println("debug");
+ }
+ int bytesRead = sis.read(buffer);
+
+ if (bytesRead == -1) {
+ return;
+ }
+ totalRead += bytesRead;
+ isReady = sis.isReady();
+ System.out.println("Read [" + bytesRead +
+ "], buffer [" + new String(buffer, 0, bytesRead, StandardCharsets.UTF_8) +
+ "], total read [" + totalRead +
+ "], isReady [" + isReady + "]");
+ } while (isReady);
+ if (totalRead == 16) {
+ partialReadLatch.countDown();
+ }
+ }
+
+ @Override
+ public void onAllDataRead() throws IOException {
+ ac.complete();
+ }
+
+ @Override
+ public void onError(Throwable throwable) {
+ throwable.printStackTrace();
+ // This is the expected behaviour so clear the failed flag.
+ testFailed.set(false);
+ ac.complete();
+ }
+ }
}
--
2.33.0

View File

@ -13,7 +13,7 @@
Name: tomcat
Epoch: 1
Version: %{major_version}.%{minor_version}.%{micro_version}
Release: 32
Release: 33
Summary: Implementation of the Java Servlet, JavaServer Pages, Java Expression Language and Java WebSocket technologies
License: ASL 2.0
URL: http://tomcat.apache.org/
@ -106,6 +106,10 @@ Patch6071: CVE-2023-28708-pre.patch
Patch6072: CVE-2023-28708.patch
Patch6073: CVE-2023-41080.patch
Patch6074: CVE-2023-45648.patch
Patch6075: CVE-2024-21733.patch
Patch6076: CVE-2023-24998.patch
Patch6077: CVE-2023-28709.patch
Patch6078: CVE-2023-42795.patch
BuildRequires: ecj >= 1:4.6.1 findutils apache-commons-collections apache-commons-daemon
BuildRequires: apache-commons-dbcp apache-commons-pool tomcat-taglibs-standard ant
@ -506,6 +510,9 @@ fi
%{_javadocdir}/%{name}
%changelog
* Tue Jan 23 2024 wangkai <13474090681@163.com> - 1:9.0.10-33
- Fix CVE-2024-21733,CVE-2023-24998,CVE-2023-28709,CVE-2023-42795
* Fri Oct 20 2023 wangkai <13474090681@163.com> - 1:9.0.10-32
- Fix CVE-2023-45648