Commit 6335e76
committed
bugfix: prevent SIGSEGV in receiveuntil __gc on aborted multipart upload.
A client that POSTs a multipart body and aborts the connection
mid-pattern against ngx.req.socket():receiveuntil(boundary) can
SIGSEGV the worker from the LuaJIT GC's __gc finalizer on the
compiled-pattern userdata.
ngx_http_lua_socket_read_error_retval_handler calls
ngx_http_lua_socket_tcp_finalize_read_part directly when the
receiveuntil iterator's recv returns an error (e.g. client RST).
finalize_read_part clears u->buf_in / u->bufs_in and memzeros
u->buffer, but does not detach the compiled-pattern userdata held
in u->input_filter_ctx -- so cp->upstream stays pointing at u and
cp->state stays > 0 (the DFA stopped mid-match).
Later, when LuaJIT GC sweeps the cp userdata,
ngx_http_lua_socket_cleanup_compiled_pattern fires and calls
ngx_http_lua_socket_tcp_read_prepare(r, u, NULL). cp->state > 0
forces the recovery branches that read u->buf_in->buf->pos -- a
NULL deref.
Belt-and-braces fix in two places:
- read_prepare: bail when u->buf_in == NULL after the cp->state
check, before the recovery branches that would deref it.
- finalize_read_part: clear cp->upstream, mirroring the same
detach that ngx_http_lua_socket_tcp_finalize already performs.
This short-circuits the __gc handler at its existing
`if (u != NULL)` guard, so the bad code path is never entered.
Reproducer:
POST a multipart body that ends mid-boundary, then close the
socket with SO_LINGER {1,0} so the server reads RST while the
DFA is mid-match. Lua handler does:
local sock = ngx.req.socket()
local iter = sock:receiveuntil("--" .. BOUNDARY)
while true do
local d = iter(1)
if not d then break end
end
collectgarbage("collect")
With the body shaped as six leading dashes against a 12-dash
boundary leader, cp->state lands at 6 with no DFA fallback,
and the synchronous collectgarbage runs cp's __gc inside the
request -- 100% crash rate.
Crash signature:
#0 ngx_http_lua_socket_tcp_read_prepare (data=0x0)
[inlined memcpy at ngx_http_lua_socket_tcp.c, recovery
branch, u->buf_in == NULL]
#1 ngx_http_lua_socket_cleanup_compiled_pattern
ngx_http_lua_socket_tcp.c
#2 lj_BC_FUNCC buildvm_x86.dasc
#3 gc_call_finalizer lj_gc.c
#4 gc_finalize lj_gc.c
#5 gc_onestep lj_gc.c
#6 lj_gc_fullgc lj_gc.c
#7 lua_gc (what=LUA_GCCOLLECT) lj_api.c
#8 lj_cf_collectgarbage lib_base.c
#9 lj_BC_FUNCC buildvm_x86.dasc
#10 ngx_http_lua_run_thread ngx_http_lua_util.c
#11 ngx_http_lua_socket_tcp_resume_helper ngx_http_lua_socket_tcp.c
#12 ngx_http_lua_socket_tcp_read ngx_http_lua_socket_tcp.c
#13 ngx_http_request_handler src/http/ngx_http_request.c1 parent 41ed26b commit 6335e76
1 file changed
Lines changed: 15 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2803 | 2803 | | |
2804 | 2804 | | |
2805 | 2805 | | |
| 2806 | + | |
| 2807 | + | |
| 2808 | + | |
| 2809 | + | |
| 2810 | + | |
| 2811 | + | |
| 2812 | + | |
2806 | 2813 | | |
2807 | 2814 | | |
2808 | 2815 | | |
| |||
4203 | 4210 | | |
4204 | 4211 | | |
4205 | 4212 | | |
| 4213 | + | |
| 4214 | + | |
| 4215 | + | |
| 4216 | + | |
| 4217 | + | |
| 4218 | + | |
| 4219 | + | |
| 4220 | + | |
4206 | 4221 | | |
4207 | 4222 | | |
4208 | 4223 | | |
| |||
0 commit comments