Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed processing of response body chunks ... #105

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 25 additions & 30 deletions src/ngx_http_modsecurity_body_filter.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ ngx_http_modsecurity_body_filter_init(void)
ngx_int_t
ngx_http_modsecurity_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
int buffer_fully_loadead = 0;
ngx_chain_t *chain = in;
ngx_http_modsecurity_ctx_t *ctx = NULL;
#if defined(MODSECURITY_SANITY_CHECKS) && (MODSECURITY_SANITY_CHECKS)
Expand Down Expand Up @@ -135,47 +134,43 @@ ngx_http_modsecurity_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
}
#endif

int is_request_processed = 0;
for (; chain != NULL; chain = chain->next)
{
/* XXX: chain->buf->last_buf || chain->buf->last_in_chain */
if (chain->buf->last_buf) {
buffer_fully_loadead = 1;
u_char *data = chain->buf->pos;
int ret;

msc_append_response_body(ctx->modsec_transaction, data, chain->buf->last - data);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's use ngx_buf_size() here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ngx_buf_size is defined as

#define ngx_buf_size(b)                                                      \
    (ngx_buf_in_memory(b) ? (off_t) (b->last - b->pos):                      \
                            (b->file_last - b->file_pos))

If somehow we happend to receive a buf which is completely in a file (i.e., buf->in_file == true but ngx_buf_in_memory(buf) == false) then .pos = .last = 0 but .file_last - .file_post > 0, so we will try to dereference a non-zero length block at NULL pointer .pos. But with current .last - .pos we would erroneously assume that we have no data but won't segfault at least.

But from the other hand I did a quick testing with gdb, even when a response body is buffered to a temporary file, nginx supplies a buf which has both .in_file and .temporary set (ngx_buf_in_memory(buf) == true => .pos, .last are valid).
ngx_http_charset_filter_module also references .pos/.last in ngx_http_charset_recode_{to,from}_utf8 without worries . So I think it is guaranteed that response body filters get chain bufs with ngx_buf_in_memory(buf) == true ?

One more thing, I did a quick grep of Nginx sources and see that ngx_buf_size is not used that much, whereas .last - .pos is much more common... maybe we should stick to the latter?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@turchanov well ok - let's keep .last - .pos.

ret = ngx_http_modsecurity_process_intervention(ctx->modsec_transaction, r);
if (ret > 0) {
return ngx_http_filter_finalize_request(r,
&ngx_http_modsecurity_module, ret);
}
}

if (buffer_fully_loadead == 1)
{
int ret;
ngx_pool_t *old_pool;
/* XXX: chain->buf->last_buf || chain->buf->last_in_chain */
is_request_processed = chain->buf->last_buf;

for (chain = in; chain != NULL; chain = chain->next)
{
u_char *data = chain->buf->start;
if (is_request_processed) {
ngx_pool_t *old_pool;

old_pool = ngx_http_modsecurity_pcre_malloc_init(r->pool);
msc_process_response_body(ctx->modsec_transaction);
ngx_http_modsecurity_pcre_malloc_done(old_pool);

msc_append_response_body(ctx->modsec_transaction, data, chain->buf->end - data);
/* XXX: I don't get how body from modsec being transferred to nginx's buffer. If so - after adjusting of nginx's
XXX: body we can proceed to adjust body size (content-length). see xslt_body_filter() for example */
ret = ngx_http_modsecurity_process_intervention(ctx->modsec_transaction, r);
if (ret > 0) {
return ngx_http_filter_finalize_request(r,
&ngx_http_modsecurity_module, ret);
return ret;
}
}

old_pool = ngx_http_modsecurity_pcre_malloc_init(r->pool);
msc_process_response_body(ctx->modsec_transaction);
ngx_http_modsecurity_pcre_malloc_done(old_pool);
else if (ret < 0) {
return ngx_http_filter_finalize_request(r,
&ngx_http_modsecurity_module, NGX_HTTP_INTERNAL_SERVER_ERROR);

/* XXX: I don't get how body from modsec being transferred to nginx's buffer. If so - after adjusting of nginx's
XXX: body we can proceed to adjust body size (content-length). see xslt_body_filter() for example */
ret = ngx_http_modsecurity_process_intervention(ctx->modsec_transaction, r);
if (ret > 0) {
return ret;
}
else if (ret < 0) {
return ngx_http_filter_finalize_request(r,
&ngx_http_modsecurity_module, NGX_HTTP_INTERNAL_SERVER_ERROR);
}
}
}
else
if (!is_request_processed)
{
dd("buffer was not fully loaded! ctx: %p", ctx);
}
Expand Down
4 changes: 2 additions & 2 deletions src/ngx_http_modsecurity_pre_access.c
Original file line number Diff line number Diff line change
Expand Up @@ -163,10 +163,10 @@ ngx_http_modsecurity_pre_access_handler(ngx_http_request_t *r)

while (chain && !already_inspected)
{
u_char *data = chain->buf->start;
u_char *data = chain->buf->pos;

msc_append_request_body(ctx->modsec_transaction, data,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto (it seems like the commit from #104 though, I left the same comment there).

chain->buf->last - chain->buf->pos);
chain->buf->last - data);

if (chain->buf->last_buf) {
break;
Expand Down