From f7ff5e65d0d20ba0425be7e3d8de4d04ceec9206 Mon Sep 17 00:00:00 2001 From: Ruslan Ermilov Date: Mon, 23 Dec 2013 18:12:00 +0400 Subject: [PATCH] Teach ngx_http_parse_unsafe_uri() how to unescape URIs. This fixes handling of escaped URIs in X-Accel-Redirect (ticket #316), SSI (ticket #240), and DAV. --- src/http/modules/ngx_http_ssi_filter_module.c | 14 ----- src/http/ngx_http_parse.c | 63 ++++++++++++++++++- 2 files changed, 60 insertions(+), 17 deletions(-) diff --git a/src/http/modules/ngx_http_ssi_filter_module.c b/src/http/modules/ngx_http_ssi_filter_module.c index c70b17e09..a53cd1472 100644 --- a/src/http/modules/ngx_http_ssi_filter_module.c +++ b/src/http/modules/ngx_http_ssi_filter_module.c @@ -1982,8 +1982,6 @@ static ngx_int_t ngx_http_ssi_include(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, ngx_str_t **params) { - u_char *dst, *src; - size_t len; ngx_int_t rc, key; ngx_str_t *uri, *file, *wait, *set, *stub, args; ngx_buf_t *b; @@ -2054,18 +2052,6 @@ ngx_http_ssi_include(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, return rc; } - dst = uri->data; - src = uri->data; - - ngx_unescape_uri(&dst, &src, uri->len, NGX_UNESCAPE_URI); - - len = (uri->data + uri->len) - src; - if (len) { - dst = ngx_movemem(dst, src, len); - } - - uri->len = dst - uri->data; - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ssi include: \"%V\"", uri); diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c index a895a8958..8c1a62a7b 100644 --- a/src/http/ngx_http_parse.c +++ b/src/http/ngx_http_parse.c @@ -1780,11 +1780,13 @@ ngx_int_t ngx_http_parse_unsafe_uri(ngx_http_request_t *r, ngx_str_t *uri, ngx_str_t *args, ngx_uint_t *flags) { - u_char ch, *p; - size_t len; + u_char ch, *p, *src, *dst; + size_t len; + ngx_uint_t quoted; len = uri->len; p = uri->data; + quoted = 0; if (len == 0 || p[0] == '?') { goto unsafe; @@ -1800,6 +1802,11 @@ ngx_http_parse_unsafe_uri(ngx_http_request_t *r, ngx_str_t *uri, ch = *p++; + if (ch == '%') { + quoted = 1; + continue; + } + if (usual[ch >> 5] & (1 << (ch & 0x1f))) { continue; } @@ -1809,7 +1816,7 @@ ngx_http_parse_unsafe_uri(ngx_http_request_t *r, ngx_str_t *uri, args->data = p; uri->len -= len; - return NGX_OK; + break; } if (ch == '\0') { @@ -1828,6 +1835,56 @@ ngx_http_parse_unsafe_uri(ngx_http_request_t *r, ngx_str_t *uri, } } + if (quoted) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "escaped URI: \"%V\"", uri); + + src = uri->data; + + dst = ngx_pnalloc(r->pool, uri->len); + if (dst == NULL) { + return NGX_ERROR; + } + + uri->data = dst; + + ngx_unescape_uri(&dst, &src, uri->len, 0); + + uri->len = dst - uri->data; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "unescaped URI: \"%V\"", uri); + + len = uri->len; + p = uri->data; + + if (p[0] == '.' && len > 1 && p[1] == '.' + && (len == 2 || ngx_path_separator(p[2]))) + { + goto unsafe; + } + + for ( /* void */ ; len; len--) { + + ch = *p++; + + if (ch == '\0') { + goto unsafe; + } + + if (ngx_path_separator(ch) && len > 2) { + + /* detect "/../" and "/.." */ + + if (p[0] == '.' && p[1] == '.' + && (len == 3 || ngx_path_separator(p[2]))) + { + goto unsafe; + } + } + } + } + return NGX_OK; unsafe: