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