Skip to content

Commit b5d23b9

Browse files
committed
bugfix: ngx.req.raw_header() could lead to buffer overflow and the "userdata length overflow" error due to misuse of r->header_end while modules like ngx_fastcgi and ngx_proxy can change r->header_end to point to buffers of their own. thanks sadmedved for the report.
1 parent e4e0f4b commit b5d23b9

File tree

2 files changed

+60
-7
lines changed

2 files changed

+60
-7
lines changed

src/ngx_http_lua_headers.c

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -93,11 +93,13 @@ ngx_http_lua_ngx_req_raw_header(lua_State *L)
9393
hc = mr->http_connection;
9494
c = mr->connection;
9595

96-
#if 0
96+
#if 1
9797
dd("hc->nbusy: %d", (int) hc->nbusy);
9898

99-
dd("hc->busy: %p %p %p %p", hc->busy[0]->start, hc->busy[0]->pos,
100-
hc->busy[0]->last, hc->busy[0]->end);
99+
if (hc->nbusy) {
100+
dd("hc->busy: %p %p %p %p", hc->busy[0]->start, hc->busy[0]->pos,
101+
hc->busy[0]->last, hc->busy[0]->end);
102+
}
101103

102104
dd("request line: %p %p", mr->request_line.data,
103105
mr->request_line.data + mr->request_line.len);
@@ -120,7 +122,7 @@ ngx_http_lua_ngx_req_raw_header(lua_State *L)
120122
first = b;
121123

122124
if (mr->header_in == b) {
123-
size += mr->header_end + 2 - mr->request_line.data;
125+
size += mr->header_in->pos - mr->request_line.data;
124126

125127
} else {
126128
/* the subsequent part of the header is in the large header
@@ -138,6 +140,8 @@ ngx_http_lua_ngx_req_raw_header(lua_State *L)
138140
}
139141
}
140142

143+
dd("size: %d", (int) size);
144+
141145
if (hc->nbusy) {
142146
b = NULL;
143147
for (i = 0; i < hc->nbusy; i++) {
@@ -160,21 +164,26 @@ ngx_http_lua_ngx_req_raw_header(lua_State *L)
160164
}
161165

162166
if (b == mr->header_in) {
163-
size += mr->header_end + 2 - b->start;
167+
size += mr->header_in->pos - b->start;
164168
break;
165169
}
166170

167171
size += b->pos - b->start;
168172
}
169173
}
170174

175+
size++; /* plus the null terminator, as required by the later
176+
ngx_strstr() call */
177+
178+
dd("header size: %d", (int) size);
179+
171180
data = lua_newuserdata(L, size);
172181
last = data;
173182

174183
b = c->buffer;
175184
if (first == b) {
176185
if (mr->header_in == b) {
177-
pos = mr->header_end + 2;
186+
pos = mr->header_in->pos;
178187

179188
} else {
180189
pos = b->pos;
@@ -221,7 +230,7 @@ ngx_http_lua_ngx_req_raw_header(lua_State *L)
221230
p = last;
222231

223232
if (b == mr->header_in) {
224-
pos = mr->header_end + 2;
233+
pos = mr->header_in->pos;
225234

226235
} else {
227236
pos = b->pos;
@@ -277,10 +286,22 @@ ngx_http_lua_ngx_req_raw_header(lua_State *L)
277286
}
278287
}
279288

289+
*last++ = '\0';
290+
280291
if (last - data > (ssize_t) size) {
281292
return luaL_error(L, "buffer error: %d", (int) (last - data - size));
282293
}
283294

295+
/* strip the leading part (if any) of the request body in our header.
296+
* the first part of the request body could slip in because nginx core's
297+
* ngx_http_request_body_length_filter and etc can move r->header_in->pos
298+
* in case that some of the body data has been preread into r->header_in.
299+
*/
300+
p = (u_char *) ngx_strstr(data, CRLF CRLF);
301+
if (p) {
302+
last = p + sizeof(CRLF CRLF) - 1;
303+
}
304+
284305
lua_pushlstring(L, (char *) data, last - data);
285306
return 1;
286307
}

t/104-req-raw-header.t

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -595,3 +595,35 @@ Cookie: " . ("C" x 1200) . "\r\n\r\n"
595595
--- no_error_log
596596
[error]
597597
598+
599+
600+
=== TEST 22: ngx_proxy/ngx_fastcgi/etc change r->header_end to point to their own buffers
601+
--- config
602+
location = /t {
603+
proxy_buffering off;
604+
proxy_pass http://127.0.0.1:$server_port/bad;
605+
proxy_intercept_errors on;
606+
error_page 500 = /500;
607+
}
608+
609+
location = /bad {
610+
return 500;
611+
}
612+
613+
location = /500 {
614+
internal;
615+
content_by_lua '
616+
ngx.print(ngx.req.raw_header())
617+
';
618+
}
619+
--- request
620+
GET /t
621+
--- response_body eval
622+
"GET /t HTTP/1.1\r
623+
Host: localhost\r
624+
Connection: Close\r
625+
\r
626+
"
627+
--- no_error_log
628+
[error]
629+

0 commit comments

Comments
 (0)