[tomcat6] 01/01: Import Debian patch 6.0.45+dfsg-1~deb7u3

Markus Koschany apo at moszumanska.debian.org
Fri Nov 25 23:38:43 UTC 2016


This is an automated email from the git hooks/post-receive script.

apo pushed a commit to branch wheezy
in repository tomcat6.

commit 416b5a11d5f28589cccb7fd6970692630fc996de
Author: Markus Koschany <apo at debian.org>
Date:   Fri Nov 25 22:04:20 2016 +0100

    Import Debian patch 6.0.45+dfsg-1~deb7u3
---
 debian/changelog                   |   14 +-
 debian/patches/CVE-2016-6816.patch | 1105 ++++++++++++++++++++++++++++++++++++
 debian/patches/CVE-2016-8735.patch |   24 +
 debian/patches/series              |    2 +
 4 files changed, 1143 insertions(+), 2 deletions(-)

diff --git a/debian/changelog b/debian/changelog
index 85928c9..5ecc7a3 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,4 +1,4 @@
-tomcat6 (6.0.45+dfsg-1~deb7u3) wheezy-security; urgency=high
+tomcat6 (6.0.45+dfsg-1~deb7u3) UNRELEASED; urgency=high
 
   * Fixed CVE-2016-0762: The Realm implementations did not process the supplied
     password if the supplied user name did not exist. This made a timing attack
@@ -19,6 +19,16 @@ tomcat6 (6.0.45+dfsg-1~deb7u3) wheezy-security; urgency=high
     web application. Therefore, it was possible for a web application to access
     any global JNDI resource whether an explicit ResourceLink had been
     configured or not.
+  * Fixed CVE-2016-6816: The code that parsed the HTTP request line permitted
+    invalid characters. This could be exploited, in conjunction with a proxy
+    that also permitted the invalid characters but with a different
+    interpretation, to inject data into the HTTP response. By manipulating the
+    HTTP response the attacker could poison a web-cache, perform an XSS attack
+    and/or obtain sensitive information from requests other then their own.
+  * Fixed CVE-2016-8735: The JmxRemoteLifecycleListener was not updated to take
+    account of Oracle's fix for CVE-2016-3427. Therefore, Tomcat installations
+    using this listener remained vulnerable to a similar remote code execution
+    vulnerability.
   * CVE-2016-1240 follow-up:
     - The previous init.d fix was vulnerable to a race condition that could
       be exploited to make any existing file writable by the tomcat user.
@@ -28,7 +38,7 @@ tomcat6 (6.0.45+dfsg-1~deb7u3) wheezy-security; urgency=high
       Thanks to Paul Szabo for the report.
   * Hardened the init.d script, thanks to Paul Szabo
 
- -- Markus Koschany <apo at debian.org>  Mon, 07 Nov 2016 13:46:30 +0100
+ -- Markus Koschany <apo at debian.org>  Fri, 25 Nov 2016 22:04:20 +0100
 
 tomcat6 (6.0.45+dfsg-1~deb7u2) wheezy-security; urgency=high
 
