fix DoS in Connection header value split (reported by Jesse Sipprell, CVE-2012-5533)

git-svn-id: svn://svn.lighttpd.net/lighttpd/branches/lighttpd-1.4.x@2860 152afb58-edef-0310-8abb-c4023f1b3aa9
svn/tags/lighttpd-1.4.32
Stefan Bühler 2012-11-21 12:01:44 +00:00
parent 6200764f05
commit 6edfc40f93
2 changed files with 39 additions and 37 deletions

1
NEWS
View File

@ -14,6 +14,7 @@ NEWS
* detect "x-gzip"/"x-bzip2" as separate encodings, more strict encoding matching (fixes #2443)
* tests: make sure mod_proxy doesn't leave running processes (fixes #2435, thx kibi)
* mod_extforward: log address of untrusted proxy with debug.log-request-handling
* fix DoS in Connection header value split (reported by Jesse Sipprell, CVE-2012-5533)
- 1.4.31 - 2012-05-31
* [ssl] fix segfault in counting renegotiations for openssl versions without TLSEXT/SNI (thx carpii for reporting)

View File

@ -209,9 +209,11 @@ static int request_check_hostname(server *srv, connection *con, buffer *host) {
#endif
static int http_request_split_value(array *vals, buffer *b) {
char *s;
size_t i;
int state = 0;
const char *current;
const char *token_start = NULL, *token_end = NULL;
/*
* parse
*
@ -222,53 +224,52 @@ static int http_request_split_value(array *vals, buffer *b) {
if (b->used == 0) return 0;
s = b->ptr;
for (i =0; i < b->used - 1; ) {
char *start = NULL, *end = NULL;
current = b->ptr;
for (i = 0; i < b->used; ++i, ++current) {
data_string *ds;
switch (state) {
case 0: /* ws */
/* skip ws */
for (; (*s == ' ' || *s == '\t') && i < b->used - 1; i++, s++);
state = 1;
break;
case 1: /* value */
start = s;
for (; *s != ',' && i < b->used - 1; i++, s++);
if (start == s) break; /* empty fields are skipped */
end = s - 1;
for (; end > start && (*end == ' ' || *end == '\t'); end--);
if (start == end) break; /* empty fields are skipped */
if (NULL == (ds = (data_string *)array_get_unused_element(vals, TYPE_STRING))) {
ds = data_string_init();
case 0: /* find start of a token */
switch (*current) {
case ' ':
case '\t': /* skip white space */
case ',': /* skip empty token */
break;
case '\0': /* end of string */
return 0;
default:
/* found real data, switch to state 1 to find the end of the token */
token_start = token_end = current;
state = 1;
break;
}
break;
case 1: /* find end of token and last non white space character */
switch (*current) {
case ' ':
case '\t':
/* space - don't update token_end */
break;
case ',':
case '\0': /* end of string also marks the end of a token */
if (NULL == (ds = (data_string *)array_get_unused_element(vals, TYPE_STRING))) {
ds = data_string_init();
}
buffer_copy_string_len(ds->value, start, end-start+1);
array_insert_unique(vals, (data_unset *)ds);
buffer_copy_string_len(ds->value, token_start, token_end-token_start+1);
array_insert_unique(vals, (data_unset *)ds);
if (*s == ',') {
state = 0;
i++;
s++;
} else {
/* end of string */
state = 2;
break;
default:
/* no white space, update token_end to include current character */
token_end = current;
break;
}
break;
default:
i++;
break;
}
}
return 0;
}