bugfix: Fix handling of new list elements#2177
bugfix: Fix handling of new list elements#2177zhuizhuhaomeng merged 4 commits intoopenresty:masterfrom
Conversation
|
@oxpa |
|
Makes sense, will do |
|
@oxpa got the following error. the header type is ngx_table_elt_t for the nginx older than 1.23 which does not have the next member https://app.travis-ci.com/github/openresty/lua-nginx-module/jobs/599726670#L2356 |
|
Sorry, didn't check this. Will fix and check it works pre-1.23.0. |
|
I have pushed the commit but I'm yet to test it. |
|
The code doesn't create a new element but rather goes through existing in a list and possibly updates their values. This element was created elsewhere and should already have proper 'next' value. |
|
I still don't see a problem. The 'h->next' value is either NULL or a valid pointer to a next element. |
|
Forgive me pasting the source code. static ngx_int_t
ngx_http_variable_headers_internal(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data, u_char sep)
{
size_t len;
u_char *p;
ngx_table_elt_t *h, *th;
h = *(ngx_table_elt_t **) ((char *) r + data);
len = 0;
for (th = h; th; th = th->next) {
if (th->hash == 0) {
continue;
}
len += th->value.len + 2; /* variable data size 'len' caculating */
}
if (len == 0) {
v->not_found = 1;
return NGX_OK;
}
len -= 2; /* not including trailing sep and space */
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
if (h->next == NULL) {
v->len = h->value.len;
v->data = h->value.data;
return NGX_OK;
}
p = ngx_pnalloc(r->pool, len);
if (p == NULL) {
return NGX_ERROR;
}
v->len = len;
v->data = p;
for (th = h; th; th = th->next) {
if (th->hash == 0) {
continue;
}
p = ngx_copy(p, th->value.data, th->value.len);
if (th->next == NULL) {. /* th->next has valid value while th->hash is 0 */
break;
}
*p++ = sep; *p++ = ' '; /* here is the problem, since the variable data size is 'len', not including
extra sep and space, this will lead heap-buffer-overflow problem */
}
return NGX_OK;
} |
|
@ssdr while I'm not sure how to trigger this, the overall idea seems correct. Let me have a think. Though this seems a bit more complex than I can handle =) |
|
or even not 'continuous tail' but rather 'the last header value should be the last element in a list'. This seems proper wording. |
|
If there are any bug there, we should try to add a test case to cover it. |
|
Another solution: Since h->next is valid value and it's hash might be 0, maybe ...
for (th = h; th; th = th->next) {
if (th->hash == 0) {
continue;
}
p = ngx_copy(p, th->value.data, th->value.len);
if (th->next == NULL) {
break;
}
*p++ = sep; *p++ = ' '; // maybe here needs some conditions, since th->next->hash might be 0
}
... |
|
There have been a test case in 016-resp-header.t TEST 34, use openresty-asan binary will lead test case failed. Non-asan binary needs gdb to check it: |
|
I don't think editing nginx sources would be the right solution: there may be other places where this problem may arise |
|
fixed in nginx: https://hg.nginx.org/nginx/rev/b71e69247483 |



ngx_list_push return an uninitialized element. Each of them needs 'next' element set to either zero or valid pointer.
The problem become apparent after #2063 : it fixes variable handling but leaves problems with uninitialized 'next' elements.
I managed to improve at least two tests to make the problem reveal itself on linux.
Adding MALLOC_PERTURB_ forces glib to initialize allocated memory with a non-zero value. This allows code to fail quicker: you don't have to wait till nginx pool reuses a chunk.
As I'm not really familiar with the code, so I might have missed a place or two more with similar problem.
Also, I guess, it makes sense to add MALLOC_PERTURB_ to all tests.
I hereby granted the copyright of the changes in this pull request
to the authors of this lua-nginx-module project.