diff options
author | Nick Mathewson <nickm@torproject.org> | 2011-05-26 17:45:54 -0400 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2011-05-26 17:45:54 -0400 |
commit | 29e5f7ea1bcc05b8505860ae5f6c6c0e4ac2563a (patch) | |
tree | 6e07e2d8dc5430ec6a8da140a5f2d3edf37ba956 /http.c | |
parent | 95f70166df3bc9c0817ef98aa3711564300d5bb3 (diff) | |
parent | dbb3c65288e219ce3f05efc3fb6c84ff96cf24a9 (diff) | |
download | libevent-29e5f7ea1bcc05b8505860ae5f6c6c0e4ac2563a.tar.gz |
Merge remote-tracking branch 'origin/patches-2.0'
Diffstat (limited to 'http.c')
-rw-r--r-- | http.c | 56 |
1 files changed, 45 insertions, 11 deletions
@@ -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); |