Finding: gzip filter leaves ctx->preallocated stale after ngx_pfree()
Summary
In freenginx, the gzip filter frees ctx->preallocated but does not clear the pointer. Later error cleanup checks only whether ctx->preallocated is non-NULL and can pass the stale pointer to ngx_pfree() again.
Affected Area
src/http/modules/ngx_http_gzip_filter_module.c
- Functions:
ngx_http_gzip_filter_deflate_end() and gzip body-filter error cleanup.
Source Evidence
The normal deflate-end path frees the preallocated zlib memory but leaves the context pointer unchanged:
rc = deflateEnd(&ctx->zstream);
if (rc != Z_OK) {
...
return NGX_ERROR;
}
ngx_pfree(r->pool, ctx->preallocated);
cl = ngx_alloc_chain_link(r->pool);
if (cl == NULL) {
return NGX_ERROR;
}
The error cleanup later treats any non-NULL ctx->preallocated as still freeable:
failed:
ctx->done = 1;
if (ctx->preallocated) {
deflateEnd(&ctx->zstream);
ngx_pfree(r->pool, ctx->preallocated);
}
An immediate second ngx_pfree() is often benign because the pool large-allocation slot has already been cleared, but the pointer remains stale. If another large request-pool allocation reuses the same address before this cleanup, the stale pointer can target the later allocation.
Expected Behavior
After freeing ctx->preallocated, the gzip context should no longer retain a non-NULL pointer to that allocation.
Impact
This is a stale-pointer cleanup bug. It is primarily a hardening issue unless a response path can force another large request-pool allocation at the same address before gzip reaches the error cleanup.
Reproduction Strategy
Force gzip deflate end, then trigger a downstream body-filter error after a later large request-pool allocation can reuse the freed address. Instrument ngx_pfree() or use allocator tracing to detect stale-pointer hits.
Suggested Fix
Set ctx->preallocated = NULL immediately after freeing it.
Finding: gzip filter leaves
ctx->preallocatedstale afterngx_pfree()Summary
In freenginx, the gzip filter frees
ctx->preallocatedbut does not clear the pointer. Later error cleanup checks only whetherctx->preallocatedis non-NULL and can pass the stale pointer tongx_pfree()again.Affected Area
src/http/modules/ngx_http_gzip_filter_module.cngx_http_gzip_filter_deflate_end()and gzip body-filter error cleanup.Source Evidence
The normal deflate-end path frees the preallocated zlib memory but leaves the context pointer unchanged:
The error cleanup later treats any non-NULL
ctx->preallocatedas still freeable:An immediate second
ngx_pfree()is often benign because the pool large-allocation slot has already been cleared, but the pointer remains stale. If another large request-pool allocation reuses the same address before this cleanup, the stale pointer can target the later allocation.Expected Behavior
After freeing
ctx->preallocated, the gzip context should no longer retain a non-NULL pointer to that allocation.Impact
This is a stale-pointer cleanup bug. It is primarily a hardening issue unless a response path can force another large request-pool allocation at the same address before gzip reaches the error cleanup.
Reproduction Strategy
Force gzip deflate end, then trigger a downstream body-filter error after a later large request-pool allocation can reuse the freed address. Instrument
ngx_pfree()or use allocator tracing to detect stale-pointer hits.Suggested Fix
Set
ctx->preallocated = NULLimmediately after freeing it.