CVE-2016-6816The code in Apache Tomcat 9.0.0.M1 to 9.0.0.M11, 8.5.0 to 8.5.6, 8.0.0.RC1 to 8.0.38, 7.0.0 to 7.0.72, and 6.0.0 to 6.0.47 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.
CWE-20 · Improper input validation
Working exploit published
A reviewed exploit catalogue carries this CVE. Somebody has published code a stranger can run.
CVSS E:P
| Index | Artifact | Stars | First seen |
|---|---|---|---|
| Exploit-DB | Apache Tomcat 6/7/8/9 - Information Disclosure | 2017-04-04 |
A Waratek agent blocks this today.
Applicable rule: CVE has an ARMR patch rule that provides mitigation
| Decided by | armr-patch-file : An ARMR patch file on disk for this CVE |
|---|---|
| Finding | CVE has an ARMR patch rule that provides mitigation |
Shipped files covering this CVE. A CVE genuinely takes more than one: separate Maven artifacts hooking different parser classes, the same patch built for two ARMR versions, or a fix at both the framework and the container.
rules/appservers/tomcat/CVE-2016-6816/patch/2.6/CVE-2016-6816.armr patch rule updated 2026-03-04app("APACHE TOMCAT"):
requires(version: ARMR/2.6)
/***************************************************************************
CVE-2016-6816 (APACHE TOMCAT)
CVSS 3.0 Summary:
Base Score | 7.1
Attack Vector | Network
Attack Complexity | Low
Privileges Required | None
User Interaction | Required
Scope | Changed
Confidentiality | Low
Integrity | Low
Availability | Low
Description:
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.
Resources:
https://www.exploit-db.com/exploits/41783/
https://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html
https://github.com/apache/tomcat80/commit/779d5d34e68e50d2f721897050b147106992f566
https://tomcat.apache.org/security-6.html#Fixed_in_Apache_Tomcat_6.0.48
http://svn.apache.org/viewvc?view=revision&revision=1767683
Affected Operating Systems:
Any
Affected Versions:
Apache Tomcat:
6.0.0 - 6.0.47
7.0.0 - 7.0.72
8.0.0.RC1 - 8.0.38
8.5.0 - 8.5.6
9.0.0.M1 - 9.0.0.M11
Tested Versions:
Apache Tomcat 6.0.45, 6.0.47, 8.0.38
Protection Provided:
Functional
Patch Version:
1.0
***************************************************************************/
/***************************************************************************
CVE-2016-6816: Tomcat 6.0.45, 6.0.47
***************************************************************************/
patch("CVE-2016-6816 :TC6 01"):
function("org/apache/coyote/http11/InternalNioInputBuffer.parseRequestLine(Z)Z",
checksums: ["5e07e435fc", "8959354f2b"]) // 6.0.45, 6.0.47
readreturn("org/apache/coyote/http11/InternalNioInputBuffer.lastValid",
occurrences: [4])
code(language: java, import: ["java.io.EOFException",
"org.apache.coyote.http11.Constants"]):
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 {
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 == '\t') {
IS_SEPARATOR[i] = true;
}
// 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;
}
}
}
private static JavaField bufField;
private static JavaField posField;
private static JavaMethod fillMethod;
public void load() {
bufField =
JavaField.load("org/apache/coyote/http11/InternalNioInputBuffer.buf");
posField =
JavaField.load("org/apache/coyote/http11/InternalNioInputBuffer.pos");
fillMethod =
JavaMethod.load("org/apache/coyote/http11/InternalNioInputBuffer.fill(ZZ)Z");
}
public void patch(JavaFrame frame) {
final Object self = frame.loadThisVariable();
boolean space = frame.loadBooleanVariable(2);
int lastValid = frame.loadIntOperand(0);
byte[] buf = (byte[]) bufField.readObject(self);
int pos = posField.readInt(self);
while (!space) {
if (pos >= lastValid) {
boolean fill = (Boolean) fillMethod.call(self, true, false);
if (!fill) {
frame.returnBoolean(false);
return;
}
}
if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) {
return;
} else if (!isToken(buf[pos])) {
throwIllegalArgumentException(frame);
return;
}
pos++;
}
}
private boolean isToken(int c) {
try {
return IS_TOKEN[c];
} catch (ArrayIndexOutOfBoundsException ex) {
return false;
}
}
private void throwIllegalArgumentException(JavaFrame frame) {
frame.raiseException(
new IllegalArgumentException(
"Invalid character found in method name. HTTP method names must be tokens"));
}
endcode
endpatch
patch("CVE-2016-6816 :TC6 02"):
function("org/apache/coyote/http11/InternalNioInputBuffer.parseRequestLine(Z)Z",
checksums: ["5e07e435fc", "8959354f2b"]) // 6.0.45, 6.0.47
readreturn("org/apache/coyote/http11/InternalNioInputBuffer.lastValid",
occurrences: [6])
code(language: java, import: ["java.io.EOFException",
"org.apache.coyote.http11.Constants"]):
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 {
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 == '\t') {
IS_SEPARATOR[i] = true;
}
// 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;
}
}
}
private static JavaField bufField;
private static JavaField posField;
private static JavaField parsingRequestLineQPosField;
private static JavaMethod fillMethod;
public void load() {
bufField =
JavaField.load("org/apache/coyote/http11/InternalNioInputBuffer.buf");
posField =
JavaField.load("org/apache/coyote/http11/InternalNioInputBuffer.pos");
parsingRequestLineQPosField =
JavaField.load("org/apache/coyote/http11/InternalNioInputBuffer.parsingRequestLineQPos");
fillMethod =
JavaMethod.load("org/apache/coyote/http11/InternalNioInputBuffer.fill(ZZ)Z");
}
public void patch(JavaFrame frame) {
final Object self = frame.loadThisVariable();
boolean space = frame.loadBooleanVariable(3);
int lastValid = frame.loadIntOperand(0);
byte[] buf = (byte[]) bufField.readObject(self);
int pos = posField.readInt(self);
int parsingRequestLineQPos = parsingRequestLineQPosField.readInt(self);
while (!space) {
if (pos >= lastValid) {
boolean fill = (Boolean) fillMethod.call(self, true, false);
if (!fill) {
frame.returnBoolean(false);
return;
}
}
if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) {
return;
} else if ((buf[pos] == Constants.CR) || (buf[pos] == Constants.LF)) {
return;
} else if ((buf[pos] == Constants.QUESTION) && (parsingRequestLineQPos == -1)) {
parsingRequestLineQPos = pos;
} else if (isNotRequestTarget(buf[pos])) {
throwIllegalArgumentException(frame);
return;
}
pos++;
}
}
private boolean isNotRequestTarget(int c) {
try {
return IS_NOT_REQUEST_TARGET[c];
} catch (ArrayIndexOutOfBoundsException ex) {
return true;
}
}
private void throwIllegalArgumentException(JavaFrame frame) {
frame.raiseException(
new IllegalArgumentException(
"Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 3986"));
}
endcode
endpatch
patch("CVE-2016-6816 :TC6 03"):
function("org/apache/coyote/http11/InternalNioInputBuffer.parseRequestLine(Z)Z",
checksums: ["5e07e435fc", "8959354f2b"]) // 6.0.45, 6.0.47
readreturn("org/apache/coyote/http11/InternalNioInputBuffer.lastValid",
occurrences: [8])
code(language: java, import: ["java.io.EOFException",
"org.apache.coyote.http11.Constants"]):
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 {
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 == '\t') {
IS_SEPARATOR[i] = true;
}
// 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;
}
}
}
private static JavaField bufField;
private static JavaField posField;
private static JavaField parsingRequestLineEolField;
private static JavaMethod fillMethod;
public void load() {
bufField =
JavaField.load("org/apache/coyote/http11/InternalNioInputBuffer.buf");
posField =
JavaField.load("org/apache/coyote/http11/InternalNioInputBuffer.pos");
parsingRequestLineEolField =
JavaField.load("org/apache/coyote/http11/InternalNioInputBuffer.parsingRequestLineEol");
fillMethod =
JavaMethod.load("org/apache/coyote/http11/InternalNioInputBuffer.fill(ZZ)Z");
}
public void patch(JavaFrame frame) {
final Object self = frame.loadThisVariable();
int lastValid = frame.loadIntOperand(0);
byte[] buf = (byte[]) bufField.readObject(self);
int pos = posField.readInt(self);
boolean parsingRequestLineEol = parsingRequestLineEolField.readBoolean(self);
while (!parsingRequestLineEol) {
if (pos >= lastValid) {
boolean fill = (Boolean) fillMethod.call(self, true, false);
if (!fill) {
frame.returnBoolean(false);
return;
}
}
if (buf[pos] == Constants.CR) {
;
} else if (buf[pos] == Constants.LF) {
return;
} else if (!isHttpProtocol(buf[pos])) {
throwIllegalArgumentException(frame);
return;
}
pos++;
}
}
private boolean isHttpProtocol(int c) {
try {
return IS_HTTP_PROTOCOL[c];
} catch (ArrayIndexOutOfBoundsException ex) {
return false;
}
}
private void throwIllegalArgumentException(JavaFrame frame) {
frame.raiseException(
new IllegalArgumentException(
"Invalid character found in the HTTP protocol"));
}
endcode
endpatch
patch("CVE-2016-6816 :TC6 04"):
function("org/apache/coyote/http11/InternalNioInputBuffer.parseHeader()Lorg/apache/coyote/http11/InternalNioInputBuffer$HeaderParseStatus;",
checksums: ["5e07e435fc", "8959354f2b"]) // 6.0.45, 6.0.47
readreturn("org/apache/coyote/http11/InternalNioInputBuffer.lastValid",
occurrences: [2])
code(language: java, import: ["java.io.EOFException",
"org.apache.coyote.http11.Constants"]):
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 {
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 == '\t') {
IS_SEPARATOR[i] = true;
}
// 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;
}
}
}
private static JavaField bufField;
private static JavaField posField;
private static JavaField headerParsePosField;
private static JavaField HEADER_NAME_Field;
private static JavaField NEED_MORE_DATA_Field;
private static JavaField lastSignificantCharField;
private static JavaField headerDataField;
private static JavaMethod skipLineMethod;
private static JavaMethod fillMethod;
public void load() {
bufField =
JavaField.load("org/apache/coyote/http11/InternalNioInputBuffer.buf");
posField =
JavaField.load("org/apache/coyote/http11/InternalNioInputBuffer.pos");
headerParsePosField =
JavaField.load("org/apache/coyote/http11/InternalNioInputBuffer.headerParsePos");
HEADER_NAME_Field =
JavaField.load("org/apache/coyote/http11/InternalNioInputBuffer$HeaderParsePosition.HEADER_NAME");
NEED_MORE_DATA_Field =
JavaField.load("org/apache/coyote/http11/AbstractNioInputBuffer$HeaderParseStatus.NEED_MORE_DATA");
lastSignificantCharField =
JavaField.load("org/apache/coyote/http11/InternalNioInputBuffer$HeaderParseData.lastSignificantChar");
headerDataField =
JavaField.load("org/apache/coyote/http11/InternalNioInputBuffer.headerData");
skipLineMethod =
JavaMethod.load("org/apache/coyote/http11/InternalNioInputBuffer.skipLine()Lorg/apache/coyote/http11/InternalNioInputBuffer$HeaderParseStatus;");
fillMethod =
JavaMethod.load("org/apache/coyote/http11/InternalNioInputBuffer.fill(ZZ)Z");
}
public void patch(JavaFrame frame) {
final Object self = frame.loadThisVariable();
byte chr = frame.loadByteVariable(1);
int lastValid = frame.loadIntOperand(0);
byte[] buf = (byte[]) bufField.readObject(self);
int pos = posField.readInt(self);
Object headerParsePos = headerParsePosField.readObject(self);
Object HEADER_NAME = HEADER_NAME_Field.readObject(null);
while (headerParsePos == HEADER_NAME) {
if (pos >= lastValid) {
boolean fill = (Boolean) fillMethod.call(self, true, false);
if (!fill) {
Object NEED_MORE_DATA = NEED_MORE_DATA_Field.readObject(null);
frame.returnObject(NEED_MORE_DATA);
return;
}
}
chr = buf[pos];
if (chr == Constants.COLON) {
return;
} else if (!isToken(buf[pos])) {
Object headerData = headerDataField.readObject(self);
lastSignificantCharField.writeInt(headerData, pos);
frame.returnObject(skipLineMethod.call(self));
return;
}
if ((chr >= Constants.A) && (chr <= Constants.Z)) {
buf[pos] = (byte) (chr - Constants.LC_OFFSET);
}
pos++;
}
}
private boolean isToken(int c) {
try {
return IS_TOKEN[c];
} catch (ArrayIndexOutOfBoundsException ex) {
return false;
}
}
endcode
endpatch
patch("CVE-2016-6816 :TC6 05"):
function("org/apache/coyote/http11/InternalAprInputBuffer.parseRequestLine(Z)Z",
checksums: ["8bc38655b2", "2a87e6b643"]) // 6.0.45, 6.0.47
readreturn("org/apache/coyote/http11/InternalAprInputBuffer.lastValid",
occurrences: [3])
code(language: java, import: ["java.io.EOFException",
"org.apache.coyote.http11.Constants"]):
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 {
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 == '\t') {
IS_SEPARATOR[i] = true;
}
// 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;
}
}
}
private static JavaField bufField;
private static JavaField posField;
private static JavaMethod fillMethod;
public void load() {
bufField =
JavaField.load("org/apache/coyote/http11/InternalAprInputBuffer.buf");
posField =
JavaField.load("org/apache/coyote/http11/InternalAprInputBuffer.pos");
fillMethod =
JavaMethod.load("org/apache/coyote/http11/InternalAprInputBuffer.fill()Z");
}
public void patch(JavaFrame frame) {
Object self = frame.loadThisVariable();
boolean space = frame.loadBooleanVariable(4);
int lastValid = frame.loadIntOperand(0);
byte[] buf = (byte[]) bufField.readObject(self);
int pos = posField.readInt(self);
while (!space) {
if (pos >= lastValid) {
boolean fill = (Boolean) fillMethod.call(self);
if (!fill) {
throwEOFException(frame);
return;
}
}
if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) {
return;
} else if (!isToken(buf[pos])) {
throwIllegalArgumentException(frame);
return;
}
pos++;
}
}
private boolean isToken(int c) {
try {
return IS_TOKEN[c];
} catch (ArrayIndexOutOfBoundsException ex) {
return false;
}
}
private void throwEOFException(JavaFrame frame) {
frame.raiseException(
new EOFException("Unexpected EOF read on the socket"));
}
private void throwIllegalArgumentException(JavaFrame frame) {
frame.raiseException(
new IllegalArgumentException(
"Invalid character found in method name. HTTP method names must be tokens"));
}
endcode
endpatch
patch("CVE-2016-6816 :TC6 06"):
function("org/apache/coyote/http11/InternalAprInputBuffer.parseRequestLine(Z)Z",
checksums: ["8bc38655b2", "2a87e6b643"]) // 6.0.45, 6.0.47
readreturn("org/apache/coyote/http11/InternalAprInputBuffer.lastValid",
occurrences: [5])
code(language: java, import: ["java.io.EOFException",
"org.apache.coyote.http11.Constants"]):
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 {
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 == '\t') {
IS_SEPARATOR[i] = true;
}
// 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;
}
}
}
private static JavaField bufField;
private static JavaField posField;
private static JavaMethod fillMethod;
public void load() {
bufField =
JavaField.load("org/apache/coyote/http11/InternalAprInputBuffer.buf");
posField =
JavaField.load("org/apache/coyote/http11/InternalAprInputBuffer.pos");
fillMethod =
JavaMethod.load("org/apache/coyote/http11/InternalAprInputBuffer.fill()Z");
}
public void patch(JavaFrame frame) {
Object self = frame.loadThisVariable();
boolean space = frame.loadBooleanVariable(4);
int questionPos = frame.loadIntVariable(6);
int lastValid = frame.loadIntOperand(0);
byte[] buf = (byte[]) bufField.readObject(self);
int pos = posField.readInt(self);
while (!space) {
if (pos >= lastValid) {
boolean fill = (Boolean) fillMethod.call(self);
if (!fill) {
throwEOFException(frame);
return;
}
}
if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) {
return;
} else if ((buf[pos] == Constants.CR) || (buf[pos] == Constants.LF)) {
return;
} else if ((buf[pos] == Constants.QUESTION) && (questionPos == -1)) {
questionPos = pos;
} else if (isNotRequestTarget(buf[pos])) {
throwIllegalArgumentException(frame);
return;
}
pos++;
}
}
private boolean isNotRequestTarget(int c) {
try {
return IS_NOT_REQUEST_TARGET[c];
} catch (ArrayIndexOutOfBoundsException ex) {
return true;
}
}
private void throwEOFException(JavaFrame frame) {
frame.raiseException(
new EOFException("Unexpected EOF read on the socket"));
}
private void throwIllegalArgumentException(JavaFrame frame) {
frame.raiseException(
new IllegalArgumentException(
"Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 3986"));
}
endcode
endpatch
patch("CVE-2016-6816 :TC6 07"):
function("org/apache/coyote/http11/InternalAprInputBuffer.parseRequestLine(Z)Z",
checksums: ["8bc38655b2", "2a87e6b643"]) // 6.0.45, 6.0.47
readreturn("org/apache/coyote/http11/InternalAprInputBuffer.lastValid",
occurrences: [7])
code(language: java, import: ["java.io.EOFException",
"org.apache.coyote.http11.Constants"]):
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 {
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 == '\t') {
IS_SEPARATOR[i] = true;
}
// 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;
}
}
}
private static JavaField bufField;
private static JavaField posField;
private static JavaMethod fillMethod;
public void load() {
bufField =
JavaField.load("org/apache/coyote/http11/InternalAprInputBuffer.buf");
posField =
JavaField.load("org/apache/coyote/http11/InternalAprInputBuffer.pos");
fillMethod =
JavaMethod.load("org/apache/coyote/http11/InternalAprInputBuffer.fill()Z");
}
public void patch(JavaFrame frame) {
Object self = frame.loadThisVariable();
boolean eol = frame.loadBooleanVariable(7);
int lastValid = frame.loadIntOperand(0);
byte[] buf = (byte[]) bufField.readObject(self);
int pos = posField.readInt(self);
while (!eol) {
if (pos >= lastValid) {
boolean fill = (Boolean) fillMethod.call(self);
if (!fill) {
throwEOFException(frame);
return;
}
}
if (buf[pos] == Constants.CR) {
;
} else if (buf[pos] == Constants.LF) {
return;
} else if (!isHttpProtocol(buf[pos])) {
throwIllegalArgumentException(frame);
return;
}
pos++;
}
}
private boolean isHttpProtocol(int c) {
try {
return IS_HTTP_PROTOCOL[c];
} catch (ArrayIndexOutOfBoundsException ex) {
return false;
}
}
private void throwEOFException(JavaFrame frame) {
frame.raiseException(
new EOFException("Unexpected EOF read on the socket"));
}
private void throwIllegalArgumentException(JavaFrame frame) {
frame.raiseException(
new IllegalArgumentException(
"Invalid character found in the HTTP protocol"));
}
endcode
endpatch
patch("CVE-2016-6816 :TC6 08"):
function("org/apache/coyote/http11/InternalAprInputBuffer.parseHeader()Z",
checksums: ["8bc38655b2", "2a87e6b643"]) // 6.0.45, 6.0.47
readreturn("org/apache/coyote/http11/InternalAprInputBuffer.lastValid",
occurrences: [2])
code(language: java, import: ["java.io.EOFException",
"org.apache.coyote.http11.Constants"]):
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 {
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 == '\t') {
IS_SEPARATOR[i] = true;
}
// 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;
}
}
}
private static JavaField bufField;
private static JavaField posField;
private static JavaMethod fillMethod;
private static JavaMethod skipLineMethod;
public void load() {
bufField =
JavaField.load("org/apache/coyote/http11/InternalAprInputBuffer.buf");
posField =
JavaField.load("org/apache/coyote/http11/InternalAprInputBuffer.pos");
fillMethod =
JavaMethod.load("org/apache/coyote/http11/InternalAprInputBuffer.fill()Z");
skipLineMethod =
JavaMethod.load("org/apache/coyote/http11/InternalAprInputBuffer.skipLine(I)V");
}
public void patch(JavaFrame frame) {
Object self = frame.loadThisVariable();
byte chr = frame.loadByteVariable(1);
int start = frame.loadIntVariable(2);
boolean colon = frame.loadBooleanVariable(3);
int lastValid = frame.loadIntOperand(0);
byte[] buf = (byte[]) bufField.readObject(self);
int pos = posField.readInt(self);
while (!colon) {
if (pos >= lastValid) {
boolean fill = (Boolean) fillMethod.call(self);
if (!fill) {
throwEOFException(frame);
return;
}
}
if (buf[pos] == Constants.COLON) {
return;
} else if (!isToken(buf[pos])) {
skipLineMethod.call(self, start);
frame.returnBoolean(true);
return;
}
chr = buf[pos];
if ((chr >= Constants.A) && (chr <= Constants.Z)) {
buf[pos] = (byte) (chr - Constants.LC_OFFSET);
}
pos++;
}
}
private boolean isToken(int c) {
try {
return IS_TOKEN[c];
} catch (ArrayIndexOutOfBoundsException ex) {
return false;
}
}
private void throwEOFException(JavaFrame frame) {
frame.raiseException(
new EOFException("Unexpected EOF read on the socket"));
}
endcode
endpatch
patch("CVE-2016-6816 :TC6 09"):
function("org/apache/coyote/http11/InternalInputBuffer.parseRequestLine()V",
checksums: ["28e6907564", "21eb5af62b"]) // 6.0.45, 6.0.47
readreturn("org/apache/coyote/http11/InternalInputBuffer.lastValid",
occurrences: [2])
code(language: java, import: ["java.io.EOFException",
"org.apache.coyote.http11.Constants"]):
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 {
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 == '\t') {
IS_SEPARATOR[i] = true;
}
// 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;
}
}
}
private static JavaField bufField;
private static JavaField posField;
private static JavaMethod fillMethod;
public void load() {
bufField =
JavaField.load("org/apache/coyote/http11/InternalInputBuffer.buf");
posField =
JavaField.load("org/apache/coyote/http11/InternalInputBuffer.pos");
fillMethod =
JavaMethod.load("org/apache/coyote/http11/InternalInputBuffer.fill()Z");
}
public void patch(JavaFrame frame) {
Object self = frame.loadThisVariable();
boolean space = frame.loadBooleanVariable(3);
int lastValid = frame.loadIntOperand(0);
byte[] buf = (byte[]) bufField.readObject(self);
int pos = posField.readInt(self);
while (!space) {
if (pos >= lastValid) {
boolean fill = (Boolean) fillMethod.call(self);
if (!fill) {
throwEOFException(frame);
return;
}
}
if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) {
return;
} else if (!isToken(buf[pos])) {
throwIllegalArgumentException(frame);
return;
}
pos++;
}
}
private boolean isToken(int c) {
try {
return IS_TOKEN[c];
} catch (ArrayIndexOutOfBoundsException ex) {
return false;
}
}
private void throwEOFException(JavaFrame frame) {
frame.raiseException(
new EOFException("Unexpected EOF read on the socket"));
}
private void throwIllegalArgumentException(JavaFrame frame) {
frame.raiseException(
new IllegalArgumentException(
"Invalid character found in method name. HTTP method names must be tokens"));
}
endcode
endpatch
patch("CVE-2016-6816 :TC6 10"):
function("org/apache/coyote/http11/InternalInputBuffer.parseRequestLine()V",
checksums: ["28e6907564", "21eb5af62b"]) // 6.0.45, 6.0.47
readreturn("org/apache/coyote/http11/InternalInputBuffer.lastValid",
occurrences: [4])
code(language: java, import: ["java.io.EOFException",
"org.apache.coyote.http11.Constants"]):
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 {
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 == '\t') {
IS_SEPARATOR[i] = true;
}
// 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;
}
}
}
private static JavaField bufField;
private static JavaField posField;
private static JavaMethod fillMethod;
public void load() {
bufField =
JavaField.load("org/apache/coyote/http11/InternalInputBuffer.buf");
posField =
JavaField.load("org/apache/coyote/http11/InternalInputBuffer.pos");
fillMethod =
JavaMethod.load("org/apache/coyote/http11/InternalInputBuffer.fill()Z");
}
public void patch(JavaFrame frame) {
Object self = frame.loadThisVariable();
boolean space = frame.loadBooleanVariable(3);
int questionPos = frame.loadIntVariable(5);
int lastValid = frame.loadIntOperand(0);
byte[] buf = (byte[]) bufField.readObject(self);
int pos = posField.readInt(self);
while (!space) {
if (pos >= lastValid) {
boolean fill = (Boolean) fillMethod.call(self);
if (!fill) {
throwEOFException(frame);
return;
}
}
if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) {
return;
} else if ((buf[pos] == Constants.CR) || (buf[pos] == Constants.LF)) {
return;
} else if ((buf[pos] == Constants.QUESTION) && (questionPos == -1)) {
questionPos = pos;
} else if (isNotRequestTarget(buf[pos])) {
throwIllegalArgumentException(frame);
return;
}
pos++;
}
}
private boolean isNotRequestTarget(int c) {
try {
return IS_NOT_REQUEST_TARGET[c];
} catch (ArrayIndexOutOfBoundsException ex) {
return true;
}
}
private void throwEOFException(JavaFrame frame) {
frame.raiseException(
new EOFException("Unexpected EOF read on the socket"));
}
private void throwIllegalArgumentException(JavaFrame frame) {
frame.raiseException(
new IllegalArgumentException(
"Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 3986"));
}
endcode
endpatch
patch("CVE-2016-6816 :TC6 11"):
function("org/apache/coyote/http11/InternalInputBuffer.parseRequestLine()V",
checksums: ["28e6907564", "21eb5af62b"]) // 6.0.45, 6.0.47
readreturn("org/apache/coyote/http11/InternalInputBuffer.lastValid",
occurrences: [6])
code(language: java, import: ["java.io.EOFException",
"org.apache.coyote.http11.Constants"]):
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 {
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 == '\t') {
IS_SEPARATOR[i] = true;
}
// 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;
}
}
}
private static JavaField bufField;
private static JavaField posField;
private static JavaMethod fillMethod;
public void load() {
bufField =
JavaField.load("org/apache/coyote/http11/InternalInputBuffer.buf");
posField =
JavaField.load("org/apache/coyote/http11/InternalInputBuffer.pos");
fillMethod =
JavaMethod.load("org/apache/coyote/http11/InternalInputBuffer.fill()Z");
}
public void patch(JavaFrame frame) {
Object self = frame.loadThisVariable();
boolean eol = frame.loadBooleanVariable(6);
int lastValid = frame.loadIntOperand(0);
byte[] buf = (byte[]) bufField.readObject(self);
int pos = posField.readInt(self);
while (!eol) {
if (pos >= lastValid) {
boolean fill = (Boolean) fillMethod.call(self);
if (!fill) {
throwEOFException(frame);
return;
}
}
if (buf[pos] == Constants.CR) {
;
} else if (buf[pos] == Constants.LF) {
return;
} else if (!isHttpProtocol(buf[pos])) {
throwIllegalArgumentException(frame);
return;
}
pos++;
}
}
private boolean isHttpProtocol(int c) {
try {
return IS_HTTP_PROTOCOL[c];
} catch (ArrayIndexOutOfBoundsException ex) {
return false;
}
}
private void throwEOFException(JavaFrame frame) {
frame.raiseException(
new EOFException(
"Unexpected EOF read on the socket"));
}
private void throwIllegalArgumentException(JavaFrame frame) {
frame.raiseException(
new IllegalArgumentException(
"Invalid character found in the HTTP protocol"));
}
endcode
endpatch
patch("CVE-2016-6816 :TC6 12"):
function("org/apache/coyote/http11/InternalInputBuffer.parseHeader()V",
checksums: ["28e6907564", "21eb5af62b"]) // 6.0.45, 6.0.47
readreturn("org/apache/coyote/http11/InternalInputBuffer.lastValid",
occurrences: [2])
code(language: java, import: ["java.io.EOFException",
"org.apache.coyote.http11.Constants"]):
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 {
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 == '\t') {
IS_SEPARATOR[i] = true;
}
// 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;
}
}
}
private static JavaField bufField;
private static JavaField posField;
private static JavaMethod fillMethod;
private static JavaMethod skipLineMethod;
public void load() {
bufField =
JavaField.load("org/apache/coyote/http11/InternalInputBuffer.buf");
posField =
JavaField.load("org/apache/coyote/http11/InternalInputBuffer.pos");
fillMethod =
JavaMethod.load("org/apache/coyote/http11/InternalInputBuffer.fill()Z");
skipLineMethod =
JavaMethod.load("org/apache/coyote/http11/InternalInputBuffer.skipLine(I)V");
}
public void patch(JavaFrame frame) {
Object self = frame.loadThisVariable();
byte chr = frame.loadByteVariable(1);
int start = frame.loadIntVariable(2);
boolean colon = frame.loadBooleanVariable(3);
int lastValid = frame.loadIntOperand(0);
byte[] buf = (byte[]) bufField.readObject(self);
int pos = posField.readInt(self);
while (!colon) {
if (pos >= lastValid) {
boolean fill = (Boolean) fillMethod.call(self);
if (!fill) {
throwEOFException(frame);
return;
}
}
if (buf[pos] == Constants.COLON) {
return;
} else if (!isToken(buf[pos])) {
skipLine.call(self, start);
frame.returnBoolean(true);
return;
}
chr = buf[pos];
if ((chr >= Constants.A) && (chr <= Constants.Z)) {
buf[pos] = (byte) (chr - Constants.LC_OFFSET);
}
pos++;
}
}
private boolean isToken(int c) {
try {
return IS_TOKEN[c];
} catch (ArrayIndexOutOfBoundsException ex) {
return false;
}
}
private void throwEOFException(JavaFrame frame) {
frame.raiseException(
new EOFException("Unexpected EOF read on the socket"));
}
endcode
endpatch
/***************************************************************************
CVE-2016-6816: Tomcat 8.0.38
***************************************************************************/
patch("CVE-2016-6816 :TC8 01"):
function("org/apache/coyote/http11/AbstractInputBuffer.<init>()V",
checksums: ["da7deb64b7"]) // 8.0.38
entry()
code(language: java, import: ["java.util.Collections",
"java.util.HashMap",
"java.util.Map"]):
private static final String BUFFER_MAP = "bufferMap";
private static final String ANIB_PRL_3 = "anib_prl_3";
private static final String ANIB_PRL_5 = "anib_prl_5";
private static final String ANIB_PRL_7 = "anib_prl_7";
private static final String ANIB_PH_2 = "anib_ph_2";
private static final String IAIB_PRL_3 = "iaib_prl_3";
private static final String IAIB_PRL_5 = "iaib_prl_5";
private static final String IAIB_PRL_7 = "iaib_prl_7";
private static final String IAIB_PH_2 = "iaib_ph_2";
private static final String IIB_PRL_2 = "iib_prl_2";
private static final String IIB_PRL_4 = "iib_prl_4";
private static final String IIB_PRL_6 = "iib_prl_6";
private static final String IIB_PH_2 = "iib_ph_2";
private static final Map<String, Boolean> bufferMap =
Collections.synchronizedMap(new HashMap<String, Boolean>());
public void patch(JavaFrame frame) {
// The initial value is 'false', which means the patch
// has not run. Each patch will set it's respective value
// to 'true' once the patch has run.
bufferMap.put(ANIB_PRL_3, false);
bufferMap.put(ANIB_PRL_5, false);
bufferMap.put(ANIB_PRL_7, false);
bufferMap.put(ANIB_PH_2, false);
bufferMap.put(IAIB_PRL_3, false);
bufferMap.put(IAIB_PRL_5, false);
bufferMap.put(IAIB_PRL_7, false);
bufferMap.put(IAIB_PH_2, false);
bufferMap.put(IIB_PRL_2, false);
bufferMap.put(IIB_PRL_4, false);
bufferMap.put(IIB_PRL_6, false);
bufferMap.put(IIB_PH_2, false);
saveValue(BUFFER_MAP, bufferMap);
}
endcode
endpatch
patch("CVE-2016-6816 :TC8 02"):
function("org/apache/coyote/http11/AbstractNioInputBuffer.parseRequestLine(Z)Z",
checksums: ["b0ea19cc74"]) // 8.0.38
readreturn("org/apache/coyote/http11/AbstractNioInputBuffer.lastValid",
occurrences: [3])
code(language: java, import: ["java.util.Map",
"org.apache.coyote.http11.Constants"]):
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 {
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 == '\t') {
IS_SEPARATOR[i] = true;
}
// 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;
}
}
}
private static final String BUFFER_MAP = "bufferMap";
private static final String ANIB_PRL_3 = "anib_prl_3";
private static JavaField lastValidField;
private static JavaField bufField;
private static JavaField posField;
private static JavaMethod fillMethod;
private Object self;
public void load() {
lastValidField = JavaField.load("org/apache/coyote/http11/AbstractInputBuffer.lastValid");
bufField = JavaField.load("org/apache/coyote/http11/AbstractInputBuffer.buf");
posField = JavaField.load("org/apache/coyote/http11/AbstractInputBuffer.pos");
fillMethod = JavaMethod.load("org/apache/coyote/http11/AbstractInputBuffer.fill(Z)Z");
}
public void patch(JavaFrame frame) {
Map<String, Boolean> bufferMap = (Map<String, Boolean>) restoreValue(BUFFER_MAP);
if (bufferMap.get(ANIB_PRL_3)) {
return;
}
bufferMap.put(ANIB_PRL_3, true);
self = frame.loadThisVariable();
boolean space = frame.loadBooleanVariable(2);
int originalPos = pos();
while (!space) {
if (pos() >= lastValid()) {
boolean fill = (boolean) fillMethod.call(self, false);
if (!fill) {
frame.returnBoolean(false);
return;
}
}
if (buf()[pos()] == Constants.SP || buf()[pos()] == Constants.HT) {
pos(originalPos);
return;
} else if (!isToken(buf()[pos()])) {
bufferMap.put(ANIB_PRL_3, false);
throwIllegalArgumentException(frame);
return;
}
pos(pos() + 1);
}
}
private int lastValid() {
return lastValidField.readInt(self);
}
private byte[] buf() {
return (byte[]) bufField.readObject(self);
}
private int pos() {
return posField.readInt(self);
}
private void pos(int i) {
posField.writeInt(self, i);
}
private boolean isToken(int c) {
try {
return IS_TOKEN[c];
} catch (ArrayIndexOutOfBoundsException ex) {
return false;
}
}
private void throwIllegalArgumentException(JavaFrame frame) {
frame.raiseException(
new IllegalArgumentException(
"Invalid character found in method name. HTTP method names must be tokens"));
}
endcode
endpatch
patch("CVE-2016-6816 :TC8 03"):
function("org/apache/coyote/http11/AbstractNioInputBuffer.parseRequestLine(Z)Z",
checksums: ["b0ea19cc74"]) // 8.0.38
readreturn("org/apache/coyote/http11/AbstractNioInputBuffer.lastValid",
occurrences: [5])
code(language: java, import: ["java.util.Map",
"org.apache.coyote.http11.Constants"]):
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 {
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 == '\t') {
IS_SEPARATOR[i] = true;
}
// 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;
}
}
}
private static final String BUFFER_MAP = "bufferMap";
private static final String ANIB_PRL_5 = "anib_prl_5";
private static JavaField lastValidField;
private static JavaField bufField;
private static JavaField posField;
private static JavaField parsingRequestLineQPosField;
private static JavaMethod fillMethod;
private Object self;
public void load() {
lastValidField = JavaField.load("org/apache/coyote/http11/AbstractInputBuffer.lastValid");
bufField = JavaField.load("org/apache/coyote/http11/AbstractInputBuffer.buf");
posField = JavaField.load("org/apache/coyote/http11/AbstractInputBuffer.pos");
parsingRequestLineQPosField = JavaField.load("org/apache/coyote/http11/AbstractNioInputBuffer.parsingRequestLineQPos");
fillMethod = JavaMethod.load("org/apache/coyote/http11/AbstractInputBuffer.fill(Z)Z");
}
public void patch(JavaFrame frame) {
Map<String, Boolean> bufferMap = (Map<String, Boolean>) restoreValue(BUFFER_MAP);
if (bufferMap.get(ANIB_PRL_5)) {
return;
}
bufferMap.put(ANIB_PRL_5, true);
self = frame.loadThisVariable();
boolean space = frame.loadBooleanVariable(3);
int originalPos = pos();
int parsingRequestLineQPos = parsingRequestLineQPos();
while (!space) {
if (pos() >= lastValid()) {
boolean fill = (boolean) fillMethod.call(self, false);
if (!fill) {
frame.returnBoolean(false);
return;
}
}
if (buf()[pos()] == Constants.SP || buf()[pos()] == Constants.HT) {
pos(originalPos);
return;
} else if (buf()[pos()] == Constants.CR || buf()[pos()] == Constants.LF) {
pos(originalPos);
return;
} else if (buf()[pos()] == Constants.QUESTION && parsingRequestLineQPos == -1) {
parsingRequestLineQPos = pos();
} else if (isNotRequestTarget(buf()[pos()])) {
bufferMap.put(ANIB_PRL_5, false);
throwIllegalArgumentException(frame);
return;
}
pos(pos() + 1);
}
}
private int lastValid() {
return lastValidField.readInt(self);
}
private byte[] buf() {
return (byte[]) bufField.readObject(self);
}
private int pos() {
return posField.readInt(self);
}
private void pos(int i) {
posField.writeInt(self, i);
}
private int parsingRequestLineQPos() {
return parsingRequestLineQPosField.readInt(self);
}
public boolean isNotRequestTarget(int c) {
try {
return IS_NOT_REQUEST_TARGET[c];
} catch (ArrayIndexOutOfBoundsException ex) {
return true;
}
}
private void throwIllegalArgumentException(JavaFrame frame) {
frame.raiseException(
new IllegalArgumentException(
"Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 3986"));
}
endcode
endpatch
patch("CVE-2016-6816 :TC8 04"):
function("org/apache/coyote/http11/AbstractNioInputBuffer.parseRequestLine(Z)Z",
checksums: ["b0ea19cc74"]) // 8.0.38
readreturn("org/apache/coyote/http11/AbstractNioInputBuffer.lastValid",
occurrences: [7])
code(language: java, import: ["java.util.Map",
"org.apache.coyote.http11.Constants"]):
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 {
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 == '\t') {
IS_SEPARATOR[i] = true;
}
// 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;
}
}
}
private static final String BUFFER_MAP = "bufferMap";
private static final String ANIB_PRL_7 = "anib_prl_7";
private static JavaField lastValidField;
private static JavaField bufField;
private static JavaField posField;
private static JavaField parsingRequestLineQPosField;
private static JavaField parsingRequestLineEolField;
private static JavaMethod fillMethod;
private Object self;
public void load() {
lastValidField = JavaField.load("org/apache/coyote/http11/AbstractInputBuffer.lastValid");
bufField = JavaField.load("org/apache/coyote/http11/AbstractInputBuffer.buf");
posField = JavaField.load("org/apache/coyote/http11/AbstractInputBuffer.pos");
parsingRequestLineQPosField = JavaField.load("org/apache/coyote/http11/AbstractNioInputBuffer.parsingRequestLineQPos");
parsingRequestLineEolField = JavaField.load("org/apache/coyote/http11/AbstractNioInputBuffer.parsingRequestLineEol");
fillMethod = JavaMethod.load("org/apache/coyote/http11/AbstractInputBuffer.fill(Z)Z");
}
public void patch(JavaFrame frame) {
Map<String, Boolean> bufferMap = (Map<String, Boolean>) restoreValue(BUFFER_MAP);
if (bufferMap.get(ANIB_PRL_7)) {
return;
}
bufferMap.put(ANIB_PRL_7, true);
self = frame.loadThisVariable();
int lastValid = frame.loadIntOperand(0);
boolean parsingRequestLineEol = parsingRequestLineEolField.readBoolean(self);
byte[] buf = (byte[]) bufField.readObject(self);
int pos = posField.readInt(self);
while (!parsingRequestLineEol) {
if (pos >= lastValid) {
boolean fill = (boolean) fillMethod.call(self, false);
if (!fill) {
frame.returnBoolean(false);
return;
}
}
if (buf[pos] == Constants.CR) {
;
} else if (buf[pos] == Constants.LF) {
return;
} else if (!isHttpProtocol(buf[pos])) {
throwIllegalArgumentException(frame);
return;
}
pos++;
}
}
public boolean isHttpProtocol(int c) {
try {
return IS_HTTP_PROTOCOL[c];
} catch (ArrayIndexOutOfBoundsException ex) {
return false;
}
}
private void throwIllegalArgumentException(JavaFrame frame) {
frame.raiseException(
new IllegalArgumentException(
"Invalid character found in the HTTP protocol"));
}
endcode
endpatch
patch("CVE-2016-6816 :TC8 05"):
function("org/apache/coyote/http11/AbstractNioInputBuffer.parseHeader()Lorg/apache/coyote/http11/AbstractNioInputBuffer$HeaderParseStatus;",
checksums: ["b0ea19cc74"]) // 8.0.38
readreturn("org/apache/coyote/http11/AbstractNioInputBuffer.lastValid",
occurrences: [2])
code(language: java, import: ["java.util.Map",
"org.apache.coyote.http11.Constants"]):
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 {
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 == '\t') {
IS_SEPARATOR[i] = true;
}
// 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;
}
}
}
private static JavaField bufField;
private static JavaField posField;
private static JavaField headerParsePosField;
private static JavaMethod fillMethod;
private static JavaField lastSignificantCharField;
private static JavaMethod skipLineMethod;
private static JavaField headerDataField;
private static Object HEADER_NAME;
private static Object NEED_MORE_DATA;
private static boolean shouldInit = true;
public void init() {
HEADER_NAME =
JavaField.load("org/apache/coyote/http11/AbstractNioInputBuffer$HeaderParsePosition.HEADER_NAME")
.readObject(null);
NEED_MORE_DATA =
JavaField.load("org/apache/coyote/http11/AbstractNioInputBuffer$HeaderParseStatus.NEED_MORE_DATA")
.readObject(null);
shouldInit = false;
}
public void load() {
bufField = JavaField.load("org/apache/coyote/http11/AbstractInputBuffer.buf");
posField = JavaField.load("org/apache/coyote/http11/AbstractInputBuffer.pos");
headerParsePosField = JavaField.load("org/apache/coyote/http11/AbstractNioInputBuffer.headerParsePos");
fillMethod = JavaMethod.load("org/apache/coyote/http11/AbstractInputBuffer.fill(Z)Z");
lastSignificantCharField = JavaField.load("org/apache/coyote/http11/AbstractNioInputBuffer$HeaderParseData.lastSignificantChar");
skipLineMethod = JavaMethod.load("org/apache/coyote/http11/AbstractNioInputBuffer.skipLine()Lorg/apache/coyote/http11/AbstractNioInputBuffer$HeaderParseStatus;");
headerDataField = JavaField.load("org/apache/coyote/http11/AbstractNioInputBuffer.headerData");
}
public void patch(JavaFrame frame) {
if (shouldInit) {
init();
}
Object self = frame.loadThisVariable();
byte chr = frame.loadByteVariable(1);
int lastValid = frame.loadIntOperand(0);
byte[] buf = (byte[]) bufField.readObject(self);
int pos = posField.readInt(self);
Object headerParsePos = headerParsePosField.readObject(self);
while (headerParsePos == HEADER_NAME) {
if (pos >= lastValid) {
boolean fill = (boolean) fillMethod.call(self, false);
if (!fill) {
frame.returnObject(NEED_MORE_DATA);
return;
}
}
chr = buf[pos];
if (chr == Constants.COLON) {
return;
} else if (!isToken(chr)) {
Object headerData = headerDataField.readObject(self);
lastSignificantCharField.writeInt(headerData, pos);
frame.returnObject(skipLineMethod.call(self));
return;
}
if ((chr >= Constants.A) && (chr <= Constants.Z)) {
buf[pos] = (byte) (chr - Constants.LC_OFFSET);
}
pos++;
}
}
private boolean isToken(int c) {
try {
return IS_TOKEN[c];
} catch (ArrayIndexOutOfBoundsException ex) {
return false;
}
}
endcode
endpatch
patch("CVE-2016-6816 :TC8 06"):
function("org/apache/coyote/http11/AbstractNioInputBuffer.parseRequestLine(Z)Z",
checksums: ["b0ea19cc74"]) // 8.0.38
exit()
code(language: java, import: ["java.util.Collections",
"java.util.HashMap",
"java.util.Map"]):
private static final String BUFFER_MAP = "bufferMap";
private static final String ANIB_PRL_3 = "anib_prl_3";
private static final String ANIB_PRL_5 = "anib_prl_5";
private static final String ANIB_PRL_7 = "anib_prl_7";
private static final String ANIB_PH_2 = "anib_ph_2";
public void patch(JavaFrame frame) {
Map<String, Boolean> bufferMap = (Map<String, Boolean>) restoreValue(BUFFER_MAP);
bufferMap.put(ANIB_PRL_3, false);
bufferMap.put(ANIB_PRL_5, false);
bufferMap.put(ANIB_PRL_7, false);
bufferMap.put(ANIB_PH_2, false);
}
endcode
endpatch
patch("CVE-2016-6816 :TC8 07"):
function("org/apache/coyote/http11/InternalAprInputBuffer.parseRequestLine(Z)Z",
checksums: ["679efed66a"]) // 8.0.38
readreturn("org/apache/coyote/http11/InternalAprInputBuffer.lastValid",
occurrences: [3])
code(language: java, import: ["java.util.Map",
"java.io.EOFException",
"org.apache.coyote.http11.Constants"]):
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 {
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 == '\t') {
IS_SEPARATOR[i] = true;
}
// 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;
}
}
}
private static JavaField bufField;
private static JavaField posField;
private static JavaMethod fillMethod;
public void load() {
bufField = JavaField.load("org/apache/coyote/http11/AbstractInputBuffer.buf");
posField = JavaField.load("org/apache/coyote/http11/AbstractInputBuffer.pos");
fillMethod = JavaMethod.load("org/apache/coyote/http11/InternalAprInputBuffer.fill(Z)Z");
}
public void patch(JavaFrame frame) {
Object self = frame.loadThisVariable();
boolean space = frame.loadBooleanVariable(4);
int lastValid = frame.loadIntOperand(0);
byte[] buf = (byte[]) bufField.readObject(self);
int pos = posField.readInt(self);
while (!space) {
if (pos >= lastValid) {
boolean fill = (boolean) fillMethod.call(self, true);
if (!fill) {
throwEOFException(frame);
return;
}
}
if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) {
return;
} else if (!isToken(buf[pos])) {
throwIllegalArgumentException(frame);
return;
}
pos++;
}
}
private boolean isToken(int c) {
try {
return IS_TOKEN[c];
} catch (ArrayIndexOutOfBoundsException ex) {
return false;
}
}
private void throwEOFException(JavaFrame frame) {
frame.raiseException(
new EOFException("Unexpected EOF read on the socket"));
}
private void throwIllegalArgumentException(JavaFrame frame) {
frame.raiseException(
new IllegalArgumentException(
"Invalid character found in method name. HTTP method names must be tokens"));
}
endcode
endpatch
patch("CVE-2016-6816 :TC8 08"):
function("org/apache/coyote/http11/InternalAprInputBuffer.parseRequestLine(Z)Z",
checksums: ["679efed66a"]) // 8.0.38
readreturn("org/apache/coyote/http11/InternalAprInputBuffer.lastValid",
occurrences: [5])
code(language: java, import: ["java.util.Map",
"java.io.EOFException",
"org.apache.coyote.http11.Constants"]):
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 {
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 == '\t') {
IS_SEPARATOR[i] = true;
}
// 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;
}
}
}
private static JavaField bufField;
private static JavaField posField;
private static JavaMethod fillMethod;
public void load() {
bufField = JavaField.load("org/apache/coyote/http11/AbstractInputBuffer.buf");
posField = JavaField.load("org/apache/coyote/http11/AbstractInputBuffer.pos");
fillMethod = JavaMethod.load("org/apache/coyote/http11/InternalAprInputBuffer.fill(Z)Z");
}
public void patch(JavaFrame frame) {
final Object self = frame.loadThisVariable();
boolean space = frame.loadBooleanVariable(4);
int questionPos = frame.loadIntVariable(6);
boolean eol = frame.loadBooleanVariable(7);
int lastValid = frame.loadIntOperand(0);
byte[] buf = (byte[]) bufField.readObject(self);
int pos = posField.readInt(self);
while (!space) {
if (pos >= lastValid) {
boolean fill = (boolean) fillMethod.call(self, true);
if (!fill) {
throwEOFException(frame);
return;
}
}
if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) {
return;
} else if ((buf[pos] == Constants.CR) || (buf[pos] == Constants.LF)) {
return;
} else if ((buf[pos] == Constants.QUESTION) && (questionPos == -1)) {
questionPos = pos;
} else if (isNotRequestTarget(buf[pos])) {
throwIllegalArgumentException(frame);
return;
}
pos++;
}
}
public boolean isNotRequestTarget(int c) {
try {
return IS_NOT_REQUEST_TARGET[c];
} catch (ArrayIndexOutOfBoundsException ex) {
return true;
}
}
private void throwEOFException(JavaFrame frame) {
frame.raiseException(
new EOFException("Unexpected EOF read on the socket"));
}
private void throwIllegalArgumentException(JavaFrame frame) {
frame.raiseException(
new IllegalArgumentException(
"Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 3986"));
}
endcode
endpatch
patch("CVE-2016-6816 :TC8 09"):
function("org/apache/coyote/http11/InternalAprInputBuffer.parseRequestLine(Z)Z",
checksums: ["679efed66a"]) // 8.0.38
readreturn("org/apache/coyote/http11/InternalAprInputBuffer.lastValid",
occurrences: [7])
code(language: java, import: ["java.util.Map",
"java.io.EOFException",
"org.apache.coyote.http11.Constants"]):
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 {
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 == '\t') {
IS_SEPARATOR[i] = true;
}
// 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;
}
}
}
private static JavaField bufField;
private static JavaField posField;
private static JavaMethod fillMethod;
public void load() {
bufField = JavaField.load("org/apache/coyote/http11/AbstractInputBuffer.buf");
posField = JavaField.load("org/apache/coyote/http11/AbstractInputBuffer.pos");
fillMethod = JavaMethod.load("org/apache/coyote/http11/InternalAprInputBuffer.fill(Z)Z");
}
public void patch(JavaFrame frame) {
final Object self = frame.loadThisVariable();
boolean space = frame.loadBooleanVariable(4);
boolean eol = frame.loadBooleanVariable(7);
int lastValid = frame.loadIntOperand(0);
byte[] buf = (byte[]) bufField.readObject(self);
int pos = posField.readInt(self);
while (!eol) {
if (pos >= lastValid) {
boolean fill = (boolean) fillMethod.call(self, true);
if (!fill) {
throwEOFException(frame);
return;
}
}
if (buf[pos] == Constants.CR) {
;
} else if (buf[pos] == Constants.LF) {
return;
} else if (!isHttpProtocol(buf[pos])) {
throwIllegalArgumentException(frame);
return;
}
pos++;
}
}
private boolean isHttpProtocol(int c) {
try {
return IS_HTTP_PROTOCOL[c];
} catch (ArrayIndexOutOfBoundsException ex) {
return false;
}
}
private void throwEOFException(JavaFrame frame) {
frame.raiseException(
new EOFException("Unexpected EOF read on the socket"));
}
private void throwIllegalArgumentException(JavaFrame frame) {
frame.raiseException(
new IllegalArgumentException(
"Invalid character found in the HTTP protocol"));
}
endcode
endpatch
patch("CVE-2016-6816 :TC8 10"):
function("org/apache/coyote/http11/InternalAprInputBuffer.parseHeader()Z",
checksums: ["679efed66a"]) // 8.0.38
readreturn("org/apache/coyote/http11/InternalAprInputBuffer.lastValid",
occurrences: [2])
code(language: java, import: ["java.util.Map",
"java.io.EOFException",
"org.apache.coyote.http11.Constants"]):
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 {
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 == '\t') {
IS_SEPARATOR[i] = true;
}
// 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;
}
}
}
private static JavaField bufField;
private static JavaField posField;
private static JavaMethod fillMethod;
private static JavaMethod skipLineMethod;
public void load() {
bufField = JavaField.load("org/apache/coyote/http11/AbstractInputBuffer.buf");
posField = JavaField.load("org/apache/coyote/http11/AbstractInputBuffer.pos");
fillMethod = JavaMethod.load("org/apache/coyote/http11/InternalAprInputBuffer.fill(Z)Z");
skipLineMethod = JavaMethod.load("org/apache/coyote/http11/InternalAprInputBuffer.skipLine(I)V");
}
public void patch(JavaFrame frame) {
Object self = frame.loadThisVariable();
byte chr = frame.loadByteVariable(1);
int start = frame.loadIntVariable(2);
boolean colon = frame.loadBooleanVariable(3);
int lastValid = frame.loadIntOperand(0);
byte[] buf = (byte[]) bufField.readObject(self);
int pos = posField.readInt(self);
while (!colon) {
if (pos >= lastValid) {
boolean fill = (boolean) fillMethod.call(self, true);
if (!fill) {
throwEOFException(frame);
return;
}
}
if (buf[pos] == Constants.COLON) {
return;
} else if (!isToken(buf[pos])) {
skipLineMethod.call(self, start);
frame.returnBoolean(true);
return;
}
chr = buf[pos];
if ((chr >= Constants.A) && (chr <= Constants.Z)) {
buf[pos] = (byte) (chr - Constants.LC_OFFSET);
}
pos++;
}
}
private boolean isToken(int c) {
try {
return IS_TOKEN[c];
} catch (ArrayIndexOutOfBoundsException ex) {
return false;
}
}
private void throwEOFException(JavaFrame frame) {
frame.raiseException(
new EOFException("Unexpected EOF read on the socket"));
}
endcode
endpatch
patch("CVE-2016-6816 :TC8 11"):
function("org/apache/coyote/http11/InternalInputBuffer.parseRequestLine(Z)Z",
checksums: ["bcdfe811f1"]) // 8.0.38
readreturn("org/apache/coyote/http11/InternalInputBuffer.lastValid",
occurrences: [2])
code(language: java, import: ["java.util.Map",
"java.io.EOFException",
"org.apache.coyote.http11.Constants"]):
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 {
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 == '\t') {
IS_SEPARATOR[i] = true;
}
// 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;
}
}
}
private static JavaField bufField;
private static JavaField posField;
private static JavaMethod fillMethod;
public void load() {
bufField = JavaField.load("org/apache/coyote/http11/AbstractInputBuffer.buf");
posField = JavaField.load("org/apache/coyote/http11/AbstractInputBuffer.pos");
fillMethod = JavaMethod.load("org/apache/coyote/http11/InternalInputBuffer.fill()Z");
}
public void patch(JavaFrame frame) {
Object self = frame.loadThisVariable();
boolean space = frame.loadBooleanVariable(4);
int lastValid = frame.loadIntOperand(0);
byte[] buf = (byte[]) bufField.readObject(self);
int pos = posField.readInt(self);
while (!space) {
if (pos >= lastValid) {
boolean fill = (boolean) fillMethod.call(self);
if (!fill) {
throwEOFException(frame);
return;
}
}
if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) {
return;
} else if (!isToken(buf[pos])) {
throwIllegalArgumentException(frame);
return;
}
pos++;
}
}
private boolean isToken(int c) {
try {
return IS_TOKEN[c];
} catch (ArrayIndexOutOfBoundsException ex) {
return false;
}
}
private void throwEOFException(JavaFrame frame) {
frame.raiseException(
new EOFException("Unexpected EOF read on the socket"));
}
private void throwIllegalArgumentException(JavaFrame frame) {
frame.raiseException(
new IllegalArgumentException(
"Invalid character found in method name. HTTP method names must be tokens"));
}
endcode
endpatch
patch("CVE-2016-6816 :TC8 12"):
function("org/apache/coyote/http11/InternalInputBuffer.parseRequestLine(Z)Z",
checksums: ["bcdfe811f1"]) // 8.0.38
readreturn("org/apache/coyote/http11/InternalInputBuffer.lastValid",
occurrences: [4])
code(language: java, import: ["java.util.Map",
"java.io.EOFException",
"org.apache.coyote.http11.Constants"]):
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 {
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 == '\t') {
IS_SEPARATOR[i] = true;
}
// 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;
}
}
}
private static JavaField bufField;
private static JavaField posField;
private static JavaMethod fillMethod;
public void load() {
bufField = JavaField.load("org/apache/coyote/http11/AbstractInputBuffer.buf");
posField = JavaField.load("org/apache/coyote/http11/AbstractInputBuffer.pos");
fillMethod = JavaMethod.load("org/apache/coyote/http11/InternalInputBuffer.fill()Z");
}
public void patch(JavaFrame frame) {
final Object self = frame.loadThisVariable();
boolean space = frame.loadBooleanVariable(4);
int questionPos = frame.loadIntVariable(6);
int lastValid = frame.loadIntOperand(0);
byte[] buf = (byte[]) bufField.readObject(self);
int pos = posField.readInt(self);
while (!space) {
if (pos >= lastValid) {
boolean fill = (boolean) fillMethod.call(self);
if (!fill) {
throwEOFException(frame);
return;
}
}
if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) {
return;
} else if ((buf[pos] == Constants.CR) || (buf[pos] == Constants.LF)) {
return;
} else if ((buf[pos] == Constants.QUESTION) && (questionPos == -1)) {
questionPos = pos;
} else if (isNotRequestTarget(buf[pos])) {
throwIllegalArgumentException(frame);
return;
}
pos++;
}
}
public boolean isNotRequestTarget(int c) {
try {
return IS_NOT_REQUEST_TARGET[c];
} catch (ArrayIndexOutOfBoundsException ex) {
return true;
}
}
private void throwEOFException(JavaFrame frame) {
frame.raiseException(
new EOFException("Unexpected EOF read on the socket"));
}
private void throwIllegalArgumentException(JavaFrame frame) {
frame.raiseException(
new IllegalArgumentException(
"Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 3986"));
}
endcode
endpatch
patch("CVE-2016-6816 :TC8 13"):
function("org/apache/coyote/http11/InternalInputBuffer.parseRequestLine(Z)Z",
checksums: ["bcdfe811f1"]) // 8.0.38
readreturn("org/apache/coyote/http11/InternalInputBuffer.lastValid",
occurrences: [6])
code(language: java, import: ["java.util.Map",
"java.io.EOFException",
"org.apache.coyote.http11.Constants"]):
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 {
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 == '\t') {
IS_SEPARATOR[i] = true;
}
// 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;
}
}
}
private static JavaField bufField;
private static JavaField posField;
private static JavaMethod fillMethod;
public void load() {
bufField = JavaField.load("org/apache/coyote/http11/AbstractInputBuffer.buf");
posField = JavaField.load("org/apache/coyote/http11/AbstractInputBuffer.pos");
fillMethod = JavaMethod.load("org/apache/coyote/http11/InternalInputBuffer.fill()Z");
}
public void patch(JavaFrame frame) {
final Object self = frame.loadThisVariable();
boolean eol = frame.loadBooleanVariable(7);
int lastValid = frame.loadIntOperand(0);
byte[] buf = (byte[]) bufField.readObject(self);
int pos = posField.readInt(self);
while (!eol) {
if (pos >= lastValid) {
boolean fill = (boolean) fillMethod.call(self);
if (!fill) {
throwEOFException(frame);
return;
}
}
if (buf[pos] == Constants.CR) {
;
} else if (buf[pos] == Constants.LF) {
return;
} else if (!isHttpProtocol(buf[pos])) {
throwIllegalArgumentException(frame);
return;
}
pos++;
}
}
public boolean isHttpProtocol(int c) {
try {
return IS_HTTP_PROTOCOL[c];
} catch (ArrayIndexOutOfBoundsException ex) {
return false;
}
}
private void throwEOFException(JavaFrame frame) {
frame.raiseException(
new EOFException("Unexpected EOF read on the socket"));
}
private void throwIllegalArgumentException(JavaFrame frame) {
frame.raiseException(
new IllegalArgumentException(
"Invalid character found in the HTTP protocol"));
}
endcode
endpatch
patch("CVE-2016-6816 :TC8 14"):
function("org/apache/coyote/http11/InternalInputBuffer.parseHeader()Z",
checksums: ["bcdfe811f1"]) // 8.0.38
readreturn("org/apache/coyote/http11/InternalInputBuffer.lastValid",
occurrences: [2])
code(language: java, import: ["java.util.Map",
"java.io.EOFException",
"org.apache.coyote.http11.Constants"]):
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 {
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 == '\t') {
IS_SEPARATOR[i] = true;
}
// 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;
}
}
}
private static JavaField bufField;
private static JavaField posField;
private static JavaMethod fillMethod;
private static JavaMethod skipLineMethod;
public void load() {
bufField = JavaField.load("org/apache/coyote/http11/AbstractInputBuffer.buf");
posField = JavaField.load("org/apache/coyote/http11/AbstractInputBuffer.pos");
fillMethod = JavaMethod.load("org/apache/coyote/http11/InternalInputBuffer.fill()Z");
skipLineMethod = JavaMethod.load("org/apache/coyote/http11/InternalInputBuffer.skipLine(I)V");
}
public void patch(JavaFrame frame) {
Object self = frame.loadThisVariable();
byte chr = frame.loadByteVariable(1);
int start = frame.loadIntVariable(2);
boolean colon = frame.loadBooleanVariable(3);
int lastValid = frame.loadIntOperand(0);
byte[] buf = (byte[]) bufField.readObject(self);
int pos = posField.readInt(self);
while (!colon) {
if (pos >= lastValid) {
boolean fill = (boolean) fillMethod.call(self);
if (!fill) {
throwEOFException(frame);
return;
}
}
if (buf[pos] == Constants.COLON) {
return;
} else if (!isToken(buf[pos])) {
skipLineMethod.call(self, start);
frame.returnBoolean(true);
return;
}
chr = buf[pos];
if ((chr >= Constants.A) && (chr <= Constants.Z)) {
buf[pos] = (byte) (chr - Constants.LC_OFFSET);
}
pos++;
}
}
private boolean isToken(int c) {
try {
return IS_TOKEN[c];
} catch (ArrayIndexOutOfBoundsException ex) {
return false;
}
}
private void throwEOFException(JavaFrame frame) {
frame.raiseException
(new EOFException("Unexpected EOF read on the socket"));
}
endcode
endpatch
endapp
CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:L
2 metrics
VRT selects the newest version's highest entry and
publishes it as cvssScore, newest rather than largest because scores are not comparable
across versions, and highest rather than first because the first entry is frequently a CNA placeholder
scoring 0.0 over NVD's own analysis.
| Version | Score | Band | Vector | Assigner | Type | |
|---|---|---|---|---|---|---|
| CVSS 3.0 | 7.1 | HIGH | CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:L |
NVD | Primary | published |
| CVSS 2.0 | 6.8 | no band published | AV:N/AC:M/Au:N/C:P/I:P/A:P |
NVD | Primary |
| Package Coordinate | Introduced | Fixed | Last affected |
|---|---|---|---|
org.apache.tomcat:tomcat-coyote |
9.0.0.M1 | 9.0.0.M12 |
unbounded |
org.apache.tomcat:tomcat-coyote |
8.5.0 | 8.5.8 |
unbounded |
org.apache.tomcat:tomcat-coyote |
8.0.0RC1 | 8.0.39 |
unbounded |
org.apache.tomcat:tomcat-coyote |
7.0.0 | 7.0.73 |
unbounded |
org.apache.tomcat:tomcat-coyote |
6.0.0 | 6.0.48 |
unbounded |
| Source | Vendor | Product | Scheme | Affected Versions |
|---|---|---|---|---|
| nvd | apache | tomcat | generic | 6.0.0 · 6.0.1 · 6.0.2 · 6.0.3 · 6.0.4 · 6.0.5 · 6.0.6 · 6.0.7 · 6.0.8 · 6.0.9 · 6.0.10 · 6.0.11 · 6.0.12 · 6.0.13 · 6.0.14 · 6.0.15 · 6.0.16 · 6.0.17 · 6.0.18 · 6.0.19 · 6.0.20 · 6.0.21 · 6.0.22 · 6.0.23 · 6.0.24 · 6.0.25 · 6.0.26 · 6.0.27 · 6.0.28 · 6.0.29 · 6.0.30 · 6.0.31 · 6.0.32 · 6.0.33 · 6.0.34 · 6.0.35 · 6.0.36 · 6.0.37 · 6.0.38 · 6.0.39 · 6.0.40 · 6.0.41 · 6.0.42 · 6.0.43 · 6.0.44 · 6.0.45 · 6.0.46 · 6.0.47 · 7.0.0 · 7.0.1 · 7.0.2 · 7.0.3 · 7.0.4 · 7.0.5 · 7.0.6 · 7.0.7 · 7.0.8 · 7.0.9 · 7.0.10 · 7.0.11 · 7.0.12 · 7.0.13 · 7.0.14 · 7.0.15 · 7.0.16 · 7.0.17 · 7.0.18 · 7.0.19 · 7.0.20 · 7.0.21 · 7.0.22 · 7.0.23 · 7.0.24 · 7.0.25 · 7.0.26 · 7.0.27 · 7.0.28 · 7.0.29 · 7.0.30 · 7.0.31 · 7.0.32 · 7.0.33 · 7.0.34 · 7.0.35 · 7.0.36 · 7.0.37 · 7.0.38 · 7.0.39 · 7.0.40 · 7.0.41 · 7.0.42 · 7.0.43 · 7.0.44 · 7.0.45 · 7.0.46 · 7.0.47 · 7.0.48 · 7.0.49 · 7.0.50 · 7.0.51 · 7.0.52 · 7.0.53 · 7.0.54 · 7.0.55 · 7.0.56 · 7.0.57 · 7.0.58 · 7.0.59 · 7.0.60 · 7.0.61 · 7.0.62 · 7.0.63 · 7.0.64 · 7.0.65 · 7.0.66 · 7.0.67 · 7.0.68 · 7.0.69 · 7.0.70 · 7.0.71 · 7.0.72 · 8.0.0 · 8.0.1 · 8.0.2 · 8.0.3 · 8.0.4 · 8.0.5 · 8.0.6 · 8.0.7 · 8.0.8 · 8.0.9 · 8.0.10 · 8.0.11 · 8.0.12 · 8.0.13 · 8.0.14 · 8.0.15 · 8.0.16 · 8.0.17 · 8.0.18 · 8.0.19 · 8.0.20 · 8.0.21 · 8.0.22 · 8.0.23 · 8.0.24 · 8.0.25 · 8.0.26 · 8.0.27 · 8.0.28 · 8.0.29 · 8.0.30 · 8.0.31 · 8.0.32 · 8.0.33 · 8.0.34 · 8.0.35 · 8.0.36 · 8.0.37 · 8.0.38 · 8.5.0 · 8.5.1 · 8.5.2 · 8.5.3 · 8.5.4 · 8.5.5 · 8.5.6 · 9.0.0:milestone1 · 9.0.0:milestone10 · 9.0.0:milestone11 · 9.0.0:milestone2 · 9.0.0:milestone3 · 9.0.0:milestone4 · 9.0.0:milestone5 · 9.0.0:milestone6 · 9.0.0:milestone7 · 9.0.0:milestone8 · 9.0.0:milestone9 |
| osv | org.apache.tomcat | tomcat-coyote | generic | ≥ 6.0.0 and < 6.0.48 · ≥ 7.0.0 and < 7.0.73 · ≥ 8.0.0 and < 8.0.39 · ≥ 8.5.0 and < 8.5.8 · ≥ 9.0.0 and < 9.0.0 |
| Published | 2017-03-20 | By the CVE Program. |
|---|---|---|
| ARMR remediation last updated | 2026-03-04 | Most recent commit touching this CVE's ARMR patch or security rule. |
| Last VRT activity | 2026-03-04 | Most recent commit touching this CVE's classification, patch or rule file. |
| NVD record modified | 2026-06-17 | NVD's own last-modified date for this record. |