Prevent buffer overrun on NGX_HTTP_REQUEST_HEADER_TOO_LARGE

Maxim Dounin mdounin at mdounin.ru
Tue Oct 7 17:54:46 UTC 2014


Hello!

On Tue, Oct 07, 2014 at 05:23:57PM +0000, Bondarev, Daniil wrote:

> Hi,
> 
> There is an issue in nginx, when it's returning NGX_HTTP_REQUEST_HEADER_TOO_LARGE
> in ngx_http_process_request_headers:
> When large header buffer is full and the last header size is 1 or 2 bytes more
> than NGX_MAX_ERROR_STR - 300, nginx will write 1 or 2 '.' symbols out of large
> header buffer, causing unpredictable behavior.
> 
> To reproduce it you can send request with total headers size of 'large client buffers size' and
> the last header size of 1749. Valgrind will catch this issue:
> 
> ==10776== Invalid write of size 1                                                                                                                                                                                                                                              
> ==10776==    at 0x426E84: ngx_http_process_request_headers (ngx_http_request.c:1230)                                                                                                                                                                                           
> ...
> 
> The following patch fixes this issue:
> 
> # HG changeset patch
> # User Daniil Bondarev <bondarev at amazon.com>
> # Date 1412401143 25200
> # Node ID 2bbb5284ca7ff658ad50254fe0c5bec14247ba75
> # Parent  6bbad2e732458bf53771e80c63a654b3d7f61963
> Prevent buffer overrun on NGX_HTTP_REQUEST_HEADER_TOO_LARGE
> 
> When large header buffer is full and the last header size is 1 or 2 bytes more
> than NGX_MAX_ERROR_STR - 300, nginx will write 1 or 2 '.' symbols out of large
> header buffer, causing unpredictable behavior.
> 
> The fix is, instead of modifying a buffer, just cut the header and print '...'
> in log line if header is too large.
> 
> diff -r 6bbad2e73245 -r 2bbb5284ca7f src/http/ngx_http_request.c
> --- a/src/http/ngx_http_request.c       Wed Aug 27 20:51:01 2014 +0400
> +++ b/src/http/ngx_http_request.c       Fri Oct 03 22:39:03 2014 -0700
> @@ -1171,6 +1171,7 @@
>  {
>      u_char                     *p;
>      size_t                      len;
> +    size_t                      print_len;
>      ssize_t                     n;
>      ngx_int_t                   rc, rv;
>      ngx_table_elt_t            *h;
> @@ -1225,14 +1226,13 @@
>  
>                      len = r->header_in->end - p;
>  
> -                    if (len > NGX_MAX_ERROR_STR - 300) {
> -                        len = NGX_MAX_ERROR_STR - 300;
> -                        p[len++] = '.'; p[len++] = '.'; p[len++] = '.';
> -                    }
> +                    /* Since log line size is limited to NGX_MAX_ERROR_STR,
> +                     * nginx has to limit header size it will print into log. */
> +                    print_len = ngx_min(len, NGX_MAX_ERROR_STR - 300);
>  
>                      ngx_log_error(NGX_LOG_INFO, c->log, 0,
> -                                  "client sent too long header line: \"%*s\"",
> -                                  len, r->header_name_start);
> +                                  "client sent too long header line: \"%*s%s\"",
> +                                  print_len, p, len != print_len ? "..." : "");

Thanks for the report.
What do you think about something as simple as:

--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -1226,7 +1226,7 @@ ngx_http_process_request_headers(ngx_eve
                     len = r->header_in->end - p;
 
                     if (len > NGX_MAX_ERROR_STR - 300) {
-                        len = NGX_MAX_ERROR_STR - 300;
+                        len = NGX_MAX_ERROR_STR - 300 - 3;
                         p[len++] = '.'; p[len++] = '.'; p[len++] = '.';
                     }
 

?

-- 
Maxim Dounin
http://nginx.org/



More information about the nginx-devel mailing list