You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tomee.apache.org by rz...@apache.org on 2023/04/18 11:40:19 UTC

[tomee] 02/04: Patch Tomcat 10.0.27 for CVE-2023-24998 by applying the changeset from

This is an automated email from the ASF dual-hosted git repository.

rzo1 pushed a commit to branch tomee-9.x-cve-patches
in repository https://gitbox.apache.org/repos/asf/tomee.git

commit d92b6f8ae38dbafc28e719322e2f6689dddfc66b
Author: Richard Zowalla <ri...@hs-heilbronn.de>
AuthorDate: Tue Apr 18 13:32:45 2023 +0200

    Patch Tomcat 10.0.27 for CVE-2023-24998 by applying the changeset from
    
    https://github.com/apache/tomcat/commit/8a2285f13affa961cc65595aad999db5efae45ce
---
 .../org/apache/catalina/connector/Request.java     | 22 +++++++---
 .../org/apache/tomcat/util/http/Parameters.java    |  9 +++-
 .../util/http/fileupload/FileUploadBase.java       | 39 ++++++++++++++---
 .../impl/FileCountLimitExceededException.java      | 50 ++++++++++++++++++++++
 4 files changed, 106 insertions(+), 14 deletions(-)

diff --git a/tomee/apache-tomee/src/patch/java/org/apache/catalina/connector/Request.java b/tomee/apache-tomee/src/patch/java/org/apache/catalina/connector/Request.java
index d867cdd554..55e7e677fa 100644
--- a/tomee/apache-tomee/src/patch/java/org/apache/catalina/connector/Request.java
+++ b/tomee/apache-tomee/src/patch/java/org/apache/catalina/connector/Request.java
@@ -1569,7 +1569,7 @@ public class Request implements HttpServletRequest {
      * @param oldValue Old attribute value
      */
     private void notifyAttributeAssigned(String name, Object value,
-            Object oldValue) {
+                                         Object oldValue) {
         Context context = getContext();
         if (context == null) {
             return;
@@ -1671,7 +1671,7 @@ public class Request implements HttpServletRequest {
     @Override
     public ServletContext getServletContext() {
         return getContext().getServletContext();
-     }
+    }
 
     @Override
     public AsyncContext startAsync() {
@@ -1680,7 +1680,7 @@ public class Request implements HttpServletRequest {
 
     @Override
     public AsyncContext startAsync(ServletRequest request,
-            ServletResponse response) {
+                                   ServletResponse response) {
         if (!isAsyncSupported()) {
             IllegalStateException ise =
                     new IllegalStateException(sm.getString("request.asyncNotSupported"));
@@ -2041,7 +2041,7 @@ public class Request implements HttpServletRequest {
                 handler = (T) instanceManager.newInstance(httpUpgradeHandlerClass);
             }
         } catch (ReflectiveOperationException | NamingException | IllegalArgumentException |
-                SecurityException e) {
+                 SecurityException e) {
             throw new ServletException(e);
         }
         UpgradeToken upgradeToken = new UpgradeToken(handler, getContext(), instanceManager,
@@ -2704,7 +2704,7 @@ public class Request implements HttpServletRequest {
         Session session = this.getSessionInternal(false);
         if (session == null) {
             throw new IllegalStateException(
-                sm.getString("coyoteRequest.changeSessionId"));
+                    sm.getString("coyoteRequest.changeSessionId"));
         }
 
         Manager manager = this.getContext().getManager();
@@ -2840,8 +2840,9 @@ public class Request implements HttpServletRequest {
             }
         }
 
+        int maxParameterCount = getConnector().getMaxParameterCount();
         Parameters parameters = coyoteRequest.getParameters();
-        parameters.setLimit(getConnector().getMaxParameterCount());
+        parameters.setLimit(maxParameterCount);
 
         boolean success = false;
         try {
@@ -2893,6 +2894,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 {
@@ -3544,7 +3552,7 @@ public class Request implements HttpServletRequest {
                     public Object get(Request request, String name) {
                         return Boolean.valueOf(
                                 request.getConnector().getProtocolHandler(
-                                        ).isSendfileSupported() && request.getCoyoteRequest().getSendfile());
+                                ).isSendfileSupported() && request.getCoyoteRequest().getSendfile());
                     }
                     @Override
                     public void set(Request request, String name, Object value) {
diff --git a/tomee/apache-tomee/src/patch/java/org/apache/tomcat/util/http/Parameters.java b/tomee/apache-tomee/src/patch/java/org/apache/tomcat/util/http/Parameters.java
index ce765374e7..bd86844b97 100644
--- a/tomee/apache-tomee/src/patch/java/org/apache/tomcat/util/http/Parameters.java
+++ b/tomee/apache-tomee/src/patch/java/org/apache/tomcat/util/http/Parameters.java
@@ -47,7 +47,7 @@ public final class Parameters {
     private static final UserDataHelper maxParamCountLog = new UserDataHelper(log);
 
     private static final StringManager sm =
-        StringManager.getManager("org.apache.tomcat.util.http");
+            StringManager.getManager("org.apache.tomcat.util.http");
 
     private final Map<String,ArrayList<String>> paramHashValues =
             new LinkedHashMap<>();
@@ -125,6 +125,11 @@ public final class Parameters {
     }
 
 
+    public int size() {
+        return parameterCount;
+    }
+
+
     public void recycle() {
         parameterCount = 0;
         paramHashValues.clear();
@@ -471,7 +476,7 @@ public final class Parameters {
     }
 
     private void urlDecode(ByteChunk bc)
-        throws IOException {
+            throws IOException {
         if( urlDec==null ) {
             urlDec=new UDecoder();
         }
diff --git a/tomee/apache-tomee/src/patch/java/org/apache/tomcat/util/http/fileupload/FileUploadBase.java b/tomee/apache-tomee/src/patch/java/org/apache/tomcat/util/http/fileupload/FileUploadBase.java
index 7d678c24d8..ce903d489c 100644
--- a/tomee/apache-tomee/src/patch/java/org/apache/tomcat/util/http/fileupload/FileUploadBase.java
+++ b/tomee/apache-tomee/src/patch/java/org/apache/tomcat/util/http/fileupload/FileUploadBase.java
@@ -25,6 +25,7 @@ import java.util.Locale;
 import java.util.Map;
 import java.util.Objects;
 
+import org.apache.tomcat.util.http.fileupload.impl.FileCountLimitExceededException;
 import org.apache.tomcat.util.http.fileupload.impl.FileItemIteratorImpl;
 import org.apache.tomcat.util.http.fileupload.impl.FileUploadIOException;
 import org.apache.tomcat.util.http.fileupload.impl.IOFileUploadException;
@@ -128,6 +129,12 @@ public abstract class FileUploadBase {
      */
     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.
      */
@@ -204,6 +211,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}, the request
@@ -247,7 +272,7 @@ public abstract class FileUploadBase {
      *   storing the uploaded content.
      */
     public FileItemIterator getItemIterator(final RequestContext ctx)
-    throws FileUploadException, IOException {
+            throws FileUploadException, IOException {
         try {
             return new FileItemIteratorImpl(this, ctx);
         } catch (final FileUploadIOException e) {
@@ -278,11 +303,15 @@ public abstract class FileUploadBase {
                     "No FileItemFactory has been set.");
             final byte[] buffer = new byte[Streams.DEFAULT_BUFFER_SIZE];
             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 = item.getName();
                 final FileItem fileItem = fileItemFactory.createItem(item.getFieldName(), item.getContentType(),
-                                                   item.isFormField(), fileName);
+                        item.isFormField(), fileName);
                 items.add(fileItem);
                 try {
                     Streams.copy(item.openStream(), fileItem.getOutputStream(), true, buffer);
@@ -290,7 +319,7 @@ public abstract class FileUploadBase {
                     throw (FileUploadException) e.getCause();
                 } catch (final IOException e) {
                     throw new IOFileUploadException(String.format("Processing of %s request failed. %s",
-                                                           MULTIPART_FORM_DATA, e.getMessage()), e);
+                            MULTIPART_FORM_DATA, e.getMessage()), e);
                 }
                 final FileItemHeaders fih = item.getHeaders();
                 fileItem.setHeaders(fih);
@@ -510,7 +539,7 @@ public abstract class FileUploadBase {
             final int offset = headerPart.indexOf('\r', index);
             if (offset == -1  ||  offset + 1 >= headerPart.length()) {
                 throw new IllegalStateException(
-                    "Expected headers to be terminated by an empty line.");
+                        "Expected headers to be terminated by an empty line.");
             }
             if (headerPart.charAt(offset + 1) == '\n') {
                 return offset;
@@ -532,7 +561,7 @@ public abstract class FileUploadBase {
         }
         final String headerName = header.substring(0, colonOffset).trim();
         final String headerValue =
-            header.substring(colonOffset + 1).trim();
+                header.substring(colonOffset + 1).trim();
         headers.addHeader(headerName, headerValue);
     }
 
diff --git a/tomee/apache-tomee/src/patch/java/org/apache/tomcat/util/http/fileupload/impl/FileCountLimitExceededException.java b/tomee/apache-tomee/src/patch/java/org/apache/tomcat/util/http/fileupload/impl/FileCountLimitExceededException.java
new file mode 100644
index 0000000000..958f681276
--- /dev/null
+++ b/tomee/apache-tomee/src/patch/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;
+    }
+}