Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Maintenance:6680
tomcat.openSUSE_Leap_42.1_Update
tomcat-8.0.32-CVE-2016-6816.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File tomcat-8.0.32-CVE-2016-6816.patch of Package tomcat.openSUSE_Leap_42.1_Update
Index: java/org/apache/coyote/http11/LocalStrings.properties IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- java/org/apache/coyote/http11/LocalStrings.properties (date 1454441552000) +++ java/org/apache/coyote/http11/LocalStrings.properties (revision ) @@ -33,8 +33,10 @@ iib.eof.error=Unexpected EOF read on the socket iib.failedread.apr=Read failed with APR/native error code [{0}] iib.filter.npe=You may not add a null filter -iib.invalidheader=The HTTP header line [{0}] does not conform to RFC 2616 and has been ignored. -iib.invalidmethod=Invalid character (CR or LF) found in method name +iib.invalidheader=The HTTP header line [{0}] does not conform to RFC 7230 and has been ignored. +iib.invalidmethod=Invalid character found in method name. HTTP method names must be tokens +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.parseheaders.ise.error=Unexpected state: headers already parsed. Buffer not recycled? iib.readtimeout=Timeout attempting to read data from the socket iib.requestheadertoolarge.error=Request header is too large Index: test/org/apache/catalina/valves/rewrite/TestRewriteValve.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- test/org/apache/catalina/valves/rewrite/TestRewriteValve.java (date 1454441552000) +++ test/org/apache/catalina/valves/rewrite/TestRewriteValve.java (revision ) @@ -16,6 +16,8 @@ */ package org.apache.catalina.valves.rewrite; +import java.nio.charset.StandardCharsets; + import org.junit.Assert; import org.junit.Test; @@ -60,7 +62,62 @@ "RewriteRule /b/(.*).html$ /c/${mapa:$1|dd}", "/b/x.html", "/c/dd"); } + @Test + public void testUtf8WithBothQsFlagsRNE() throws Exception { + // Note %C2%A1 == \u00A1 + // Failing to escape the redirect means UTF-8 bytes in the Location + // header which will be treated as if they are ISO-8859-1 + doTestRewrite("RewriteRule ^/b/(.*)/(.*) /c/\u00A1$1?$2 [R,NE]", + "/b/%C2%A1/id=%C2%A1?di=%C2%AE", null); + } + + @Test + public void testUtf8WithBothQsFlagsRNEQSA() throws Exception { + // Note %C2%A1 == \u00A1 + // Failing to escape the redirect means UTF-8 bytes in the Location + // header which will be treated as if they are ISO-8859-1 + doTestRewrite("RewriteRule ^/b/(.*)/(.*) /c/\u00A1$1?$2 [R,NE,QSA]", + "/b/%C2%A1/id=%C2%A1?di=%C2%AE", null); + } + + @Test + public void testUtf8WithOriginalQsFlagsRNE() throws Exception { + // Note %C2%A1 == \u00A1 + // Failing to escape the redirect means UTF-8 bytes in the Location + // header which will be treated as if they are ISO-8859-1 + doTestRewrite("RewriteRule ^/b/(.*) /c/\u00A1$1 [R,NE]", + "/b/%C2%A1?id=%C2%A1", null); + } + + @Test + public void testUtf8WithRewriteQsFlagsRNE() throws Exception { + // Note %C2%A1 == \u00A1 + // Failing to escape the redirect means UTF-8 bytes in the Location + // header which will be treated as if they are ISO-8859-1 + doTestRewrite("RewriteRule ^/b/(.*)/(.*) /c/\u00A1$1?$2 [R,NE]", + "/b/%C2%A1/id=%C2%A1", null); + } + + @Test + public void testUtf8FlagsRNE() throws Exception { + // Note %C2%A1 == \u00A1 + // Failing to escape the redirect means UTF-8 bytes in the Location + // header which will be treated as if they are ISO-8859-1 + doTestRewrite("RewriteRule ^/b/(.*) /c/\u00A1$1 [R,NE]", "/b/%C2%A1", null); + } + private void doTestRewrite(String config, String request, String expectedURI) throws Exception { + doTestRewrite(config, request, expectedURI, null); + } + + + private void doTestRewrite(String config, String request, String expectedURI, + String expectedQueryString) throws Exception { + doTestRewrite(config, request, expectedURI, expectedQueryString, null); + } + + private void doTestRewrite(String config, String request, String expectedURI, + String expectedQueryString, String expectedAttributeValue) throws Exception { Tomcat tomcat = getTomcatInstance(); // No file system docBase required @@ -81,11 +138,29 @@ tomcat.start(); - ByteChunk res = getUrl("http://localhost:" + getPort() + request); + ByteChunk res = new ByteChunk(); + int rc = getUrl("http://localhost:" + getPort() + request, res, null); + res.setCharset(StandardCharsets.UTF_8); + if (expectedURI == null) { + // Rewrite is expected to fail. Probably because invalid characters + // were written into the request target + Assert.assertEquals(400, rc); + } else { - String body = res.toString(); - RequestDescriptor requestDesc = SnoopResult.parse(body); - String requestURI = requestDesc.getRequestInfo("REQUEST-URI"); - Assert.assertEquals(expectedURI, requestURI); + String body = res.toString(); + RequestDescriptor requestDesc = SnoopResult.parse(body); + String requestURI = requestDesc.getRequestInfo("REQUEST-URI"); + Assert.assertEquals(expectedURI, requestURI); + + if (expectedQueryString != null) { + String queryString = requestDesc.getRequestInfo("REQUEST-QUERY-STRING"); + Assert.assertEquals(expectedQueryString, queryString); + } + + if (expectedAttributeValue != null) { + String attributeValue = requestDesc.getAttribute("X-Test"); + Assert.assertEquals(expectedAttributeValue, attributeValue); + } + } } } Index: java/org/apache/coyote/http11/InternalAprInputBuffer.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- java/org/apache/coyote/http11/InternalAprInputBuffer.java (date 1454441552000) +++ java/org/apache/coyote/http11/InternalAprInputBuffer.java (revision ) @@ -32,6 +32,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.parser.HttpParser; import org.apache.tomcat.util.net.AbstractEndpoint; import org.apache.tomcat.util.net.SocketWrapper; @@ -237,6 +238,8 @@ } else if ((buf[pos] == Constants.QUESTION) && (questionPos == -1)) { questionPos = pos; + } else if (HttpParser.isNotRequestTarget(buf[pos])) { + throw new IllegalArgumentException(sm.getString("iib.invalidRequestTarget")); } pos++; @@ -289,6 +292,8 @@ if (end == 0) end = pos; eol = true; + } else if (!HttpParser.isHttpProtocol(buf[pos])) { + throw new IllegalArgumentException(sm.getString("iib.invalidHttpProtocol")); } pos++; @@ -387,7 +392,7 @@ 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); Index: java/org/apache/tomcat/util/http/parser/HttpParser.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- java/org/apache/tomcat/util/http/parser/HttpParser.java (date 1454441552000) +++ java/org/apache/tomcat/util/http/parser/HttpParser.java (revision ) @@ -34,33 +34,57 @@ */ public class HttpParser { - // Arrays used by isToken(), isHex() - private static final boolean isToken[] = new boolean[128]; - private static final boolean isHex[] = new boolean[128]; + private static final int ARRAY_SIZE = 128; + private static final boolean[] IS_CONTROL = new boolean[ARRAY_SIZE]; + private static final boolean[] IS_SEPARATOR = new boolean[ARRAY_SIZE]; + private static final boolean[] IS_TOKEN = new boolean[ARRAY_SIZE]; + private static final boolean[] IS_HEX = new boolean[ARRAY_SIZE]; + private static final boolean[] IS_NOT_REQUEST_TARGET = new boolean[ARRAY_SIZE]; + private static final boolean[] IS_HTTP_PROTOCOL = new boolean[ARRAY_SIZE]; + static { - // Setup the flag arrays - for (int i = 0; i < 128; i++) { - if (i <= 32) { // includes '\t' and ' ' - isToken[i] = false; - } else if (i == '(' || i == ')' || i == '<' || i == '>' || i == '@' || + for (int i = 0; i < ARRAY_SIZE; i++) { + // Control> 0-31, 127 + if (i < 32 || i == 127) { + IS_CONTROL[i] = true; + } + + // Separator + if ( i == '(' || i == ')' || i == '<' || i == '>' || i == '@' || - i == ',' || i == ';' || i == ':' || i == '\\' || i == '\"' || - i == '/' || i == '[' || i == ']' || i == '?' || i == '=' || + i == ',' || i == ';' || i == ':' || i == '\\' || i == '\"' || + i == '/' || i == '[' || i == ']' || i == '?' || i == '=' || - i == '{' || i == '}') { - isToken[i] = false; - } else { - isToken[i] = true; + i == '{' || i == '}' || i == ' ' || i == '\t') { + IS_SEPARATOR[i] = true; } - if (i >= '0' && i <= '9' || i >= 'A' && i <= 'F' || - i >= 'a' && i <= 'f') { - isHex[i] = true; - } else { - isHex[i] = false; + // Token: Anything 0-127 that is not a control and not a separator + if (!IS_CONTROL[i] && !IS_SEPARATOR[i] && i < 128) { + IS_TOKEN[i] = true; } + + // Hex: 0-9, a-f, A-F + if ((i >= '0' && i <='9') || (i >= 'a' && i <= 'f') || (i >= 'A' && i <= 'F')) { + IS_HEX[i] = true; - } + } + + // 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; + } + } + } + public static String unquote(String input) { if (input == null || input.length() < 2 || input.charAt(0) != '"') { return input; @@ -79,19 +103,19 @@ return result.toString(); } - static boolean isToken(int c) { + public static boolean isToken(int c) { // Fast for correct values, slower for incorrect ones try { - return isToken[c]; + return IS_TOKEN[c]; } catch (ArrayIndexOutOfBoundsException ex) { return false; } } - static boolean isHex(int c) { + public static boolean isHex(int c) { // Fast for correct values, slower for incorrect ones try { - return isHex[c]; + return IS_HEX[c]; } catch (ArrayIndexOutOfBoundsException ex) { return false; } @@ -383,6 +407,27 @@ return result; } + + 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; + } + } /** * Skips all characters until EOF or the specified target is found. Normally Index: java/org/apache/coyote/http11/AbstractNioInputBuffer.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- java/org/apache/coyote/http11/AbstractNioInputBuffer.java (date 1454441552000) +++ java/org/apache/coyote/http11/AbstractNioInputBuffer.java (revision ) @@ -21,6 +21,7 @@ import org.apache.coyote.Request; import org.apache.tomcat.util.buf.MessageBytes; +import org.apache.tomcat.util.http.parser.HttpParser; public abstract class AbstractNioInputBuffer<S> extends AbstractInputBuffer<S> { @@ -231,6 +232,8 @@ 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++; } @@ -280,6 +283,8 @@ } else if ((buf[pos] == Constants.QUESTION) && (parsingRequestLineQPos == -1)) { parsingRequestLineQPos = pos; + } else if (HttpParser.isNotRequestTarget(buf[pos])) { + throw new IllegalArgumentException(sm.getString("iib.invalidRequestTarget")); } pos++; } @@ -331,6 +336,8 @@ if (end == 0) end = pos; parsingRequestLineEol = true; + } else if (!HttpParser.isHttpProtocol(buf[pos])) { + throw new IllegalArgumentException(sm.getString("iib.invalidHttpProtocol")); } pos++; } @@ -471,7 +478,7 @@ 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; Index: java/org/apache/coyote/http11/InternalInputBuffer.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- java/org/apache/coyote/http11/InternalInputBuffer.java (date 1454441552000) +++ java/org/apache/coyote/http11/InternalInputBuffer.java (revision ) @@ -28,6 +28,7 @@ import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.buf.ByteChunk; import org.apache.tomcat.util.buf.MessageBytes; +import org.apache.tomcat.util.http.parser.HttpParser; import org.apache.tomcat.util.net.AbstractEndpoint; import org.apache.tomcat.util.net.SocketWrapper; @@ -199,6 +200,8 @@ } else if ((buf[pos] == Constants.QUESTION) && (questionPos == -1)) { questionPos = pos; + } else if (HttpParser.isNotRequestTarget(buf[pos])) { + throw new IllegalArgumentException(sm.getString("iib.invalidRequestTarget")); } pos++; @@ -250,6 +253,8 @@ if (end == 0) end = pos; eol = true; + } else if (!HttpParser.isHttpProtocol(buf[pos])) { + throw new IllegalArgumentException(sm.getString("iib.invalidHttpProtocol")); } pos++; @@ -348,7 +353,7 @@ 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); Index: java/org/apache/coyote/http11/AbstractInputBuffer.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- java/org/apache/coyote/http11/AbstractInputBuffer.java (date 1454441552000) +++ java/org/apache/coyote/http11/AbstractInputBuffer.java (revision ) @@ -30,62 +30,10 @@ public abstract class AbstractInputBuffer<S> implements InputBuffer{ - protected static final boolean[] HTTP_TOKEN_CHAR = new boolean[128]; - /** * The string manager for this package. */ - protected static final StringManager sm = - StringManager.getManager(Constants.Package); - - - 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(Constants.Package); /**
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor