Merge remote-tracking branch 'origin/patches-2.0'

This commit is contained in:
Nick Mathewson 2011-05-26 17:45:54 -04:00
commit 29e5f7ea1b

54
http.c
View File

@ -841,9 +841,23 @@ evhttp_connection_done(struct evhttp_connection *evcon)
static enum message_read_status static enum message_read_status
evhttp_handle_chunked_read(struct evhttp_request *req, struct evbuffer *buf) evhttp_handle_chunked_read(struct evhttp_request *req, struct evbuffer *buf)
{ {
ev_ssize_t len; if (req == NULL || buf == NULL) {
return DATA_CORRUPTED;
}
while (1) {
size_t buflen;
if ((buflen = evbuffer_get_length(buf)) == 0) {
break;
}
/* evbuffer_get_length returns size_t, but len variable is ssize_t,
* check for overflow conditions */
if (buflen > EV_SSIZE_MAX) {
return DATA_CORRUPTED;
}
while ((len = evbuffer_get_length(buf)) > 0) {
if (req->ntoread < 0) { if (req->ntoread < 0) {
/* Read chunk size */ /* Read chunk size */
ev_int64_t ntoread; ev_int64_t ntoread;
@ -866,11 +880,18 @@ evhttp_handle_chunked_read(struct evhttp_request *req, struct evbuffer *buf)
/* could not get chunk size */ /* could not get chunk size */
return (DATA_CORRUPTED); return (DATA_CORRUPTED);
} }
/* ntoread is signed int64, body_size is unsigned size_t, check for under/overflow conditions */
if (ntoread > EV_SIZE_MAX - req->body_size) {
return DATA_CORRUPTED;
}
if (req->body_size + (size_t)ntoread > req->evcon->max_body_size) { if (req->body_size + (size_t)ntoread > req->evcon->max_body_size) {
/* failed body length test */ /* failed body length test */
event_debug(("Request body is too long")); event_debug(("Request body is too long"));
return (DATA_TOO_LONG); return (DATA_TOO_LONG);
} }
req->body_size += (size_t)ntoread; req->body_size += (size_t)ntoread;
req->ntoread = ntoread; req->ntoread = ntoread;
if (req->ntoread == 0) { if (req->ntoread == 0) {
@ -880,12 +901,17 @@ evhttp_handle_chunked_read(struct evhttp_request *req, struct evbuffer *buf)
continue; continue;
} }
/* req->ntoread is signed int64, len is ssize_t, based on arch,
* ssize_t could only be 32b, check for these conditions */
if (req->ntoread > EV_SSIZE_MAX) {
return DATA_CORRUPTED;
}
/* don't have enough to complete a chunk; wait for more */ /* don't have enough to complete a chunk; wait for more */
if (len < req->ntoread) if (buflen < req->ntoread)
return (MORE_DATA_EXPECTED); return (MORE_DATA_EXPECTED);
/* Completed chunk */ /* Completed chunk */
/* XXXX fixme: what if req->ntoread is > SIZE_T_MAX? */
evbuffer_remove_buffer(buf, req->input_buffer, (size_t)req->ntoread); evbuffer_remove_buffer(buf, req->input_buffer, (size_t)req->ntoread);
req->ntoread = -1; req->ntoread = -1;
if (req->chunk_cb != NULL) { if (req->chunk_cb != NULL) {
@ -953,13 +979,19 @@ evhttp_read_body(struct evhttp_connection *evcon, struct evhttp_request *req)
} }
} else if (req->ntoread < 0) { } else if (req->ntoread < 0) {
/* Read until connection close. */ /* Read until connection close. */
if ((size_t)(req->body_size + evbuffer_get_length(buf)) < req->body_size) {
evhttp_connection_fail(evcon, EVCON_HTTP_INVALID_HEADER);
return;
}
req->body_size += evbuffer_get_length(buf); req->body_size += evbuffer_get_length(buf);
evbuffer_add_buffer(req->input_buffer, buf); evbuffer_add_buffer(req->input_buffer, buf);
} else if (req->chunk_cb != NULL || } else if (req->chunk_cb != NULL || evbuffer_get_length(buf) >= (size_t)req->ntoread) {
evbuffer_get_length(buf) >= (size_t)req->ntoread) { /* XXX: the above get_length comparison has to be fixed for overflow conditions! */
/* We've postponed moving the data until now, but we're /* We've postponed moving the data until now, but we're
* about to use it. */ * about to use it. */
size_t n = evbuffer_get_length(buf); size_t n = evbuffer_get_length(buf);
if (n > (size_t) req->ntoread) if (n > (size_t) req->ntoread)
n = (size_t) req->ntoread; n = (size_t) req->ntoread;
req->ntoread -= n; req->ntoread -= n;
@ -970,6 +1002,7 @@ evhttp_read_body(struct evhttp_connection *evcon, struct evhttp_request *req)
if (req->body_size > req->evcon->max_body_size || if (req->body_size > req->evcon->max_body_size ||
(!req->chunked && req->ntoread >= 0 && (!req->chunked && req->ntoread >= 0 &&
(size_t)req->ntoread > req->evcon->max_body_size)) { (size_t)req->ntoread > req->evcon->max_body_size)) {
/* XXX: The above casted comparison must checked for overflow */
/* failed body length test */ /* failed body length test */
event_debug(("Request body is too long")); event_debug(("Request body is too long"));
evhttp_connection_fail(evcon, evhttp_connection_fail(evcon,
@ -2000,12 +2033,13 @@ evhttp_get_body(struct evhttp_connection *evcon, struct evhttp_request *req)
no, we should respond with an error. For no, we should respond with an error. For
now, just optimistically tell the client to now, just optimistically tell the client to
send their message body. */ send their message body. */
if (req->ntoread > 0 && if (req->ntoread > 0) {
(size_t)req->ntoread > req->evcon->max_body_size) { /* ntoread is ev_int64_t, max_body_size is ev_uint64_t */
evhttp_send_error(req, HTTP_ENTITYTOOLARGE, if ((req->evcon->max_body_size <= EV_INT64_MAX) && (ev_uint64_t)req->ntoread > req->evcon->max_body_size) {
NULL); evhttp_send_error(req, HTTP_ENTITYTOOLARGE, NULL);
return; return;
} }
}
if (!evbuffer_get_length(bufferevent_get_input(evcon->bufev))) if (!evbuffer_get_length(bufferevent_get_input(evcon->bufev)))
evhttp_send_continue(evcon, req); evhttp_send_continue(evcon, req);
} else { } else {