Blame SOURCES/tomcat-7.0.54-CVE-2014-0227.patch

e41f6f
--- java/org/apache/coyote/http11/filters/ChunkedInputFilter.java.orig	2015-03-24 16:32:02.657913000 -0400
e41f6f
+++ java/org/apache/coyote/http11/filters/ChunkedInputFilter.java	2015-03-24 18:21:47.397617000 -0400
e41f6f
@@ -14,7 +14,6 @@
e41f6f
  *  See the License for the specific language governing permissions and
e41f6f
  *  limitations under the License.
e41f6f
  */
e41f6f
-
e41f6f
 package org.apache.coyote.http11.filters;
e41f6f
 
e41f6f
 import java.io.EOFException;
e41f6f
@@ -29,6 +28,7 @@
e41f6f
 import org.apache.tomcat.util.buf.HexUtils;
e41f6f
 import org.apache.tomcat.util.buf.MessageBytes;
e41f6f
 import org.apache.tomcat.util.http.MimeHeaders;
e41f6f
+import org.apache.tomcat.util.res.StringManager;
e41f6f
 
e41f6f
 /**
e41f6f
  * Chunked input filter. Parses chunked data according to
e41f6f
@@ -39,9 +39,11 @@
e41f6f
  */
e41f6f
 public class ChunkedInputFilter implements InputFilter {
e41f6f
 
e41f6f
+    private static final StringManager sm = StringManager.getManager(
e41f6f
+            ChunkedInputFilter.class.getPackage().getName());
e41f6f
 
e41f6f
-    // -------------------------------------------------------------- Constants
e41f6f
 
e41f6f
+    // -------------------------------------------------------------- Constants
e41f6f
 
e41f6f
     protected static final String ENCODING_NAME = "chunked";
e41f6f
     protected static final ByteChunk ENCODING = new ByteChunk();
e41f6f
@@ -49,7 +51,6 @@
e41f6f
 
e41f6f
     // ----------------------------------------------------- Static Initializer
e41f6f
 
e41f6f
-
e41f6f
     static {
e41f6f
         ENCODING.setBytes(ENCODING_NAME.getBytes(Charset.defaultCharset()), 0,
e41f6f
                 ENCODING_NAME.length());
e41f6f
@@ -58,7 +59,6 @@
e41f6f
 
e41f6f
     // ----------------------------------------------------- Instance Variables
e41f6f
 
e41f6f
-
e41f6f
     /**
e41f6f
      * Next buffer in the pipeline.
e41f6f
      */
e41f6f
@@ -106,6 +106,7 @@
e41f6f
      */
e41f6f
     protected ByteChunk trailingHeaders = new ByteChunk();
e41f6f
 
e41f6f
+
e41f6f
     /**
e41f6f
      * Flag set to true if the next call to doRead() must parse a CRLF pair
e41f6f
      * before doing anything else.
e41f6f
@@ -130,21 +131,29 @@
e41f6f
      */
e41f6f
     private final int maxTrailerSize;
e41f6f
 
e41f6f
+
e41f6f
     /**
e41f6f
      * Size of extensions processed for this request.
e41f6f
      */
e41f6f
     private long extensionSize;
e41f6f
 
e41f6f
 
e41f6f
+    /**
e41f6f
+     * Flag that indicates if an error has occurred.
e41f6f
+     */
e41f6f
+    private boolean error;
e41f6f
+
e41f6f
+
e41f6f
     // ----------------------------------------------------------- Constructors
e41f6f
+
e41f6f
     public ChunkedInputFilter(int maxTrailerSize, int maxExtensionSize) {
e41f6f
         this.trailingHeaders.setLimit(maxTrailerSize);
e41f6f
         this.maxExtensionSize = maxExtensionSize;
e41f6f
         this.maxTrailerSize = maxTrailerSize;
e41f6f
     }
e41f6f
 
e41f6f
-    // ---------------------------------------------------- InputBuffer Methods
e41f6f
 
e41f6f
+    // ---------------------------------------------------- InputBuffer Methods
e41f6f
 
e41f6f
     /**
e41f6f
      * Read bytes.
e41f6f
@@ -156,11 +165,12 @@
e41f6f
      * control, the returned value should be -1.
e41f6f
      */
e41f6f
     @Override
e41f6f
-    public int doRead(ByteChunk chunk, Request req)
e41f6f
-        throws IOException {
e41f6f
-
e41f6f
-        if (endChunk)
e41f6f
+    public int doRead(ByteChunk chunk, Request req) throws IOException {
e41f6f
+        if (endChunk) {
e41f6f
             return -1;
e41f6f
+        }
e41f6f
+
e41f6f
+        checkError();
e41f6f
 
e41f6f
         if(needCRLFParse) {
e41f6f
             needCRLFParse = false;
e41f6f
@@ -169,7 +179,7 @@
e41f6f
 
e41f6f
         if (remaining <= 0) {
e41f6f
             if (!parseChunkHeader()) {
e41f6f
-                throw new IOException("Invalid chunk header");
e41f6f
+                throwIOException(sm.getString("chunkedInputFilter.invalidHeader"));
e41f6f
             }
e41f6f
             if (endChunk) {
e41f6f
                 parseEndChunk();
e41f6f
@@ -181,8 +191,7 @@
e41f6f
 
e41f6f
         if (pos >= lastValid) {
e41f6f
             if (readBytes() < 0) {
e41f6f
-                throw new IOException(
e41f6f
-                        "Unexpected end of stream whilst reading request body");
e41f6f
+                throwIOException(sm.getString("chunkedInputFilter.eos"));
e41f6f
             }
e41f6f
         }
e41f6f
 
e41f6f
@@ -207,13 +216,11 @@
e41f6f
         }
e41f6f
 
e41f6f
         return result;
e41f6f
-
e41f6f
     }
e41f6f
 
e41f6f
 
e41f6f
     // ---------------------------------------------------- InputFilter Methods
e41f6f
 
e41f6f
-
e41f6f
     /**
e41f6f
      * Read the content length from the request.
e41f6f
      */
e41f6f
@@ -227,17 +234,13 @@
e41f6f
      * End the current request.
e41f6f
      */
e41f6f
     @Override
e41f6f
-    public long end()
e41f6f
-        throws IOException {
e41f6f
-
e41f6f
-        // Consume extra bytes : parse the stream until the end chunk is found
e41f6f
+    public long end() throws IOException {
e41f6f
         while (doRead(readChunk, null) >= 0) {
e41f6f
-            // NOOP: Just consume the input
e41f6f
+             // NOOP: just consume the input
e41f6f
         }
e41f6f
 
e41f6f
         // Return the number of extra bytes which were consumed
e41f6f
-        return (lastValid - pos);
e41f6f
-
e41f6f
+        return lastValid - pos;
e41f6f
     }
e41f6f
 
e41f6f
 
e41f6f
@@ -246,7 +249,7 @@
e41f6f
      */
e41f6f
     @Override
e41f6f
     public int available() {
e41f6f
-        return (lastValid - pos);
e41f6f
+        return lastValid - pos;
e41f6f
     }
e41f6f
     
e41f6f
 
e41f6f
@@ -272,6 +275,7 @@
e41f6f
         trailingHeaders.recycle();
e41f6f
         trailingHeaders.setLimit(maxTrailerSize);
e41f6f
         extensionSize = 0;
e41f6f
+        error = false;
e41f6f
     }
e41f6f
 
e41f6f
 
e41f6f
@@ -287,12 +291,10 @@
e41f6f
 
e41f6f
     // ------------------------------------------------------ Protected Methods
e41f6f
 
e41f6f
-
e41f6f
     /**
e41f6f
      * Read bytes from the previous buffer.
e41f6f
      */
e41f6f
-    protected int readBytes()
e41f6f
-        throws IOException {
e41f6f
+    protected int readBytes() throws IOException {
e41f6f
 
e41f6f
         int nRead = buffer.doRead(readChunk, null);
e41f6f
         pos = readChunk.getStart();
e41f6f
@@ -300,7 +302,6 @@
e41f6f
         buf = readChunk.getBytes();
e41f6f
 
e41f6f
         return nRead;
e41f6f
-
e41f6f
     }
e41f6f
 
e41f6f
 
e41f6f
@@ -315,8 +316,7 @@
e41f6f
      * digits. We should not parse F23IAMGONNAMESSTHISUP34CRLF as a valid
e41f6f
      * header according to the spec.
e41f6f
      */
e41f6f
-    protected boolean parseChunkHeader()
e41f6f
-        throws IOException {
e41f6f
+    protected boolean parseChunkHeader() throws IOException {
e41f6f
 
e41f6f
         int result = 0;
e41f6f
         boolean eol = false;
e41f6f
@@ -356,7 +356,7 @@
e41f6f
                 // validated. Currently it is simply ignored.
e41f6f
                 extensionSize++;
e41f6f
                 if (maxExtensionSize > -1 && extensionSize > maxExtensionSize) {
e41f6f
-                    throw new IOException("maxExtensionSize exceeded");
e41f6f
+                    throwIOException(sm.getString("chunkedInputFilter.maxExtension"));
e41f6f
                 }
e41f6f
             }
e41f6f
 
e41f6f
@@ -364,21 +364,22 @@
e41f6f
             if (!eol) {
e41f6f
                 pos++;
e41f6f
             }
e41f6f
-
e41f6f
         }
e41f6f
 
e41f6f
-        if (readDigit == 0 || result < 0)
e41f6f
+        if (readDigit == 0 || result < 0) {
e41f6f
             return false;
e41f6f
+        }
e41f6f
 
e41f6f
-        if (result == 0)
e41f6f
+        if (result == 0) {
e41f6f
             endChunk = true;
e41f6f
+        }
e41f6f
 
e41f6f
         remaining = result;
e41f6f
-        if (remaining < 0)
e41f6f
+        if (remaining < 0) {
e41f6f
             return false;
e41f6f
+        }
e41f6f
 
e41f6f
         return true;
e41f6f
-
e41f6f
     }
e41f6f
 
e41f6f
 
e41f6f
@@ -405,26 +406,27 @@
e41f6f
         boolean crfound = false;
e41f6f
 
e41f6f
         while (!eol) {
e41f6f
-
e41f6f
             if (pos >= lastValid) {
e41f6f
-                if (readBytes() <= 0)
e41f6f
-                    throw new IOException("Invalid CRLF");
e41f6f
+                if (readBytes() <= 0) {
e41f6f
+                    throwIOException(sm.getString("chunkedInputFilter.invalidCrlfNoData"));
e41f6f
+                }
e41f6f
             }
e41f6f
 
e41f6f
             if (buf[pos] == Constants.CR) {
e41f6f
-                if (crfound) throw new IOException("Invalid CRLF, two CR characters encountered.");
e41f6f
+                if (crfound) {
e41f6f
+                    throwIOException(sm.getString("chunkedInputFilter.invalidCrlfCRCR"));
e41f6f
+                }
e41f6f
                 crfound = true;
e41f6f
             } else if (buf[pos] == Constants.LF) {
e41f6f
                 if (!tolerant && !crfound) {
e41f6f
-                    throw new IOException("Invalid CRLF, no CR character encountered.");
e41f6f
+                    throwIOException(sm.getString("chunkedInputFilter.invalidCrlfNoCR"));
e41f6f
                 }
e41f6f
                 eol = true;
e41f6f
             } else {
e41f6f
-                throw new IOException("Invalid CRLF");
e41f6f
+                throwIOException(sm.getString("chunkedInputFilter.invalidCrlf"));
e41f6f
             }
e41f6f
 
e41f6f
             pos++;
e41f6f
-
e41f6f
         }
e41f6f
     }
e41f6f
 
e41f6f
@@ -433,7 +435,6 @@
e41f6f
      * Parse end chunk data.
e41f6f
      */
e41f6f
     protected void parseEndChunk() throws IOException {
e41f6f
-
e41f6f
         // Handle optional trailer headers
e41f6f
         while (parseHeader()) {
e41f6f
             // Loop until we run out of headers
e41f6f
@@ -449,8 +450,9 @@
e41f6f
 
e41f6f
         // Read new bytes if needed
e41f6f
         if (pos >= lastValid) {
e41f6f
-            if (readBytes() <0)
e41f6f
-                throw new EOFException("Unexpected end of stream whilst reading trailer headers for chunked request");
e41f6f
+            if (readBytes() <0) {
e41f6f
+               throwEOFException(sm.getString("chunkedInputFilter.eosTrailer"));
e41f6f
+            }
e41f6f
         }
e41f6f
     
e41f6f
         chr = buf[pos];
e41f6f
@@ -474,8 +476,9 @@
e41f6f
     
e41f6f
             // Read new bytes if needed
e41f6f
             if (pos >= lastValid) {
e41f6f
-                if (readBytes() <0)
e41f6f
-                    throw new EOFException("Unexpected end of stream whilst reading trailer headers for chunked request");
e41f6f
+                if (readBytes() <0) {
e41f6f
+                    throwEOFException(sm.getString("chunkedInputFilter.eosTrailer"));
e41f6f
+                }
e41f6f
             }
e41f6f
     
e41f6f
             chr = buf[pos];
e41f6f
@@ -515,8 +518,9 @@
e41f6f
     
e41f6f
                 // Read new bytes if needed
e41f6f
                 if (pos >= lastValid) {
e41f6f
-                    if (readBytes() <0)
e41f6f
-                        throw new EOFException("Unexpected end of stream whilst reading trailer headers for chunked request");
e41f6f
+                    if (readBytes() <0) {
e41f6f
+                        throwEOFException(sm.getString("chunkedInputFilter.eosTrailer"));
e41f6f
+                    }
e41f6f
                 }
e41f6f
     
e41f6f
                 chr = buf[pos];
e41f6f
@@ -526,7 +530,7 @@
e41f6f
                     // limit placed on trailing header size
e41f6f
                     int newlimit = trailingHeaders.getLimit() -1;
e41f6f
                     if (trailingHeaders.getEnd() > newlimit) {
e41f6f
-                        throw new IOException("Exceeded maxTrailerSize");
e41f6f
+                        throwIOException(sm.getString("chunkedInputFilter.maxTrailer"));
e41f6f
                     }
e41f6f
                     trailingHeaders.setLimit(newlimit);
e41f6f
                 } else {
e41f6f
@@ -540,8 +544,9 @@
e41f6f
     
e41f6f
                 // Read new bytes if needed
e41f6f
                 if (pos >= lastValid) {
e41f6f
-                    if (readBytes() <0)
e41f6f
-                        throw new EOFException("Unexpected end of stream whilst reading trailer headers for chunked request");
e41f6f
+                    if (readBytes() <0) {
e41f6f
+                        throwEOFException(sm.getString("chunkedInputFilter.eosTrailer"));
e41f6f
+                    }
e41f6f
                 }
e41f6f
     
e41f6f
                 chr = buf[pos];
e41f6f
@@ -565,8 +570,9 @@
e41f6f
     
e41f6f
             // Read new bytes if needed
e41f6f
             if (pos >= lastValid) {
e41f6f
-                if (readBytes() <0)
e41f6f
-                    throw new EOFException("Unexpected end of stream whilst reading trailer headers for chunked request");
e41f6f
+                if (readBytes() <0) {
e41f6f
+                    throwEOFException(sm.getString("chunkedInputFilter.eosTrailer"));
e41f6f
+                }
e41f6f
             }
e41f6f
     
e41f6f
             chr = buf[pos];
e41f6f
@@ -587,4 +593,23 @@
e41f6f
     
e41f6f
         return true;
e41f6f
     }
e41f6f
+
e41f6f
+
e41f6f
+    private void throwIOException(String msg) throws IOException {
e41f6f
+        error = true;
e41f6f
+        throw new IOException(msg);
e41f6f
+    }
e41f6f
+
e41f6f
+
e41f6f
+    private void throwEOFException(String msg) throws IOException {
e41f6f
+        error = true;
e41f6f
+        throw new EOFException(msg);
e41f6f
+    }
e41f6f
+
e41f6f
+
e41f6f
+    private void checkError() throws IOException {
e41f6f
+        if (error) {
e41f6f
+            throw new IOException(sm.getString("chunkedInputFilter.error"));
e41f6f
+        }
e41f6f
+    }
e41f6f
 }
e41f6f
--- java/org/apache/coyote/http11/filters/LocalStrings.properties.orig	2015-03-24 16:32:02.662909000 -0400
e41f6f
+++ java/org/apache/coyote/http11/filters/LocalStrings.properties	2015-03-24 16:39:31.017419000 -0400
e41f6f
@@ -0,0 +1,27 @@
e41f6f
+# Licensed to the Apache Software Foundation (ASF) under one or more
e41f6f
+# contributor license agreements.  See the NOTICE file distributed with
e41f6f
+# this work for additional information regarding copyright ownership.
e41f6f
+# The ASF licenses this file to You under the Apache License, Version 2.0
e41f6f
+# (the "License"); you may not use this file except in compliance with
e41f6f
+# the License.  You may obtain a copy of the License at
e41f6f
+#
e41f6f
+#     http://www.apache.org/licenses/LICENSE-2.0
e41f6f
+#
e41f6f
+# Unless required by applicable law or agreed to in writing, software
e41f6f
+# distributed under the License is distributed on an "AS IS" BASIS,
e41f6f
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
e41f6f
+# See the License for the specific language governing permissions and
e41f6f
+# limitations under the License.
e41f6f
+
e41f6f
+chunkedInputFilter.error=No data available due to previous error
e41f6f
+chunkedInputFilter.eos=Unexpected end of stream while reading request body
e41f6f
+chunkedInputFilter.eosTrailer=Unexpected end of stream while reading trailer headers
e41f6f
+chunkedInputFilter.invalidCrlf=Invalid end of line sequence (character other than CR or LF found)
e41f6f
+chunkedInputFilter.invalidCrlfCRCR=Invalid end of line sequence (CRCR)
e41f6f
+chunkedInputFilter.invalidCrlfNoCR=Invalid end of line sequence (No CR before LF)
e41f6f
+chunkedInputFilter.invalidCrlfNoData=Invalid end of line sequence (no data available to read)
e41f6f
+chunkedInputFilter.invalidHeader=Invalid chunk header
e41f6f
+chunkedInputFilter.maxExtension=maxExtensionSize exceeded
e41f6f
+chunkedInputFilter.maxTrailer=maxTrailerSize exceeded
e41f6f
+
e41f6f
+inputFilter.maxSwallow=maxSwallowSize exceeded
e41f6f
\ No newline at end of file