diff --git a/debian/patches/CVE-2016-6816.patch b/debian/patches/CVE-2016-6816.patch
new file mode 100644
index 0000000..d936b4e
--- /dev/null
+++ b/debian/patches/CVE-2016-6816.patch
@@ -0,0 +1,1105 @@
+From: Markus Koschany <apo at debian.org>
+Date: Fri, 25 Nov 2016 20:08:42 +0100
+Subject: CVE-2016-6816
+
+Origin: http://svn.apache.org/r1767683
+---
+ .../apache/coyote/http11/AbstractInputBuffer.java  |  52 +---------
+ .../coyote/http11/InternalAprInputBuffer.java      |  77 +++++++--------
+ .../apache/coyote/http11/InternalInputBuffer.java  |  69 ++++++-------
+ .../coyote/http11/InternalNioInputBuffer.java      | 110 ++++++++++-----------
+ .../apache/coyote/http11/LocalStrings.properties   |   3 +
+ .../apache/tomcat/util/http/parser/HttpParser.java |  45 ++++++++-
+ java/org/apache/tomcat/util/res/StringManager.java |   3 +
+ 7 files changed, 168 insertions(+), 191 deletions(-)
+
+diff --git a/java/org/apache/coyote/http11/AbstractInputBuffer.java b/java/org/apache/coyote/http11/AbstractInputBuffer.java
+index 05e9d34..587755f 100644
+--- a/java/org/apache/coyote/http11/AbstractInputBuffer.java
++++ b/java/org/apache/coyote/http11/AbstractInputBuffer.java
+@@ -17,56 +17,8 @@
+ package org.apache.coyote.http11;
+ 
+ import org.apache.coyote.InputBuffer;
++import org.apache.tomcat.util.res.StringManager;
+ 
+ public abstract class AbstractInputBuffer implements InputBuffer {
+-    
+-    protected static final boolean[] HTTP_TOKEN_CHAR = new boolean[128];
+ 
+-    static {
+-        for (int i = 0; i < 128; i++) {
+-            if (i < 32) {
+-                HTTP_TOKEN_CHAR[i] = false;
+-            } else if (i == 127) {
+-                HTTP_TOKEN_CHAR[i] = false;
+-            } else if (i == '(') {
+-                HTTP_TOKEN_CHAR[i] = false;
+-            } else if (i == ')') {
+-                HTTP_TOKEN_CHAR[i] = false;
+-            } else if (i == '<') {
+-                HTTP_TOKEN_CHAR[i] = false;
+-            } else if (i == '>') {
+-                HTTP_TOKEN_CHAR[i] = false;
+-            } else if (i == '@') {
+-                HTTP_TOKEN_CHAR[i] = false;
+-            } else if (i == ',') {
+-                HTTP_TOKEN_CHAR[i] = false;
+-            } else if (i == ';') {
+-                HTTP_TOKEN_CHAR[i] = false;
+-            } else if (i == ':') {
+-                HTTP_TOKEN_CHAR[i] = false;
+-            } else if (i == '\\') {
+-                HTTP_TOKEN_CHAR[i] = false;
+-            } else if (i == '\"') {
+-                HTTP_TOKEN_CHAR[i] = false;
+-            } else if (i == '/') {
+-                HTTP_TOKEN_CHAR[i] = false;
+-            } else if (i == '[') {
+-                HTTP_TOKEN_CHAR[i] = false;
+-            } else if (i == ']') {
+-                HTTP_TOKEN_CHAR[i] = false;
+-            } else if (i == '?') {
+-                HTTP_TOKEN_CHAR[i] = false;
+-            } else if (i == '=') {
+-                HTTP_TOKEN_CHAR[i] = false;
+-            } else if (i == '{') {
+-                HTTP_TOKEN_CHAR[i] = false;
+-            } else if (i == '}') {
+-                HTTP_TOKEN_CHAR[i] = false;
+-            } else if (i == ' ') {
+-                HTTP_TOKEN_CHAR[i] = false;
+-            } else {
+-                HTTP_TOKEN_CHAR[i] = true;
+-            }
+-        }
+-    }
+-}
++    protected static final StringManager sm = StringManager.getManager(AbstractInputBuffer.class);}
+diff --git a/java/org/apache/coyote/http11/InternalAprInputBuffer.java b/java/org/apache/coyote/http11/InternalAprInputBuffer.java
+index f703719..a5f2804 100644
+--- a/java/org/apache/coyote/http11/InternalAprInputBuffer.java
++++ b/java/org/apache/coyote/http11/InternalAprInputBuffer.java
+@@ -26,7 +26,7 @@ import org.apache.tomcat.jni.Status;
+ import org.apache.tomcat.util.buf.ByteChunk;
+ import org.apache.tomcat.util.buf.MessageBytes;
+ import org.apache.tomcat.util.http.MimeHeaders;
+-import org.apache.tomcat.util.res.StringManager;
++import org.apache.tomcat.util.http.parser.HttpParser;
+ import org.apache.coyote.InputBuffer;
+ import org.apache.coyote.Request;
+ import org.apache.juli.logging.Log;
+@@ -68,23 +68,12 @@ public class InternalAprInputBuffer extends AbstractInputBuffer {
+ 
+         parsingHeader = true;
+         swallowInput = true;
+-        
+-    }
+-
+-
+-    // -------------------------------------------------------------- Variables
+ 
+-
+-    /**
+-     * The string manager for this package.
+-     */
+-    protected static StringManager sm =
+-        StringManager.getManager(Constants.Package);
++    }
+ 
+ 
+     // ----------------------------------------------------- Instance Variables
+ 
+-
+     /**
+      * Associated Coyote request.
+      */
+@@ -196,7 +185,7 @@ public class InternalAprInputBuffer extends AbstractInputBuffer {
+      */
+     public void addFilter(InputFilter filter) {
+ 
+-        InputFilter[] newFilterLibrary = 
++        InputFilter[] newFilterLibrary =
+             new InputFilter[filterLibrary.length + 1];
+         for (int i = 0; i < filterLibrary.length; i++) {
+             newFilterLibrary[i] = filterLibrary[i];
+@@ -264,7 +253,7 @@ public class InternalAprInputBuffer extends AbstractInputBuffer {
+ 
+ 
+     /**
+-     * Recycle the input buffer. This should be called when closing the 
++     * Recycle the input buffer. This should be called when closing the
+      * connection.
+      */
+     public void recycle() {
+@@ -289,7 +278,7 @@ public class InternalAprInputBuffer extends AbstractInputBuffer {
+ 
+     /**
+      * End processing of current HTTP request.
+-     * Note: All bytes of the current request should have been already 
++     * Note: All bytes of the current request should have been already
+      * consumed. This method only resets all the pointers so that we are ready
+      * to parse the next HTTP request.
+      */
+@@ -302,7 +291,7 @@ public class InternalAprInputBuffer extends AbstractInputBuffer {
+         if (lastValid - pos > 0 && pos > 0) {
+             System.arraycopy(buf, pos, buf, 0, lastValid - pos);
+         }
+-        
++
+         // Recycle filters
+         for (int i = 0; i <= lastActiveFilter; i++) {
+             activeFilters[i].recycle();
+@@ -320,7 +309,7 @@ public class InternalAprInputBuffer extends AbstractInputBuffer {
+ 
+     /**
+      * End request (consumes leftover bytes).
+-     * 
++     *
+      * @throws IOException an undelying I/O error occured
+      */
+     public void endRequest()
+@@ -335,14 +324,14 @@ public class InternalAprInputBuffer extends AbstractInputBuffer {
+ 
+ 
+     /**
+-     * Read the request line. This function is meant to be used during the 
+-     * HTTP request header parsing. Do NOT attempt to read the request body 
++     * Read the request line. This function is meant to be used during the
++     * HTTP request header parsing. Do NOT attempt to read the request body
+      * using it.
+      *
+      * @throws IOException If an exception occurs during the underlying socket
+      * read operations, or if the given buffer is not big enough to accomodate
+      * the whole line.
+-     * @return true if data is properly fed; false if no data is available 
++     * @return true if data is properly fed; false if no data is available
+      * immediately and thread should be freed
+      */
+     public boolean parseRequestLine(boolean useAvailableData)
+@@ -398,17 +387,19 @@ public class InternalAprInputBuffer extends AbstractInputBuffer {
+                     throw new EOFException(sm.getString("iib.eof.error"));
+             }
+ 
+-            // Spec says no CR or LF in method name
+-            if (buf[pos] == Constants.CR || buf[pos] == Constants.LF) {
+-                throw new IllegalArgumentException(
+-                        sm.getString("iib.invalidmethod"));
++            // Spec says method name is a token followed by a single SP but
++            // also be tolerant of multiple SP and/or HT.
++            if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) {
+             }
+             // Spec says single SP but it also says be tolerant of HT
+             if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) {
+                 space = true;
+                 request.method().setBytes(buf, start, pos - start);
++            } else if (!HttpParser.isToken(buf[pos])) {
++                throw new IllegalArgumentException(sm.getString("iib.invalidmethod"));
+             }
+ 
++
+             pos++;
+ 
+         }
+@@ -450,15 +441,17 @@ public class InternalAprInputBuffer extends AbstractInputBuffer {
+             if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) {
+                 space = true;
+                 end = pos;
+-            } else if ((buf[pos] == Constants.CR) 
++            } else if ((buf[pos] == Constants.CR)
+                        || (buf[pos] == Constants.LF)) {
+                 // HTTP/0.9 style request
+                 eol = true;
+                 space = true;
+                 end = pos;
+-            } else if ((buf[pos] == Constants.QUESTION) 
++            } else if ((buf[pos] == Constants.QUESTION)
+                        && (questionPos == -1)) {
+                 questionPos = pos;
++            } else if (HttpParser.isNotRequestTarget(buf[pos])) {
++                throw new IllegalArgumentException(sm.getString("iib.invalidRequestTarget"));
+             }
+ 
+             pos++;
+@@ -467,7 +460,7 @@ public class InternalAprInputBuffer extends AbstractInputBuffer {
+ 
+         request.unparsedURI().setBytes(buf, start, end - start);
+         if (questionPos >= 0) {
+-            request.queryString().setBytes(buf, questionPos + 1, 
++            request.queryString().setBytes(buf, questionPos + 1,
+                                            end - questionPos - 1);
+             request.requestURI().setBytes(buf, start, questionPos - start);
+         } else {
+@@ -495,7 +488,7 @@ public class InternalAprInputBuffer extends AbstractInputBuffer {
+ 
+         //
+         // Reading the protocol
+-        // Protocol is always US-ASCII
++        // Protocol is always "HTTP/" DIGIT "." DIGIT
+         //
+ 
+         while (!eol) {
+@@ -512,6 +505,8 @@ public class InternalAprInputBuffer extends AbstractInputBuffer {
+                 if (end == 0)
+                     end = pos;
+                 eol = true;
++            } else if (!HttpParser.isHttpProtocol(buf[pos])) {
++                throw new IllegalArgumentException(sm.getString("iib.invalidHttpProtocol"));
+             }
+ 
+             pos++;
+@@ -523,7 +518,7 @@ public class InternalAprInputBuffer extends AbstractInputBuffer {
+         } else {
+             request.protocol().setString("");
+         }
+-        
++
+         return true;
+ 
+     }
+@@ -546,7 +541,7 @@ public class InternalAprInputBuffer extends AbstractInputBuffer {
+ 
+     /**
+      * Parse an HTTP header.
+-     * 
++     *
+      * @return false after reading a blank line (which indicates that the
+      * HTTP header parsing is done
+      */
+@@ -604,7 +599,7 @@ public class InternalAprInputBuffer extends AbstractInputBuffer {
+             if (buf[pos] == Constants.COLON) {
+                 colon = true;
+                 headerValue = headers.addValue(buf, start, pos - start);
+-            } else if (!HTTP_TOKEN_CHAR[buf[pos]]) {
++            } else if (!HttpParser.isToken(buf[pos])) {
+                 // If a non-token header is detected, skip the line and
+                 // ignore the header
+                 skipLine(start);
+@@ -710,14 +705,14 @@ public class InternalAprInputBuffer extends AbstractInputBuffer {
+ 
+     }
+ 
+-    
++
+     private void skipLine(int start) throws IOException {
+         boolean eol = false;
+         int lastRealByte = start;
+         if (pos - 1 > start) {
+             lastRealByte = pos - 1;
+         }
+-        
++
+         while (!eol) {
+ 
+             // Read new bytes if needed
+@@ -741,8 +736,8 @@ public class InternalAprInputBuffer extends AbstractInputBuffer {
+                     lastRealByte - start + 1, "ISO-8859-1")));
+         }
+     }
+-    
+-    
++
++
+     /**
+      * Available bytes (note that due to encoding, this may not correspond )
+      */
+@@ -763,7 +758,7 @@ public class InternalAprInputBuffer extends AbstractInputBuffer {
+     /**
+      * Read some bytes.
+      */
+-    public int doRead(ByteChunk chunk, Request req) 
++    public int doRead(ByteChunk chunk, Request req)
+         throws IOException {
+ 
+         if (lastActiveFilter == -1)
+@@ -779,7 +774,7 @@ public class InternalAprInputBuffer extends AbstractInputBuffer {
+ 
+     /**
+      * Fill the internal buffer using data from the undelying input stream.
+-     * 
++     *
+      * @return false if at end of stream
+      */
+     protected boolean fill()
+@@ -811,7 +806,7 @@ public class InternalAprInputBuffer extends AbstractInputBuffer {
+         } else {
+ 
+             if (buf.length - end < 4500) {
+-                // In this case, the request header was really large, so we allocate a 
++                // In this case, the request header was really large, so we allocate a
+                 // brand new one; the old one will get GCed when subsequent requests
+                 // clear all references
+                 buf = new byte[buf.length];
+@@ -850,14 +845,14 @@ public class InternalAprInputBuffer extends AbstractInputBuffer {
+      * This class is an input buffer which will read its data from an input
+      * stream.
+      */
+-    protected class SocketInputBuffer 
++    protected class SocketInputBuffer
+         implements InputBuffer {
+ 
+ 
+         /**
+          * Read bytes into the specified chunk.
+          */
+-        public int doRead(ByteChunk chunk, Request req ) 
++        public int doRead(ByteChunk chunk, Request req )
+             throws IOException {
+ 
+             if (pos >= lastValid) {
+diff --git a/java/org/apache/coyote/http11/InternalInputBuffer.java b/java/org/apache/coyote/http11/InternalInputBuffer.java
+index ffad9da..94f3017 100644
+--- a/java/org/apache/coyote/http11/InternalInputBuffer.java
++++ b/java/org/apache/coyote/http11/InternalInputBuffer.java
+@@ -23,8 +23,7 @@ import java.io.EOFException;
+ import org.apache.tomcat.util.buf.ByteChunk;
+ import org.apache.tomcat.util.buf.MessageBytes;
+ import org.apache.tomcat.util.http.MimeHeaders;
+-import org.apache.tomcat.util.res.StringManager;
+-
++import org.apache.tomcat.util.http.parser.HttpParser;
+ import org.apache.coyote.InputBuffer;
+ import org.apache.coyote.Request;
+ import org.apache.juli.logging.Log;
+@@ -39,7 +38,7 @@ import org.apache.juli.logging.LogFactory;
+ public class InternalInputBuffer extends AbstractInputBuffer {
+ 
+     private static final Log log = LogFactory.getLog(InternalInputBuffer.class);
+-    
++
+     // -------------------------------------------------------------- Constants
+ 
+ 
+@@ -76,19 +75,8 @@ public class InternalInputBuffer extends AbstractInputBuffer {
+     }
+ 
+ 
+-    // -------------------------------------------------------------- Variables
+-
+-
+-    /**
+-     * The string manager for this package.
+-     */
+-    protected static StringManager sm =
+-        StringManager.getManager(Constants.Package);
+-
+-
+     // ----------------------------------------------------- Instance Variables
+ 
+-
+     /**
+      * Associated Coyote request.
+      */
+@@ -201,7 +189,7 @@ public class InternalInputBuffer extends AbstractInputBuffer {
+ 
+         // FIXME: Check for null ?
+ 
+-        InputFilter[] newFilterLibrary = 
++        InputFilter[] newFilterLibrary =
+             new InputFilter[filterLibrary.length + 1];
+         for (int i = 0; i < filterLibrary.length; i++) {
+             newFilterLibrary[i] = filterLibrary[i];
+@@ -269,7 +257,7 @@ public class InternalInputBuffer extends AbstractInputBuffer {
+ 
+ 
+     /**
+-     * Recycle the input buffer. This should be called when closing the 
++     * Recycle the input buffer. This should be called when closing the
+      * connection.
+      */
+     public void recycle() {
+@@ -294,7 +282,7 @@ public class InternalInputBuffer extends AbstractInputBuffer {
+ 
+     /**
+      * End processing of current HTTP request.
+-     * Note: All bytes of the current request should have been already 
++     * Note: All bytes of the current request should have been already
+      * consumed. This method only resets all the pointers so that we are ready
+      * to parse the next HTTP request.
+      */
+@@ -325,7 +313,7 @@ public class InternalInputBuffer extends AbstractInputBuffer {
+ 
+     /**
+      * End request (consumes leftover bytes).
+-     * 
++     *
+      * @throws IOException an undelying I/O error occured
+      */
+     public void endRequest()
+@@ -340,8 +328,8 @@ public class InternalInputBuffer extends AbstractInputBuffer {
+ 
+ 
+     /**
+-     * Read the request line. This function is meant to be used during the 
+-     * HTTP request header parsing. Do NOT attempt to read the request body 
++     * Read the request line. This function is meant to be used during the
++     * HTTP request header parsing. Do NOT attempt to read the request body
+      * using it.
+      *
+      * @throws IOException If an exception occurs during the underlying socket
+@@ -390,17 +378,16 @@ public class InternalInputBuffer extends AbstractInputBuffer {
+                     throw new EOFException(sm.getString("iib.eof.error"));
+             }
+ 
+-            // Spec says no CR or LF in method name
+-            if (buf[pos] == Constants.CR || buf[pos] == Constants.LF) {
+-                throw new IllegalArgumentException(
+-                        sm.getString("iib.invalidmethod"));
+-            }
+-            // Spec says single SP but it also says be tolerant of HT
++            // Spec says method name is a token followed by a single SP but
++            // also be tolerant of multiple SP and/or HT.
+             if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) {
+                 space = true;
+                 request.method().setBytes(buf, start, pos - start);
++            } else if (!HttpParser.isToken(buf[pos])) {
++                throw new IllegalArgumentException(sm.getString("iib.invalidmethod"));
+             }
+ 
++
+             pos++;
+ 
+         }
+@@ -443,15 +430,17 @@ public class InternalInputBuffer extends AbstractInputBuffer {
+             if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) {
+                 space = true;
+                 end = pos;
+-            } else if ((buf[pos] == Constants.CR) 
++            } else if ((buf[pos] == Constants.CR)
+                        || (buf[pos] == Constants.LF)) {
+                 // HTTP/0.9 style request
+                 eol = true;
+                 space = true;
+                 end = pos;
+-            } else if ((buf[pos] == Constants.QUESTION) 
++            } else if ((buf[pos] == Constants.QUESTION)
+                        && (questionPos == -1)) {
+                 questionPos = pos;
++            } else if (HttpParser.isNotRequestTarget(buf[pos])) {
++                throw new IllegalArgumentException(sm.getString("iib.invalidRequestTarget"));
+             }
+ 
+             pos++;
+@@ -460,7 +449,7 @@ public class InternalInputBuffer extends AbstractInputBuffer {
+ 
+         request.unparsedURI().setBytes(buf, start, end - start);
+         if (questionPos >= 0) {
+-            request.queryString().setBytes(buf, questionPos + 1, 
++            request.queryString().setBytes(buf, questionPos + 1,
+                                            end - questionPos - 1);
+             request.requestURI().setBytes(buf, start, questionPos - start);
+         } else {
+@@ -487,7 +476,7 @@ public class InternalInputBuffer extends AbstractInputBuffer {
+ 
+         //
+         // Reading the protocol
+-        // Protocol is always US-ASCII
++        // Protocol is always "HTTP/" DIGIT "." DIGIT
+         //
+ 
+         while (!eol) {
+@@ -504,6 +493,8 @@ public class InternalInputBuffer extends AbstractInputBuffer {
+                 if (end == 0)
+                     end = pos;
+                 eol = true;
++            } else if (!HttpParser.isHttpProtocol(buf[pos])) {
++                throw new IllegalArgumentException(sm.getString("iib.invalidHttpProtocol"));
+             }
+ 
+             pos++;
+@@ -536,7 +527,7 @@ public class InternalInputBuffer extends AbstractInputBuffer {
+ 
+     /**
+      * Parse an HTTP header.
+-     * 
++     *
+      * @return false after reading a blank line (which indicates that the
+      * HTTP header parsing is done
+      */
+@@ -594,7 +585,7 @@ public class InternalInputBuffer extends AbstractInputBuffer {
+             if (buf[pos] == Constants.COLON) {
+                 colon = true;
+                 headerValue = headers.addValue(buf, start, pos - start);
+-            } else if (!HTTP_TOKEN_CHAR[buf[pos]]) {
++            } else if (!HttpParser.isToken(buf[pos])) {
+                 // If a non-token header is detected, skip the line and
+                 // ignore the header
+                 skipLine(start);
+@@ -708,7 +699,7 @@ public class InternalInputBuffer extends AbstractInputBuffer {
+     /**
+      * Read some bytes.
+      */
+-    public int doRead(ByteChunk chunk, Request req) 
++    public int doRead(ByteChunk chunk, Request req)
+         throws IOException {
+ 
+         if (lastActiveFilter == -1)
+@@ -727,7 +718,7 @@ public class InternalInputBuffer extends AbstractInputBuffer {
+         if (pos - 1 > start) {
+             lastRealByte = pos - 1;
+         }
+-        
++
+         while (!eol) {
+ 
+             // Read new bytes if needed
+@@ -752,10 +743,10 @@ public class InternalInputBuffer extends AbstractInputBuffer {
+         }
+     }
+ 
+-    
++
+     /**
+      * Fill the internal buffer using data from the undelying input stream.
+-     * 
++     *
+      * @return false if at end of stream
+      */
+     protected boolean fill()
+@@ -778,7 +769,7 @@ public class InternalInputBuffer extends AbstractInputBuffer {
+         } else {
+ 
+             if (buf.length - end < 4500) {
+-                // In this case, the request header was really large, so we allocate a 
++                // In this case, the request header was really large, so we allocate a
+                 // brand new one; the old one will get GCed when subsequent requests
+                 // clear all references
+                 buf = new byte[buf.length];
+@@ -805,14 +796,14 @@ public class InternalInputBuffer extends AbstractInputBuffer {
+      * This class is an input buffer which will read its data from an input
+      * stream.
+      */
+-    protected class InputStreamInputBuffer 
++    protected class InputStreamInputBuffer
+         implements InputBuffer {
+ 
+ 
+         /**
+          * Read bytes into the specified chunk.
+          */
+-        public int doRead(ByteChunk chunk, Request req ) 
++        public int doRead(ByteChunk chunk, Request req )
+             throws IOException {
+ 
+             if (pos >= lastValid) {
+diff --git a/java/org/apache/coyote/http11/InternalNioInputBuffer.java b/java/org/apache/coyote/http11/InternalNioInputBuffer.java
+index 7289201..c050a16 100644
+--- a/java/org/apache/coyote/http11/InternalNioInputBuffer.java
++++ b/java/org/apache/coyote/http11/InternalNioInputBuffer.java
+@@ -25,9 +25,9 @@ import org.apache.coyote.Request;
+ import org.apache.tomcat.util.buf.ByteChunk;
+ import org.apache.tomcat.util.buf.MessageBytes;
+ import org.apache.tomcat.util.http.MimeHeaders;
++import org.apache.tomcat.util.http.parser.HttpParser;
+ import org.apache.tomcat.util.net.NioChannel;
+ import org.apache.tomcat.util.net.NioSelectorPool;
+-import org.apache.tomcat.util.res.StringManager;
+ import org.apache.tomcat.util.net.NioEndpoint;
+ 
+ /**
+@@ -88,7 +88,7 @@ public class InternalNioInputBuffer extends AbstractInputBuffer {
+     }
+ 
+     // ----------------------------------------------------------- Constructors
+-    
++
+ 
+     /**
+      * Alternate constructor.
+@@ -119,19 +119,8 @@ public class InternalNioInputBuffer extends AbstractInputBuffer {
+     }
+ 
+ 
+-    // -------------------------------------------------------------- Variables
+-
+-
+-    /**
+-     * The string manager for this package.
+-     */
+-    protected static StringManager sm =
+-        StringManager.getManager(Constants.Package);
+-
+-
+     // ----------------------------------------------------- Instance Variables
+ 
+-
+     /**
+      * Associated Coyote request.
+      */
+@@ -193,12 +182,12 @@ public class InternalNioInputBuffer extends AbstractInputBuffer {
+      * Underlying socket.
+      */
+     protected NioChannel socket;
+-    
++
+     /**
+      * Selector pool, for blocking reads and blocking writes
+      */
+     protected NioSelectorPool pool;
+-    
++
+ 
+     /**
+      * Underlying input buffer.
+@@ -263,7 +252,7 @@ public class InternalNioInputBuffer extends AbstractInputBuffer {
+             buf = new byte[bufLength];
+         }
+     }
+-    
++
+     /**
+      * Get the underlying socket input stream.
+      */
+@@ -271,10 +260,10 @@ public class InternalNioInputBuffer extends AbstractInputBuffer {
+         return socket;
+     }
+ 
+-    public void setSelectorPool(NioSelectorPool pool) { 
++    public void setSelectorPool(NioSelectorPool pool) {
+         this.pool = pool;
+     }
+-    
++
+     public NioSelectorPool getSelectorPool() {
+         return pool;
+     }
+@@ -285,7 +274,7 @@ public class InternalNioInputBuffer extends AbstractInputBuffer {
+      */
+     public void addFilter(InputFilter filter) {
+ 
+-        InputFilter[] newFilterLibrary = 
++        InputFilter[] newFilterLibrary =
+             new InputFilter[filterLibrary.length + 1];
+         for (int i = 0; i < filterLibrary.length; i++) {
+             newFilterLibrary[i] = filterLibrary[i];
+@@ -357,7 +346,7 @@ public class InternalNioInputBuffer extends AbstractInputBuffer {
+     public boolean isReadable() throws IOException {
+         return (pos < lastValid) || (nbRead()>0);
+     }
+-    
++
+     /**
+      * Issues a non blocking read
+      * @return int
+@@ -368,7 +357,7 @@ public class InternalNioInputBuffer extends AbstractInputBuffer {
+     }
+ 
+     /**
+-     * Recycle the input buffer. This should be called when closing the 
++     * Recycle the input buffer. This should be called when closing the
+      * connection.
+      */
+     public void recycle() {
+@@ -399,7 +388,7 @@ public class InternalNioInputBuffer extends AbstractInputBuffer {
+ 
+     /**
+      * End processing of current HTTP request.
+-     * Note: All bytes of the current request should have been already 
++     * Note: All bytes of the current request should have been already
+      * consumed. This method only resets all the pointers so that we are ready
+      * to parse the next HTTP request.
+      */
+@@ -437,7 +426,7 @@ public class InternalNioInputBuffer extends AbstractInputBuffer {
+ 
+     /**
+      * End request (consumes leftover bytes).
+-     * 
++     *
+      * @throws IOException an undelying I/O error occured
+      */
+     public void endRequest()
+@@ -452,14 +441,14 @@ public class InternalNioInputBuffer extends AbstractInputBuffer {
+ 
+ 
+     /**
+-     * Read the request line. This function is meant to be used during the 
+-     * HTTP request header parsing. Do NOT attempt to read the request body 
++     * Read the request line. This function is meant to be used during the
++     * HTTP request header parsing. Do NOT attempt to read the request body
+      * using it.
+      *
+      * @throws IOException If an exception occurs during the underlying socket
+      * read operations, or if the given buffer is not big enough to accommodate
+      * the whole line.
+-     * @return true if data is properly fed; false if no data is available 
++     * @return true if data is properly fed; false if no data is available
+      * immediately and thread should be freed
+      */
+     public boolean parseRequestLine(boolean useAvailableDataOnly)
+@@ -473,7 +462,7 @@ public class InternalNioInputBuffer extends AbstractInputBuffer {
+         if ( parsingRequestLinePhase == 0 ) {
+             byte chr = 0;
+             do {
+-                
++
+                 // Read new bytes if needed
+                 if (pos >= lastValid) {
+                     if (useAvailableDataOnly) {
+@@ -510,14 +499,13 @@ public class InternalNioInputBuffer extends AbstractInputBuffer {
+                     if (!fill(true, false)) //request line parsing
+                         return false;
+                 }
+-                // Spec says no CR or LF in method name
+-                if (buf[pos] == Constants.CR || buf[pos] == Constants.LF) {
+-                    throw new IllegalArgumentException(
+-                            sm.getString("iib.invalidmethod"));
+-                }
++                // Spec says method name is a token followed by a single SP but
++                // also be tolerant of multiple SP and/or HT.
+                 if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) {
+                     space = true;
+                     request.method().setBytes(buf, parsingRequestLineStart, pos - parsingRequestLineStart);
++                } else if (!HttpParser.isToken(buf[pos])) {
++                    throw new IllegalArgumentException(sm.getString("iib.invalidmethod"));
+                 }
+                 pos++;
+             }
+@@ -543,7 +531,7 @@ public class InternalNioInputBuffer extends AbstractInputBuffer {
+         }
+         if (parsingRequestLinePhase == 4) {
+             // Mark the current buffer position
+-            
++
+             int end = 0;
+             //
+             // Reading the URI
+@@ -558,21 +546,23 @@ public class InternalNioInputBuffer extends AbstractInputBuffer {
+                 if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) {
+                     space = true;
+                     end = pos;
+-                } else if ((buf[pos] == Constants.CR) 
++                } else if ((buf[pos] == Constants.CR)
+                            || (buf[pos] == Constants.LF)) {
+                     // HTTP/0.9 style request
+                     parsingRequestLineEol = true;
+                     space = true;
+                     end = pos;
+-                } else if ((buf[pos] == Constants.QUESTION) 
++                } else if ((buf[pos] == Constants.QUESTION)
+                            && (parsingRequestLineQPos == -1)) {
+                     parsingRequestLineQPos = pos;
++                } else if (HttpParser.isNotRequestTarget(buf[pos])) {
++                    throw new IllegalArgumentException(sm.getString("iib.invalidRequestTarget"));
+                 }
+                 pos++;
+             }
+             request.unparsedURI().setBytes(buf, parsingRequestLineStart, end - parsingRequestLineStart);
+             if (parsingRequestLineQPos >= 0) {
+-                request.queryString().setBytes(buf, parsingRequestLineQPos + 1, 
++                request.queryString().setBytes(buf, parsingRequestLineQPos + 1,
+                                                end - parsingRequestLineQPos - 1);
+                 request.requestURI().setBytes(buf, parsingRequestLineStart, parsingRequestLineQPos - parsingRequestLineStart);
+             } else {
+@@ -601,10 +591,10 @@ public class InternalNioInputBuffer extends AbstractInputBuffer {
+             // Mark the current buffer position
+             end = 0;
+         }
+-        if (parsingRequestLinePhase == 6) { 
++        if (parsingRequestLinePhase == 6) {
+             //
+             // Reading the protocol
+-            // Protocol is always US-ASCII
++            // Protocol is always "HTTP/" DIGIT "." DIGIT
+             //
+             while (!parsingRequestLineEol) {
+                 // Read new bytes if needed
+@@ -612,17 +602,19 @@ public class InternalNioInputBuffer extends AbstractInputBuffer {
+                     if (!fill(true, false)) //request line parsing
+                         return false;
+                 }
+-        
++
+                 if (buf[pos] == Constants.CR) {
+                     end = pos;
+                 } else if (buf[pos] == Constants.LF) {
+                     if (end == 0)
+                         end = pos;
+                     parsingRequestLineEol = true;
++                } else if (!HttpParser.isHttpProtocol(buf[pos])) {
++                    throw new IllegalArgumentException(sm.getString("iib.invalidHttpProtocol"));
+                 }
+                 pos++;
+             }
+-        
++
+             if ( (end - parsingRequestLineStart) > 0) {
+                 request.protocol().setBytes(buf, parsingRequestLineStart, end - parsingRequestLineStart);
+             } else {
+@@ -636,7 +628,7 @@ public class InternalNioInputBuffer extends AbstractInputBuffer {
+         }
+         throw new IllegalStateException("Invalid request line parse phase:"+parsingRequestLinePhase);
+     }
+-    
++
+     private void expand(int newsize) {
+         if ( newsize > buf.length ) {
+             if (parsingHeader) {
+@@ -652,7 +644,7 @@ public class InternalNioInputBuffer extends AbstractInputBuffer {
+             tmp = null;
+         }
+     }
+-    
++
+     /**
+      * Perform blocking read with a timeout if desired
+      * @param timeout boolean - if we want to use the timeout data
+@@ -673,7 +665,7 @@ public class InternalNioInputBuffer extends AbstractInputBuffer {
+                 nRead = getSelectorPool().read(socket.getBufHandler().getReadBuffer(),socket,selector,att.getTimeout());
+             } catch ( EOFException eof ) {
+                 nRead = -1;
+-            } finally { 
++            } finally {
+                 if ( selector != null ) getSelectorPool().put(selector);
+             }
+         } else {
+@@ -700,7 +692,7 @@ public class InternalNioInputBuffer extends AbstractInputBuffer {
+     public boolean parseHeaders()
+         throws IOException {
+         HeaderParseStatus status = HeaderParseStatus.HAVE_MORE_HEADERS;
+-        
++
+         do {
+             status = parseHeader();
+             // Checking that
+@@ -729,7 +721,7 @@ public class InternalNioInputBuffer extends AbstractInputBuffer {
+ 
+     /**
+      * Parse an HTTP header.
+-     * 
++     *
+      * @return false after reading a blank line (which indicates that the
+      * HTTP header parsing is done
+      */
+@@ -745,7 +737,7 @@ public class InternalNioInputBuffer extends AbstractInputBuffer {
+ 
+             // Read new bytes if needed
+             if (pos >= lastValid) {
+-                if (!fill(true,false)) {//parse header 
++                if (!fill(true,false)) {//parse header
+                     headerParsePos = HeaderParsePosition.HEADER_START;
+                     return HeaderParseStatus.NEED_MORE_DATA;
+                 }
+@@ -770,18 +762,18 @@ public class InternalNioInputBuffer extends AbstractInputBuffer {
+             // Mark the current buffer position
+             headerData.start = pos;
+             headerParsePos = HeaderParsePosition.HEADER_NAME;
+-        }    
++        }
+ 
+         //
+         // Reading the header name
+         // Header name is always US-ASCII
+         //
+-        
++
+         while (headerParsePos == HeaderParsePosition.HEADER_NAME) {
+ 
+             // Read new bytes if needed
+             if (pos >= lastValid) {
+-                if (!fill(true,false)) { //parse header 
++                if (!fill(true,false)) { //parse header
+                     return HeaderParseStatus.NEED_MORE_DATA;
+                 }
+             }
+@@ -796,7 +788,7 @@ public class InternalNioInputBuffer extends AbstractInputBuffer {
+                 headerData.realPos = pos;
+                 headerData.lastSignificantChar = pos;
+                 break;
+-            } else if (!HTTP_TOKEN_CHAR[chr]) {
++            } else if (!HttpParser.isToken(chr)) {
+                 // If a non-token header is detected, skip the line and
+                 // ignore the header
+                 headerData.lastSignificantChar = pos;
+@@ -828,7 +820,7 @@ public class InternalNioInputBuffer extends AbstractInputBuffer {
+                 while (true) {
+                     // Read new bytes if needed
+                     if (pos >= lastValid) {
+-                        if (!fill(true,false)) {//parse header 
++                        if (!fill(true,false)) {//parse header
+                             //HEADER_VALUE_START
+                             return HeaderParseStatus.NEED_MORE_DATA;
+                         }
+@@ -851,7 +843,7 @@ public class InternalNioInputBuffer extends AbstractInputBuffer {
+ 
+                     // Read new bytes if needed
+                     if (pos >= lastValid) {
+-                        if (!fill(true,false)) {//parse header 
++                        if (!fill(true,false)) {//parse header
+                             //HEADER_VALUE
+                             return HeaderParseStatus.NEED_MORE_DATA;
+                         }
+@@ -884,7 +876,7 @@ public class InternalNioInputBuffer extends AbstractInputBuffer {
+             // Read new bytes if needed
+             if (pos >= lastValid) {
+                 if (!fill(true,false)) {//parse header
+-                    
++
+                     //HEADER_MULTI_LINE
+                     return HeaderParseStatus.NEED_MORE_DATA;
+                 }
+@@ -910,7 +902,7 @@ public class InternalNioInputBuffer extends AbstractInputBuffer {
+         headerData.recycle();
+         return HeaderParseStatus.HAVE_MORE_HEADERS;
+     }
+-    
++
+     private HeaderParseStatus skipLine() throws IOException {
+         headerParsePos = HeaderParsePosition.HEADER_SKIPLINE;
+         boolean eol = false;
+@@ -945,7 +937,7 @@ public class InternalNioInputBuffer extends AbstractInputBuffer {
+         headerParsePos = HeaderParsePosition.HEADER_START;
+         return HeaderParseStatus.HAVE_MORE_HEADERS;
+     }
+-    
++
+     private HeaderParseData headerData = new HeaderParseData();
+     public static class HeaderParseData {
+         /**
+@@ -1004,7 +996,7 @@ public class InternalNioInputBuffer extends AbstractInputBuffer {
+     /**
+      * Read some bytes.
+      */
+-    public int doRead(ByteChunk chunk, Request req) 
++    public int doRead(ByteChunk chunk, Request req)
+         throws IOException {
+ 
+         if (lastActiveFilter == -1)
+@@ -1019,7 +1011,7 @@ public class InternalNioInputBuffer extends AbstractInputBuffer {
+ 
+     /**
+      * Fill the internal buffer using data from the undelying input stream.
+-     * 
++     *
+      * @return false if at end of stream
+      */
+     protected boolean fill(boolean timeout, boolean block)
+@@ -1052,14 +1044,14 @@ public class InternalNioInputBuffer extends AbstractInputBuffer {
+      * This class is an input buffer which will read its data from an input
+      * stream.
+      */
+-    protected class SocketInputBuffer 
++    protected class SocketInputBuffer
+         implements InputBuffer {
+ 
+ 
+         /**
+          * Read bytes into the specified chunk.
+          */
+-        public int doRead(ByteChunk chunk, Request req ) 
++        public int doRead(ByteChunk chunk, Request req )
+             throws IOException {
+ 
+             if (pos >= lastValid) {
+diff --git a/java/org/apache/coyote/http11/LocalStrings.properties b/java/org/apache/coyote/http11/LocalStrings.properties
+index 542eedd..0fb5d0c 100644
+--- a/java/org/apache/coyote/http11/LocalStrings.properties
++++ b/java/org/apache/coyote/http11/LocalStrings.properties
+@@ -62,5 +62,8 @@ http11processor.sendfile.error=Error sending data using sendfile. May be caused
+ 
+ iib.eof.error=Unexpected EOF read on the socket
+ iib.requestheadertoolarge.error=Request header is too large
++iib.invalidheader=The HTTP header line [{0}] does not conform to RFC 7230 and has been ignored.
++iib.invalidRequestTarget=Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 3986
++iib.invalidHttpProtocol=Invalid character found in the HTTP protocol
+ iib.invalidmethod=Invalid character (CR or LF) found in method name
+ 
+diff --git a/java/org/apache/tomcat/util/http/parser/HttpParser.java b/java/org/apache/tomcat/util/http/parser/HttpParser.java
+index b828f71..b92d687 100644
+--- a/java/org/apache/tomcat/util/http/parser/HttpParser.java
++++ b/java/org/apache/tomcat/util/http/parser/HttpParser.java
+@@ -54,8 +54,11 @@ public class HttpParser {
+             new HashMap<String, Integer>();
+ 
+     // Arrays used by isToken(), isHex()
++    private static final boolean[] IS_CONTROL = new boolean[128];
+     private static final boolean isToken[] = new boolean[128];
+     private static final boolean isHex[] = new boolean[128];
++    private static final boolean[] IS_NOT_REQUEST_TARGET = new boolean[128];
++    private static final boolean[] IS_HTTP_PROTOCOL = new boolean[128];
+ 
+     static {
+         // Digest field types.
+@@ -96,6 +99,21 @@ public class HttpParser {
+             } else {
+                 isHex[i] = false;
+             }
++
++            // Not valid for request target.
++            // Combination of multiple rules from RFC7230 and RFC 3986. Must be
++            // ASCII, no controls plus a few additional characters excluded
++            if (IS_CONTROL[i] || i > 127 ||
++                    i == ' ' || i == '\"' || i == '#' || i == '<' || i == '>' || i == '\\' ||
++                    i == '^' || i == '`'  || i == '{' || i == '|' || i == '}') {
++                IS_NOT_REQUEST_TARGET[i] = true;
++            }
++
++            // Not valid for HTTP protocol
++            // "HTTP/" DIGIT "." DIGIT
++            if (i == 'H' || i == 'T' || i == 'P' || i == '/' || i == '.' || (i >= '0' && i <= '9')) {
++                IS_HTTP_PROTOCOL[i] = true;
++            }
+         }
+     }
+ 
+@@ -246,7 +264,7 @@ public class HttpParser {
+         return result.toString();
+     }
+ 
+-    private static boolean isToken(int c) {
++    public static boolean isToken(int c) {
+         // Fast for correct values, slower for incorrect ones
+         try {
+             return isToken[c];
+@@ -255,7 +273,7 @@ public class HttpParser {
+         }
+     }
+ 
+-    private static boolean isHex(int c) {
++    public static boolean isHex(int c) {
+         // Fast for correct values, slower for incorrect ones
+         try {
+             return isHex[c];
+@@ -264,6 +282,29 @@ public class HttpParser {
+         }
+     }
+ 
++
++    public static boolean isNotRequestTarget(int c) {
++        // Fast for valid request target characters, slower for some incorrect
++        // ones
++        try {
++            return IS_NOT_REQUEST_TARGET[c];
++        } catch (ArrayIndexOutOfBoundsException ex) {
++            return true;
++        }
++    }
++
++
++    public static boolean isHttpProtocol(int c) {
++        // Fast for valid HTTP protocol characters, slower for some incorrect
++        // ones
++        try {
++            return IS_HTTP_PROTOCOL[c];
++        } catch (ArrayIndexOutOfBoundsException ex) {
++            return false;
++        }
++    }
++
++
+     // Skip any LWS and return the next char
+     private static int skipLws(StringReader input, boolean withReset)
+             throws IOException {
+diff --git a/java/org/apache/tomcat/util/res/StringManager.java b/java/org/apache/tomcat/util/res/StringManager.java
+index 67c56f0..bd0a84c 100644
+--- a/java/org/apache/tomcat/util/res/StringManager.java
++++ b/java/org/apache/tomcat/util/res/StringManager.java
+@@ -179,6 +179,9 @@ public class StringManager {
+     private static final Map<String,Map<Locale,StringManager>> managers =
+             new Hashtable<String,Map<Locale,StringManager>>();
+ 
++    public static final StringManager getManager(Class<?> clazz) {
++        return getManager(clazz.getPackage().getName());
++    }
+     /**
+      * Get the StringManager for a particular package. If a manager for
+      * a package already exists, it will be reused, else a new
diff --git a/debian/patches/CVE-2016-8735.patch b/debian/patches/CVE-2016-8735.patch
new file mode 100644
index 0000000..0d3a851
--- /dev/null
+++ b/debian/patches/CVE-2016-8735.patch
@@ -0,0 +1,24 @@
+From: Markus Koschany <apo at debian.org>
+Date: Fri, 25 Nov 2016 20:11:08 +0100
+Subject: CVE-2016-8735
+
+Origin: http://svn.apache.org/r1767684
+---
+ java/org/apache/catalina/mbeans/JmxRemoteLifecycleListener.java | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/java/org/apache/catalina/mbeans/JmxRemoteLifecycleListener.java b/java/org/apache/catalina/mbeans/JmxRemoteLifecycleListener.java
+index 7d04955..7f8ff01 100644
+--- a/java/org/apache/catalina/mbeans/JmxRemoteLifecycleListener.java
++++ b/java/org/apache/catalina/mbeans/JmxRemoteLifecycleListener.java
+@@ -198,6 +198,10 @@ public class JmxRemoteLifecycleListener implements LifecycleListener {
+                 csf = new RmiClientLocalhostSocketFactory(csf);
+             }
+ 
++            env.put("jmx.remote.rmi.server.credential.types", new String[] {
++                    String[].class.getName(),
++                    String.class.getName() });
++
+             // Populate the env properties used to create the server
+             if (csf != null) {
+                 env.put(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE,
diff --git a/debian/patches/series b/debian/patches/series
index 5aa3fc5..e2c4068 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -12,3 +12,5 @@ CVE-2016-6794.patch
 CVE-2016-6797.patch
 CVE-2016-5018.patch
 CVE-2016-6796.patch
+CVE-2016-6816.patch
+CVE-2016-8735.patch

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-java/tomcat6.git



More information about the pkg-java-commits mailing list