Skip to content

gzip filter leaves ctx->preallocated stale after ngx_pfree() #25

@xintenseapple

Description

@xintenseapple

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions