Skip to content

Commit 1f65751

Browse files
committed
bugfix: removing a request header might lead to memory corruptions. thanks Bjørnar Ness for the report.
1 parent 82ba941 commit 1f65751

File tree

3 files changed

+119
-17
lines changed

3 files changed

+119
-17
lines changed

src/ngx_http_lua_common.h

+2
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
#define MD5_DIGEST_LENGTH 16
3131
#endif
3232

33+
#define ngx_http_lua_assert(a) assert(a)
34+
3335
/* Nginx HTTP Lua Inline tag prefix */
3436

3537
#define NGX_HTTP_LUA_INLINE_TAG "nhli_"

src/ngx_http_lua_headers_in.c

+59-16
Original file line numberDiff line numberDiff line change
@@ -171,13 +171,22 @@ ngx_http_set_header_helper(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv,
171171
rc = ngx_http_lua_rm_header_helper(&r->headers_in.headers,
172172
part, i);
173173

174+
ngx_http_lua_assert(!(r->headers_in.headers.part.next == NULL
175+
&& r->headers_in.headers.last
176+
!= &r->headers_in.headers.part));
177+
178+
dd("rm header: rc=%d", (int) rc);
179+
174180
if (rc == NGX_OK) {
181+
175182
if (output_header) {
176183
*output_header = NULL;
177184
}
178185

179186
goto retry;
180187
}
188+
189+
return NGX_ERROR;
181190
}
182191

183192
h[i].value = *value;
@@ -651,42 +660,76 @@ ngx_http_lua_rm_header_helper(ngx_list_t *l, ngx_list_part_t *cur,
651660
(int) data[i].value.len, data[i].value.data);
652661

653662
if (i == 0) {
663+
dd("first entry in the part");
654664
cur->elts = (char *) cur->elts + l->size;
655665
cur->nelts--;
656666

657667
if (cur == l->last) {
668+
dd("being the last part");
658669
if (cur->nelts == 0) {
659670
#if 1
660671
part = &l->part;
661-
while (part->next != cur) {
662-
if (part->next == NULL) {
663-
return NGX_ERROR;
672+
dd("cur=%p, part=%p, part next=%p, last=%p",
673+
cur, part, part->next, l->last);
674+
675+
if (part == cur) {
676+
cur->elts = (char *) cur->elts - l->size;
677+
/* do nothing */
678+
679+
} else {
680+
while (part->next != cur) {
681+
if (part->next == NULL) {
682+
return NGX_ERROR;
683+
}
684+
part = part->next;
664685
}
665-
part = part->next;
666-
}
667686

668-
l->last = part;
669-
part->next = NULL;
670-
l->nalloc = part->nelts;
687+
l->last = part;
688+
part->next = NULL;
689+
dd("part nelts: %d", (int) part->nelts);
690+
l->nalloc = part->nelts;
691+
}
671692
#endif
672693

673694
} else {
674-
l->nalloc = cur->nelts;
695+
l->nalloc--;
696+
dd("nalloc decreased: %d", (int) l->nalloc);
675697
}
676698

677699
return NGX_OK;
678700
}
679701

680702
if (cur->nelts == 0) {
703+
dd("current part is empty");
681704
part = &l->part;
682-
while (part->next != cur) {
683-
if (part->next == NULL) {
684-
return NGX_ERROR;
705+
if (part == cur) {
706+
ngx_http_lua_assert(cur->next != NULL);
707+
708+
dd("remove 'cur' from the list by rewriting 'cur': "
709+
"l->last: %p, cur: %p, cur->next: %p, part: %p",
710+
l->last, cur, cur->next, part);
711+
712+
if (l->last == cur->next) {
713+
dd("last is cur->next");
714+
l->part = *(cur->next);
715+
l->last = part;
716+
l->nalloc = part->nelts;
717+
718+
} else {
719+
l->part = *(cur->next);
685720
}
686-
part = part->next;
687-
}
688721

689-
part->next = cur->next;
722+
} else {
723+
dd("remove 'cur' from the list");
724+
while (part->next != cur) {
725+
if (part->next == NULL) {
726+
return NGX_ERROR;
727+
}
728+
part = part->next;
729+
}
730+
731+
part->next = cur->next;
732+
}
690733

691734
return NGX_OK;
692735
}
@@ -700,7 +743,7 @@ ngx_http_lua_rm_header_helper(ngx_list_t *l, ngx_list_part_t *cur,
700743
cur->nelts--;
701744

702745
if (cur == l->last) {
703-
l->nalloc = cur->nelts;
746+
l->nalloc--;
704747
}
705748

706749
return NGX_OK;

t/028-req-header.t

+58-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use t::TestNginxLua;
99

1010
repeat_each(2);
1111

12-
plan tests => repeat_each() * (2 * blocks() + 19);
12+
plan tests => repeat_each() * (2 * blocks() + 20);
1313

1414
#no_diff();
1515
#no_long_string();
@@ -1346,3 +1346,60 @@ GET /bar
13461346
host var: agentzh.org
13471347
http_host var: agentZH.org:1984
13481348
1349+
1350+
1351+
=== TEST 44: clear all and re-insert
1352+
--- config
1353+
location = /t {
1354+
content_by_lua '
1355+
local headers = ngx.req.get_headers(100, true)
1356+
local n = 0
1357+
for header, _ in pairs(headers) do
1358+
n = n + 1
1359+
ngx.req.clear_header(header)
1360+
end
1361+
ngx.say("got ", n, " headers")
1362+
local i = 0
1363+
for header, value in pairs(headers) do
1364+
i = i + 1
1365+
print("1: reinsert header ", header, ": ", i)
1366+
ngx.req.set_header(header, value)
1367+
end
1368+
local headers = ngx.req.get_headers(100, true)
1369+
n = 0
1370+
for header, _ in pairs(headers) do
1371+
n = n + 1
1372+
ngx.req.clear_header(header)
1373+
end
1374+
ngx.say("got ", n, " headers")
1375+
-- do return end
1376+
local i = 0
1377+
for header, value in pairs(headers) do
1378+
i = i + 1
1379+
if i > 8 then
1380+
break
1381+
end
1382+
print("2: reinsert header ", header, ": ", i)
1383+
ngx.req.set_header(header, value)
1384+
end
1385+
';
1386+
}
1387+
1388+
--- raw_request eval
1389+
"GET /t HTTP/1.1\r
1390+
Host: localhost\r
1391+
Connection: close\r
1392+
Cache-Control: max-age=0\r
1393+
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8\r
1394+
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36\r
1395+
Accept-Encoding: gzip,deflate,sdch\r
1396+
Accept-Language: en-US,en;q=0.8\r
1397+
Cookie: test=cookie;\r
1398+
\r
1399+
"
1400+
--- response_body
1401+
got 8 headers
1402+
got 8 headers
1403+
--- no_error_log
1404+
[error]
1405+

0 commit comments

Comments
 (0)