Skip to content

Commit 9ab38e8

Browse files
thibaultchaagentzh
authored andcommitted
bugfix: prevented request smuggling in the ngx.location.capture API.
Signed-off-by: Yichun Zhang (agentzh) <yichun@openresty.com>
1 parent 6913b1b commit 9ab38e8

File tree

2 files changed

+585
-131
lines changed

2 files changed

+585
-131
lines changed

src/ngx_http_lua_subrequest.c

Lines changed: 68 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,6 @@ static ngx_str_t ngx_http_lua_content_length_header_key =
5757
ngx_string("Content-Length");
5858

5959

60-
static ngx_int_t ngx_http_lua_set_content_length_header(ngx_http_request_t *r,
61-
off_t len);
6260
static ngx_int_t ngx_http_lua_adjust_subrequest(ngx_http_request_t *sr,
6361
ngx_uint_t method, int forward_body,
6462
ngx_http_request_body_t *body, unsigned vars_action,
@@ -79,7 +77,7 @@ static void ngx_http_lua_cancel_subreq(ngx_http_request_t *r);
7977
static ngx_int_t ngx_http_post_request_to_head(ngx_http_request_t *r);
8078
static ngx_int_t ngx_http_lua_copy_in_file_request_body(ngx_http_request_t *r);
8179
static ngx_int_t ngx_http_lua_copy_request_headers(ngx_http_request_t *sr,
82-
ngx_http_request_t *r);
80+
ngx_http_request_t *pr, int pr_not_chunked);
8381

8482

