diff options
author | Stefan Eissing <icing@apache.org> | 2016-12-04 23:06:30 +0100 |
---|---|---|
committer | Stefan Eissing <icing@apache.org> | 2016-12-04 23:06:30 +0100 |
commit | c671673db96e286e2321d5babf05c767cb76a1ef (patch) | |
tree | 3a010f268ebaf21c2baae6bc3c0f673dc8285834 /modules/http2/h2_stream.c | |
parent | Changes done by Daniel, reviewed by me, adding the html files and meta file t... (diff) | |
download | apache2-c671673db96e286e2321d5babf05c767cb76a1ef.tar.xz apache2-c671673db96e286e2321d5babf05c767cb76a1ef.zip |
SECURITY: CVE-2016-8740
mod_http2: properly crafted, endless HTTP/2 CONTINUATION frames could be used to exhaust all server's memory.
Reported by: Naveen Tiwari <naveen.tiwari@asu.edu> and CDF/SEFCOM at Arizona State University
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1772576 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to '')
-rw-r--r-- | modules/http2/h2_stream.c | 61 |
1 files changed, 33 insertions, 28 deletions
diff --git a/modules/http2/h2_stream.c b/modules/http2/h2_stream.c index 2d179d0b0f..d31193909c 100644 --- a/modules/http2/h2_stream.c +++ b/modules/http2/h2_stream.c @@ -333,45 +333,50 @@ apr_status_t h2_stream_add_header(h2_stream *stream, const char *name, size_t nlen, const char *value, size_t vlen) { + int error = 0; ap_assert(stream); - if (!stream->has_response) { - if (name[0] == ':') { - if ((vlen) > stream->session->s->limit_req_line) { - /* pseudo header: approximation of request line size check */ - ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, stream->session->c, - "h2_stream(%ld-%d): pseudo header %s too long", - stream->session->id, stream->id, name); - return h2_stream_set_error(stream, - HTTP_REQUEST_URI_TOO_LARGE); - } - } - else if ((nlen + 2 + vlen) > stream->session->s->limit_req_fieldsize) { - /* header too long */ + if (stream->has_response) { + return APR_EINVAL; + } + ++stream->request_headers_added; + if (name[0] == ':') { + if ((vlen) > stream->session->s->limit_req_line) { + /* pseudo header: approximation of request line size check */ ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, stream->session->c, - "h2_stream(%ld-%d): header %s too long", + "h2_stream(%ld-%d): pseudo header %s too long", stream->session->id, stream->id, name); - return h2_stream_set_error(stream, - HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE); + error = HTTP_REQUEST_URI_TOO_LARGE; } - - if (name[0] != ':') { - ++stream->request_headers_added; - if (stream->request_headers_added - > stream->session->s->limit_req_fields) { - /* too many header lines */ - ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, stream->session->c, - "h2_stream(%ld-%d): too many header lines", - stream->session->id, stream->id); - return h2_stream_set_error(stream, - HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE); - } + } + else if ((nlen + 2 + vlen) > stream->session->s->limit_req_fieldsize) { + /* header too long */ + ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, stream->session->c, + "h2_stream(%ld-%d): header %s too long", + stream->session->id, stream->id, name); + error = HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE; + } + + if (stream->request_headers_added + > stream->session->s->limit_req_fields + 4) { + /* too many header lines, include 4 pseudo headers */ + if (stream->request_headers_added + > stream->session->s->limit_req_fields + 4 + 100) { + /* yeah, right */ + return APR_ECONNRESET; } + ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, stream->session->c, + "h2_stream(%ld-%d): too many header lines", + stream->session->id, stream->id); + error = HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE; } if (h2_stream_is_scheduled(stream)) { return add_trailer(stream, name, nlen, value, vlen); } + else if (error) { + return h2_stream_set_error(stream, error); + } else { if (!stream->rtmp) { stream->rtmp = h2_req_create(stream->id, stream->pool, |