From: Stefan Eissing Date: Fri, 1 Oct 2021 11:21:11 +0000 (+0000) Subject: Merge of /httpd/httpd/trunk:r1893724 X-Git-Tag: candidate-2.4.50-rc1~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=98246aa96079dad5f7b20521bbc0142a04f1c5e7;p=thirdparty%2Fapache%2Fhttpd.git Merge of /httpd/httpd/trunk:r1893724 *) core: AP_NORMALIZE_DECODE_UNRESERVED should normalize the second dot in the uri-path when it's preceded by a dot. [Yann Ylavic] git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1893775 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/changes-entries/normalize_unreserved.txt b/changes-entries/normalize_unreserved.txt new file mode 100644 index 00000000000..4782967a656 --- /dev/null +++ b/changes-entries/normalize_unreserved.txt @@ -0,0 +1,2 @@ + *) core: AP_NORMALIZE_DECODE_UNRESERVED should normalize the second dot in + the uri-path when it's preceded by a dot. [Yann Ylavic] \ No newline at end of file diff --git a/server/util.c b/server/util.c index 2a7fdda8e97..896574b4c57 100644 --- a/server/util.c +++ b/server/util.c @@ -502,7 +502,8 @@ static char x2c(const char *what); AP_DECLARE(int) ap_normalize_path(char *path, unsigned int flags) { int ret = 1; - apr_size_t l = 1, w = 1; + apr_size_t l = 1, w = 1, n; + int decode_unreserved = (flags & AP_NORMALIZE_DECODE_UNRESERVED) != 0; if (!IS_SLASH(path[0])) { /* Besides "OPTIONS *", a request-target should start with '/' @@ -529,7 +530,7 @@ AP_DECLARE(int) ap_normalize_path(char *path, unsigned int flags) * be decoded to their corresponding unreserved characters by * URI normalizers. */ - if ((flags & AP_NORMALIZE_DECODE_UNRESERVED) + if (decode_unreserved && path[l] == '%' && apr_isxdigit(path[l + 1]) && apr_isxdigit(path[l + 2])) { const char c = x2c(&path[l + 1]); @@ -567,8 +568,17 @@ AP_DECLARE(int) ap_normalize_path(char *path, unsigned int flags) continue; } - /* Remove /xx/../ segments */ - if (path[l + 1] == '.' && IS_SLASH_OR_NUL(path[l + 2])) { + /* Remove /xx/../ segments (or /xx/.%2e/ when + * AP_NORMALIZE_DECODE_UNRESERVED is set since we + * decoded only the first dot above). + */ + n = l + 1; + if ((path[n] == '.' || (decode_unreserved + && path[n] == '%' + && path[++n] == '2' + && (path[++n] == 'e' + || path[n] == 'E'))) + && IS_SLASH_OR_NUL(path[n + 1])) { /* Wind w back to remove the previous segment */ if (w > 1) { do { @@ -585,7 +595,7 @@ AP_DECLARE(int) ap_normalize_path(char *path, unsigned int flags) } /* Move l forward to the next segment */ - l += 2; + l = n + 1; if (path[l]) { l++; }