8583
enum {
@@ -634,8 +632,8 @@ ngx_http_lua_adjust_subrequest(ngx_http_request_t *sr, ngx_uint_t method,
634632
unsigned vars_action, ngx_array_t *extra_vars)
635633
{
636634
ngx_http_request_t *r;
637-
ngx_int_t rc;
638635
ngx_http_core_main_conf_t *cmcf;
636+
int pr_not_chunked = 0;
639637
size_t size;
640638

641639
r = sr->parent;
@@ -645,46 +643,32 @@ ngx_http_lua_adjust_subrequest(ngx_http_request_t *sr, ngx_uint_t method,
645643
if (body) {
646644
sr->request_body = body;
647645

648-
rc = ngx_http_lua_set_content_length_header(sr,
649-
body->buf
650-
? ngx_buf_size(body->buf)
651-
: 0);
652-
653-
if (rc != NGX_OK) {
654-
return NGX_ERROR;
655-
}
656-
657646
} else if (!always_forward_body
658647
&& method != NGX_HTTP_PUT
659648
&& method != NGX_HTTP_POST
660649
&& r->headers_in.content_length_n > 0)
661650
{
662-
rc = ngx_http_lua_set_content_length_header(sr, 0);
663-
if (rc != NGX_OK) {
664-
return NGX_ERROR;
665-
}
666-
667-
#if 1
668651
sr->request_body = NULL;
669-
#endif
670652

671653
} else {
672-
if (ngx_http_lua_copy_request_headers(sr, r) != NGX_OK) {
673-
return NGX_ERROR;
654+
if (!r->headers_in.chunked) {
655+
pr_not_chunked = 1;
674656
}
675657

676-
if (sr->request_body) {
658+
if (sr->request_body && sr->request_body->temp_file) {
677659

678660
/* deep-copy the request body */
679661

680-
if (sr->request_body->temp_file) {
681-
if (ngx_http_lua_copy_in_file_request_body(sr) != NGX_OK) {
682-
return NGX_ERROR;
683-
}
662+
if (ngx_http_lua_copy_in_file_request_body(sr) != NGX_OK) {
663+
return NGX_ERROR;
684664
}
685665
}
686666
}
687667

668+
if (ngx_http_lua_copy_request_headers(sr, r, pr_not_chunked) != NGX_OK) {
669+
return NGX_ERROR;
670+
}
671+
688672
sr->method = method;
689673

690674
switch (method) {
@@ -1134,100 +1118,6 @@ ngx_http_lua_post_subrequest(ngx_http_request_t *r, void *data, ngx_int_t rc)
11341118
}
11351119

11361120

1137-
static ngx_int_t
1138-
ngx_http_lua_set_content_length_header(ngx_http_request_t *r, off_t len)
1139-
{
1140-
ngx_table_elt_t *h, *header;
1141-
u_char *p;
1142-
ngx_list_part_t *part;
1143-
ngx_http_request_t *pr;
1144-
ngx_uint_t i;
1145-
1146-
r->headers_in.content_length_n = len;
1147-
1148-
if (ngx_list_init(&r->headers_in.headers, r->pool, 20,
1149-
sizeof(ngx_table_elt_t)) != NGX_OK)
1150-
{
1151-
return NGX_ERROR;
1152-
}
1153-
1154-
h = ngx_list_push(&r->headers_in.headers);
1155-
if (h == NULL) {
1156-
return NGX_ERROR;
1157-
}
1158-
1159-
h->key = ngx_http_lua_content_length_header_key;
1160-
h->lowcase_key = ngx_pnalloc(r->pool, h->key.len);
1161-
if (h->lowcase_key == NULL) {
1162-
return NGX_ERROR;
1163-
}
1164-
1165-
ngx_strlow(h->lowcase_key, h->key.data, h->key.len);
1166-
1167-
r->headers_in.content_length = h;
1168-
1169-
p = ngx_palloc(r->pool, NGX_OFF_T_LEN);
1170-
if (p == NULL) {
1171-
return NGX_ERROR;
1172-
}
1173-
1174-
h->value.data = p;
1175-
1176-
h->value.len = ngx_sprintf(h->value.data, "%O", len) - h->value.data;
1177-
1178-
h->hash = ngx_http_lua_content_length_hash;
1179-
1180-
#if 0
1181-
dd("content length hash: %lu == %lu", (unsigned long) h->hash,
1182-
ngx_hash_key_lc((u_char *) "Content-Length",
1183-
sizeof("Content-Length") - 1));
1184-
#endif
1185-
1186-
dd("r content length: %.*s",
1187-
(int) r->headers_in.content_length->value.len,
1188-
r->headers_in.content_length->value.data);
1189-
1190-
pr = r->parent;
1191-
1192-
if (pr == NULL) {
1193-
return NGX_OK;
1194-
}
1195-
1196-
/* forward the parent request's all other request headers */
1197-
1198-
part = &pr->headers_in.headers.part;
1199-
header = part->elts;
1200-
1201-
for (i = 0; /* void */; i++) {
1202-
1203-
if (i >= part->nelts) {
1204-
if (part->next == NULL) {
1205-
break;
1206-
}
1207-
1208-
part = part->next;
1209-
header = part->elts;
1210-
i = 0;
1211-
}
1212-
1213-
if (header[i].key.len == sizeof("Content-Length") - 1
1214-
&& ngx_strncasecmp(header[i].key.data, (u_char *) "Content-Length",
1215-
sizeof("Content-Length") - 1) == 0)
1216-
{
1217-
continue;
1218-
}
1219-
1220-
if (ngx_http_lua_set_input_header(r, header[i].key,
1221-
header[i].value, 0) == NGX_ERROR)
1222-
{
1223-
return NGX_ERROR;
1224-
}
1225-
}
1226-
1227-
return NGX_OK;
1228-
}
1229-
1230-
12311121
static void
12321122
ngx_http_lua_handle_subreq_responses(ngx_http_request_t *r,
12331123
ngx_http_lua_ctx_t *ctx)
@@ -1742,22 +1632,64 @@ ngx_http_lua_copy_in_file_request_body(ngx_http_request_t *r)
17421632

17431633

17441634
static ngx_int_t
1745-
ngx_http_lua_copy_request_headers(ngx_http_request_t *sr, ngx_http_request_t *r)
1635+
ngx_http_lua_copy_request_headers(ngx_http_request_t *sr,
1636+
ngx_http_request_t *pr, int pr_not_chunked)
17461637
{
1747-
ngx_table_elt_t *header;
1638+
ngx_table_elt_t *clh, *header;
17481639
ngx_list_part_t *part;
17491640
ngx_uint_t i;
1641+
u_char *p;
1642+
off_t len;
1643+
1644+
dd("before: parent req headers count: %d",
1645+
(int) pr->headers_in.headers.part.nelts);
17501646

17511647
if (ngx_list_init(&sr->headers_in.headers, sr->pool, 20,
17521648
sizeof(ngx_table_elt_t)) != NGX_OK)
17531649
{
17541650
return NGX_ERROR;
17551651
}
17561652

1757-
dd("before: parent req headers count: %d",
1758-
(int) r->headers_in.headers.part.nelts);
1653+
if (sr->request_body && !pr_not_chunked) {
1654+
1655+
/* craft our own Content-Length */
1656+
1657+
len = sr->request_body->buf ? ngx_buf_size(sr->request_body->buf) : 0;
1658+
1659+
clh = ngx_list_push(&sr->headers_in.headers);
1660+
if (clh == NULL) {
1661+
return NGX_ERROR;
1662+
}
17591663

1760-
part = &r->headers_in.headers.part;
1664+
clh->hash = ngx_http_lua_content_length_hash;
1665+
clh->key = ngx_http_lua_content_length_header_key;
1666+
clh->lowcase_key = ngx_pnalloc(sr->pool, clh->key.len);
1667+
if (clh->lowcase_key == NULL) {
1668+
return NGX_ERROR;
1669+
}
1670+
1671+
ngx_strlow(clh->lowcase_key, clh->key.data, clh->key.len);
1672+
1673+
p = ngx_palloc(sr->pool, NGX_OFF_T_LEN);
1674+
if (p == NULL) {
1675+
return NGX_ERROR;
1676+
}
1677+
1678+
clh->value.data = p;
1679+
clh->value.len = ngx_sprintf(clh->value.data, "%O", len)
1680+
- clh->value.data;
1681+
1682+
sr->headers_in.content_length = clh;
1683+
sr->headers_in.content_length_n = len;
1684+
1685+
dd("sr crafted content-length: %.*s",
1686+
(int) sr->headers_in.content_length->value.len,
1687+
sr->headers_in.content_length->value.data);
1688+
}
1689+
1690+
/* copy the parent request's headers */
1691+
1692+
part = &pr->headers_in.headers.part;
17611693
header = part->elts;
17621694

17631695
for (i = 0; /* void */; i++) {
@@ -1772,7 +1704,14 @@ ngx_http_lua_copy_request_headers(ngx_http_request_t *sr, ngx_http_request_t *r)
17721704
i = 0;
17731705
}
17741706

1775-
dd("setting request header %.*s: %.*s", (int) header[i].key.len,
1707+
if (!pr_not_chunked && header[i].key.len == sizeof("Content-Length") - 1
1708+
&& ngx_strncasecmp(header[i].key.data, (u_char *) "Content-Length",
1709+
sizeof("Content-Length") - 1) == 0)
1710+
{
1711+
continue;
1712+
}
1713+
1714+
dd("sr copied req header %.*s: %.*s", (int) header[i].key.len,
17761715
header[i].key.data, (int) header[i].value.len,
17771716
header[i].value.data);
17781717

@@ -1784,9 +1723,10 @@ ngx_http_lua_copy_request_headers(ngx_http_request_t *sr, ngx_http_request_t *r)
17841723
}
17851724

17861725
dd("after: parent req headers count: %d",
1787-
(int) r->headers_in.headers.part.nelts);
1726+
(int) pr->headers_in.headers.part.nelts);
17881727

17891728
return NGX_OK;
17901729
}
17911730

1731+
17921732
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */

0 commit comments

Comments
 (0)