Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
SUSE:SLE-12-SP5:GA
tomcat.3464
tomcat-8.0.36-CVE-2016-6816.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File tomcat-8.0.36-CVE-2016-6816.patch of Package tomcat.3464
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 1465480394000) +++ 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> { @@ -228,7 +229,7 @@ if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) { space = true; request.method().setBytes(buf, parsingRequestLineStart, pos - parsingRequestLineStart); - } else if (!HTTP_TOKEN_CHAR[buf[pos]]) { + } else if (!HttpParser.isToken(buf[pos])) { throw new IllegalArgumentException(sm.getString("iib.invalidmethod")); } pos++; @@ -276,9 +277,10 @@ parsingRequestLineEol = true; space = true; end = pos; - } else if ((buf[pos] == Constants.QUESTION) - && (parsingRequestLineQPos == -1)) { + } else if ((buf[pos] == Constants.QUESTION) && (parsingRequestLineQPos == -1)) { parsingRequestLineQPos = pos; + } else if (HttpParser.isNotRequestTarget(buf[pos])) { + throw new IllegalArgumentException(sm.getString("iib.invalidRequestTarget")); } pos++; } @@ -315,7 +317,7 @@ if (parsingRequestLinePhase == 6) { // // Reading the protocol - // Protocol is always US-ASCII + // Protocol is always "HTTP/" DIGIT "." DIGIT // while (!parsingRequestLineEol) { // Read new bytes if needed @@ -330,6 +332,8 @@ if (end == 0) end = pos; parsingRequestLineEol = true; + } else if (!HttpParser.isHttpProtocol(buf[pos])) { + throw new IllegalArgumentException(sm.getString("iib.invalidHttpProtocol")); } pos++; } @@ -470,7 +474,7 @@ headerData.realPos = pos; headerData.lastSignificantChar = pos; break; - } else if (chr < 0 || !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 1465480394000) +++ 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; @@ -142,7 +143,7 @@ if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) { space = true; request.method().setBytes(buf, start, pos - start); - } else if (!HTTP_TOKEN_CHAR[buf[pos]]) { + } else if (!HttpParser.isToken(buf[pos])) { throw new IllegalArgumentException(sm.getString("iib.invalidmethod")); } @@ -193,9 +194,10 @@ eol = true; space = true; end = pos; - } else if ((buf[pos] == Constants.QUESTION) - && (questionPos == -1)) { + } else if ((buf[pos] == Constants.QUESTION) && (questionPos == -1)) { questionPos = pos; + } else if (HttpParser.isNotRequestTarget(buf[pos])) { + throw new IllegalArgumentException(sm.getString("iib.invalidRequestTarget")); } pos++; @@ -230,9 +232,8 @@ // // Reading the protocol - // Protocol is always US-ASCII + // Protocol is always "HTTP/" DIGIT "." DIGIT // - while (!eol) { // Read new bytes if needed @@ -247,6 +248,8 @@ if (end == 0) end = pos; eol = true; + } else if (!HttpParser.isHttpProtocol(buf[pos])) { + throw new IllegalArgumentException(sm.getString("iib.invalidHttpProtocol")); } pos++; @@ -345,7 +348,7 @@ if (buf[pos] == Constants.COLON) { colon = true; headerValue = headers.addValue(buf, start, pos - start); - } else if (buf[pos] < 0 || !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/InternalAprInputBuffer.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- java/org/apache/coyote/http11/InternalAprInputBuffer.java (date 1465480394000) +++ 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; @@ -181,7 +182,7 @@ if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) { space = true; request.method().setBytes(buf, start, pos - start); - } else if (!HTTP_TOKEN_CHAR[buf[pos]]) { + } else if (!HttpParser.isToken(buf[pos])) { throw new IllegalArgumentException(sm.getString("iib.invalidmethod")); } @@ -232,9 +233,10 @@ eol = true; space = true; end = pos; - } else if ((buf[pos] == Constants.QUESTION) - && (questionPos == -1)) { + } else if ((buf[pos] == Constants.QUESTION) && (questionPos == -1)) { questionPos = pos; + } else if (HttpParser.isNotRequestTarget(buf[pos])) { + throw new IllegalArgumentException(sm.getString("iib.invalidRequestTarget")); } pos++; @@ -270,7 +272,7 @@ // // Reading the protocol - // Protocol is always US-ASCII + // Protocol is always "HTTP/" DIGIT "." DIGIT // while (!eol) { @@ -287,6 +289,8 @@ if (end == 0) end = pos; eol = true; + } else if (!HttpParser.isHttpProtocol(buf[pos])) { + throw new IllegalArgumentException(sm.getString("iib.invalidHttpProtocol")); } pos++; @@ -385,7 +389,7 @@ if (buf[pos] == Constants.COLON) { colon = true; headerValue = headers.addValue(buf, start, pos - start); - } else if (buf[pos] < 0 || !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/LocalStrings.properties IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- java/org/apache/coyote/http11/LocalStrings.properties (date 1465480394000) +++ 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.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 @@ -45,4 +47,4 @@ iob.illegalreset=The response may not be reset once it has been committed iob.responseheadertoolarge.error=An attempt was made to write more data to the response headers than there was room available in the buffer. Increase maxHttpHeaderSize on the connector or write less data into the response headers. -iob.nio2.nullSocket=Socket was null while trying to process exception. See Bug 57749 \ No newline at end of file +iob.nio2.nullSocket=Socket was null while trying to process exception. See Bug 57749 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 1465480394000) +++ 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); /** 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 1465480394000) +++ java/org/apache/tomcat/util/http/parser/HttpParser.java (revision ) @@ -34,33 +34,58 @@ */ 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) { return input; @@ -91,23 +116,46 @@ 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) { - // Fast for correct values, slower for incorrect ones + // Fast for correct values, slower for some incorrect ones try { - return isHex[c]; + return IS_HEX[c]; } catch (ArrayIndexOutOfBoundsException ex) { return false; } } + + + 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 static int skipLws(StringReader input, boolean withReset) throws IOException { 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 1465480394000) +++ 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; @@ -103,6 +105,17 @@ } 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 @@ -123,11 +136,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); + } + } } }
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