Hello,

I came across a situation when using X-Accel-Redirect could lead to a segfault (tested on the latest version - hg changeset 9207:73eb75bee30f but I believe this has been there for a long time).

It occurs only if the response with the X-Accel-Redirect header is firstly cached (when using proxy_ignore_headers to not interpret this header) and later this cached response is interpreted (after removing the X-Accel-Redirect from the proxy_ignore_headers directive). I prepared a simple testcase to reproduce it: use the attached nginx.conf file and run this curl (the first request caches the response, the second one tries to interpret it):

    curl localhost:1080 localhost:1081

Also, I believe that the core of the problem is because of the ngx_http_finalize_request(r, NGX_DONE); call in the ngx_http_upstream_process_headers function. This call is needed when doing an internal redirect after the real upstream request (to close the upstream request), but when serving from the cache, there is no upstream request to close and this call causes ngx_http_set_lingering_close to be called from the ngx_http_finalize_connection with no active request on the connection yielding to the segfault.

See the attached patch. Tested on our side and this fix works, also run through the nginx-tests and ok,  but I am not thoroughly sure that I am not forgetting some cases.

Thank you for your review.

Sincerely
Jiří Setnička
daemon off;

events {
    worker_connections 768;
}

http {
    proxy_cache_path    /usr/local/nginx/cache levels=1:2 keys_zone=cache:64m;
    proxy_cache         cache;
    proxy_buffering     on;
    proxy_cache_valid   200 1d;

    server {
        listen 1080;
        location / {
            proxy_ignore_headers X-Accel-Redirect;
            proxy_pass http://localhost:1082;
        }
    }

    server {
        listen 1081;
        location / {
            proxy_pass http://localhost:1082;
        }
    }

    server {
        listen 1082;
        location / {
            add_header X-Accel-Redirect "/redirected";
            return 200 "ORIG";
        }
        location /redirected {
            return 200 "REDIRECTED";
        }
    }
}

# HG changeset patch
# User Jiří Setnička <jiri.setni...@cdn77.com>
# Date 1706872218 -3600
#      Fri Feb 02 12:10:18 2024 +0100
# Node ID 0bca1841ee4bcca415630e30964efa4cdb9902cd
# Parent  73eb75bee30f4aee66edfb500270dbb14710aafd
commit 6078c3a06ce16498f0cec5572672146919c9ac74
Author: Jiří Setnička <jiri.setni...@cdn77.com>
Date:   Fri Feb 2 11:58:32 2024 +0100

    Do not finalize additional request on X-Accel-Redirect served from cache

    Response with X-Accel-Redirect could be cached by using the
    proxy_ignore_headers directive. If this directive is then removed, this
    response could be served from the cache and interpreted as redirection.
    Because there is no upstream request the additional
    ngx_http_finalize_request would lead to the segfault.

diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -2814,7 +2814,7 @@ static ngx_int_t
 ngx_http_upstream_process_headers(ngx_http_request_t *r, ngx_http_upstream_t *u)
 {
     ngx_str_t                       uri, args;
-    ngx_uint_t                      i, flags;
+    ngx_uint_t                      i, cached, flags;
     ngx_list_part_t                *part;
     ngx_table_elt_t                *h;
     ngx_http_upstream_header_t     *hh;
@@ -2862,6 +2862,8 @@ ngx_http_upstream_process_headers(ngx_ht
             }
         }
 
+        cached = r->cached;
+
         uri = u->headers_in.x_accel_redirect->value;
 
         if (uri.data[0] == '@') {
@@ -2884,7 +2886,9 @@ ngx_http_upstream_process_headers(ngx_ht
             ngx_http_internal_redirect(r, &uri, &args);
         }
 
-        ngx_http_finalize_request(r, NGX_DONE);
+        if (!cached) {
+            ngx_http_finalize_request(r, NGX_DONE);
+        }
         return NGX_DONE;
     }
 
_______________________________________________
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel

Reply via email to