Fix use-after-free and double-free in upstream NTLM connection teardown#4
Draft
Fix use-after-free and double-free in upstream NTLM connection teardown#4
Conversation
…dule.c Bug 1: Add c->fd guard before recv() in ngx_http_upstream_ntlm_close_handler to prevent use-after-free on a closed/recycled file descriptor. Bug 2: Reorder pool teardown in ngx_http_upstream_ntlm_close — set c->pool=NULL before ngx_close_connection(), then destroy the pool afterwards, preventing potential double-free regardless of nginx version. Agent-Logs-Url: https://github.com/Securepoint/nginx-ntlm-modulev2/sessions/478abd91-5849-4fce-90c8-c23a0284c998 Co-authored-by: dsabotta <262123149+dsabotta@users.noreply.github.com>
Copilot
AI
changed the title
[WIP] Fix use-after-free in ngx_http_upstream_ntlm_close_handler
Fix use-after-free and double-free in upstream NTLM connection teardown
May 8, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two high-severity memory safety bugs in the idle-connection close path that can lead to
recv()on a recycled file descriptor and potential double-free of the connection pool.Bug 1: Use-after-free in
ngx_http_upstream_ntlm_close_handlerBetween the
item->in_cachecheck and therecv()syscall, a concurrent client disconnect could triggerngx_http_upstream_client_conn_cleanup, which callsngx_close_connection(c)— settingc->fd = -1— beforerecv()executes on the now-closed/recycled descriptor.Added an explicit
c->fdguard before the syscall:Bug 2: Double-free of connection pool in
ngx_http_upstream_ntlm_closeThe previous order destroyed the pool then called
ngx_close_connection(c), which may also accessc->pooldepending on nginx version — risking a double-free. Fix follows the safe pattern: null outc->poolfirst songx_close_connectionsees it as NULL, then destroy the pool after:This is safe across all nginx versions regardless of whether
ngx_close_connectioninternally touchesc->pool.Original prompt
Two high-severity memory safety bugs in
ngx_http_upstream_ntlm_module.cBug 1: Use-after-free in
ngx_http_upstream_ntlm_close_handlerIn
ngx_http_upstream_ntlm_close_handler(), the code checksitem->in_cacheand retrievesc = item->peer_connection, then later callsrecv(c->fd, buf, 1, MSG_PEEK). Between the initial check and therecv()call,ngx_http_upstream_client_conn_cleanupcould fire (e.g. client disconnects), which callsngx_http_upstream_ntlm_item_release(item)(settingitem->peer_connection = NULL) and thenngx_http_upstream_ntlm_close(c)(destroyingc->pooland callingngx_close_connection(c)). The close_handler then doesrecv(c->fd, ...)on a closed/recycled file descriptor.Fix: Add a guard checking
c->fd != (ngx_socket_t) -1before callingrecv(). Also re-verifyitem->in_cache && item->peer_connection == cimmediately before therecv()syscall to narrow the race window. The function currently looks like:It should be changed to add a
c->fdcheck beforerecv():Bug 2: Double pool destroy in
ngx_http_upstream_ntlm_closengx_http_upstream_ntlm_close()callsngx_destroy_pool(c->pool)and setsc->pool = NULL, then callsngx_close_connection(c). In nginx 1.28.x,ngx_close_connection()may also accessc->pool. The standard nginx pattern (as used inngx_http_upstream_keepalive_module) is to destroy the pool and then callngx_close_connection, but the order matters and the pool should only be explicitly destroyed ifngx_close_connectionin the target nginx version does NOT destroy it. For safety with nginx 1.28.3, follow the exact pattern used by nginx's own keepalive module: callngx_destroy_poolfirst, setc->pool = NULL, thenngx_close_connection. Actually in nginx 1.28.xngx_close_connectiondoes NOT destroy the pool (it was removed), so the current order is safe but the pool NULL-check should be strengthened. However,ngx_close_connectionin some builds checksc->pooland if non-NULL frees it — leading to double-free if the pool was already destroyed butc->poolnot yet set to NULL due to compiler reordering.Fix: Use the pattern that is safe regardless of nginx version — set
c->pool = NULLatomically by saving the pool pointer first:This ensures
ngx_close_connectionseesc->pool == NULL(so it won't try to destroy it), and we destroy the pool ourselves afterwards. This matches the safe pattern and avoids any double-free regardless of nginx version.Files to modify
ngx_http_upstream_ntlm_module.c— apply both fixes as described above.The following is the prior conversation context from the user's chat exploration (may be truncated):
User: This nginx mdule will be used with nginx 1.28.3
Analyze the code for security issues, specially for errors with session handling.
And Check for potential memory access errors and memory leaks.
Assistant: Here is a thorough security and memory-safety audit of the module. Overall the code is well-structured and demonstrates awareness of the key pitfalls (the documented invariants I1–I4 are solid). However, several issues remain:
🔴 High Severity
1. Use-After-Free in
ngx_http_upstream_ntlm_close_handler(line 728)Between the first
item->in_cachecheck (line 712) and therecv()call (line 728),ngx_http_upstream_client_conn_cleanupcould fire (e.g. if the client disconne...This pull request was created from Copilot chat.