summaryrefslogtreecommitdiff
path: root/http.c
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2011-05-26 17:45:54 -0400
committerNick Mathewson <nickm@torproject.org>2011-05-26 17:45:54 -0400
commit29e5f7ea1bcc05b8505860ae5f6c6c0e4ac2563a (patch)
tree6e07e2d8dc5430ec6a8da140a5f2d3edf37ba956 /http.c
parent95f70166df3bc9c0817ef98aa3711564300d5bb3 (diff)
parentdbb3c65288e219ce3f05efc3fb6c84ff96cf24a9 (diff)
downloadlibevent-29e5f7ea1bcc05b8505860ae5f6c6c0e4ac2563a.tar.gz
Merge remote-tracking branch 'origin/patches-2.0'
Diffstat (limited to 'http.c')
-rw-r--r--http.c56
1 files changed, 45 insertions, 11 deletions
diff --git a/http.c b/http.c
index ac928980..aa951e91 100644
--- a/http.c
+++ b/http.c
@@ -841,9 +841,23 @@ evhttp_connection_done(struct evhttp_connection *evcon)
static enum message_read_status
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) {
/* Read chunk size */
ev_int64_t ntoread;
@@ -866,11 +880,18 @@ evhttp_handle_chunked_read(struct evhttp_request *req, struct evbuffer *buf)
/* could not get chunk size */
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) {
/* failed body length test */
event_debug(("Request body is too long"));
return (DATA_TOO_LONG);
}
+
req->body_size += (size_t)ntoread;
req->ntoread = ntoread;
if (req->ntoread == 0) {
@@ -880,12 +901,17 @@ evhttp_handle_chunked_read(struct evhttp_request *req, struct evbuffer *buf)
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 */
- if (len < req->ntoread)
+ if (buflen < req->ntoread)
return (MORE_DATA_EXPECTED);
/* Completed chunk */
- /* XXXX fixme: what if req->ntoread is > SIZE_T_MAX? */
evbuffer_remove_buffer(buf, req->input_buffer, (size_t)req->ntoread);
req->ntoread = -1;
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) {
/* 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);
evbuffer_add_buffer(req->input_buffer, buf);
- } else if (req->chunk_cb != NULL ||
- evbuffer_get_length(buf) >= (size_t)req->ntoread) {
+ } else if (req->chunk_cb != NULL || 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
* about to use it. */
size_t n = evbuffer_get_length(buf);
+
if (n > (size_t) req->ntoread)
n = (size_t) req->ntoread;
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 ||
(!req->chunked && req->ntoread >= 0 &&
(size_t)req->ntoread > req->evcon->max_body_size)) {
+ /* XXX: The above casted comparison must checked for overflow */
/* failed body length test */
event_debug(("Request body is too long"));
evhttp_connection_fail(evcon,
@@ -2000,11 +2033,12 @@ evhttp_get_body(struct evhttp_connection *evcon, struct evhttp_request *req)
no, we should respond with an error. For
now, just optimistically tell the client to
send their message body. */
- if (req->ntoread > 0 &&
- (size_t)req->ntoread > req->evcon->max_body_size) {
- evhttp_send_error(req, HTTP_ENTITYTOOLARGE,
- NULL);
- return;
+ if (req->ntoread > 0) {
+ /* ntoread is ev_int64_t, max_body_size is ev_uint64_t */
+ if ((req->evcon->max_body_size <= EV_INT64_MAX) && (ev_uint64_t)req->ntoread > req->evcon->max_body_size) {
+ evhttp_send_error(req, HTTP_ENTITYTOOLARGE, NULL);
+ return;
+ }
}
if (!evbuffer_get_length(bufferevent_get_input(evcon->bufev)))
evhttp_send_continue(evcon, req);