You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by yl...@apache.org on 2020/06/22 10:29:27 UTC

svn commit: r1879074 - in /httpd/httpd/trunk: include/ap_mmn.h include/httpd.h modules/dav/main/util.c modules/generators/mod_autoindex.c server/util.c

Author: ylavic
Date: Mon Jun 22 10:29:27 2020
New Revision: 1879074

URL: http://svn.apache.org/viewvc?rev=1879074&view=rev
Log:
Add ap_normalize_path() to replace ap_getparents() (with options).

include/httpd.h: Declare ap_normalize_path() and flags.
    AP_NORMALIZE_ALLOW_RELATIVE:
        Don't require that the path be absolute as per RFC 7230.
        This is needed for lookup subrequests.
    AP_NORMALIZE_NOT_ABOVE_ROOT:
        Check that directory traversal ("..") don't go above root, or
        initial directory with relative paths.
    AP_NORMALIZE_DECODE_UNRESERVED:
        Decode unreserved characters (like '.') first since they have
        the same semantics encoded and decoded.
    AP_NORMALIZE_MERGE_SLASHES:
        Merge multiple slahes into a single one.
    AP_NORMALIZE_DROP_PARAMETERS:
        Ignore path parameters (";foo=bar"). Not used by httpd but since
        ap_normalize_path() is taken from mod_jk's jk_servlet_normalize()
        it can allow them to use the upstream version now.

server/util.c: Implement ap_normalize_path().

modules/dav/main/util.c: Replace call to ap_getparents() using
    ap_normalize_path() with AP_NORMALIZE_DECODE_UNRESERVED flag since
    the path comes from an obsolute URL (thus potentially %-encoded).
    
modules/generators/mod_autoindex.c: Replace call to ap_getparents() using
    ap_normalize_path() with AP_NORMALIZE_ALLOW_RELATIVE and
    AP_NORMALIZE_NOT_ABOVE_ROOT flags to be consistent with original code.

include/ap_mmn.h: MINOR bump for ap_normalize_path().


Modified:
    httpd/httpd/trunk/include/ap_mmn.h
    httpd/httpd/trunk/include/httpd.h
    httpd/httpd/trunk/modules/dav/main/util.c
    httpd/httpd/trunk/modules/generators/mod_autoindex.c
    httpd/httpd/trunk/server/util.c

Modified: httpd/httpd/trunk/include/ap_mmn.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/include/ap_mmn.h?rev=1879074&r1=1879073&r2=1879074&view=diff
==============================================================================
--- httpd/httpd/trunk/include/ap_mmn.h (original)
+++ httpd/httpd/trunk/include/ap_mmn.h Mon Jun 22 10:29:27 2020
@@ -632,6 +632,7 @@
  * 20200420.1 (2.5.1-dev)  Add ap_filter_adopt_brigade()
  * 20200420.2 (2.5.1-dev)  Add ap_proxy_worker_can_upgrade()
  * 20200420.3 (2.5.1-dev)  Add ap_parse_strict_length()
+ * 20200420.4 (2.5.1-dev)  Add ap_normalize_path()
  */
 
 #define MODULE_MAGIC_COOKIE 0x41503235UL /* "AP25" */
@@ -639,7 +640,7 @@
 #ifndef MODULE_MAGIC_NUMBER_MAJOR
 #define MODULE_MAGIC_NUMBER_MAJOR 20200420
 #endif
-#define MODULE_MAGIC_NUMBER_MINOR 3            /* 0...n */
+#define MODULE_MAGIC_NUMBER_MINOR 4            /* 0...n */
 
 /**
  * Determine if the server's current MODULE_MAGIC_NUMBER is at least a

Modified: httpd/httpd/trunk/include/httpd.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/include/httpd.h?rev=1879074&r1=1879073&r2=1879074&view=diff
==============================================================================
--- httpd/httpd/trunk/include/httpd.h (original)
+++ httpd/httpd/trunk/include/httpd.h Mon Jun 22 10:29:27 2020
@@ -1779,6 +1779,21 @@ AP_DECLARE(void) ap_no2slash(char *name)
 AP_DECLARE(void) ap_no2slash_ex(char *name, int is_fs_path)
                  AP_FN_ATTR_NONNULL_ALL;
 
+#define AP_NORMALIZE_ALLOW_RELATIVE     (1u <<  0)
+#define AP_NORMALIZE_NOT_ABOVE_ROOT     (1u <<  1)
+#define AP_NORMALIZE_DECODE_UNRESERVED  (1u <<  2)
+#define AP_NORMALIZE_MERGE_SLASHES      (1u <<  3)
+#define AP_NORMALIZE_DROP_PARAMETERS    (1u <<  4)
+
+/**
+ * Remove all ////, /./ and /xx/../ substrings from a path, and more
+ * depending on passed in flags.
+ * @param path The path to normalize
+ * @param flags bitmask of AP_NORMALIZE_* flags
+ * @return non-zero on success
+ */
+AP_DECLARE(int) ap_normalize_path(char *path, unsigned int flags)
+                AP_FN_ATTR_NONNULL((1));
 
 /**
  * Remove all ./ and xx/../ substrings from a file name. Also remove

Modified: httpd/httpd/trunk/modules/dav/main/util.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/dav/main/util.c?rev=1879074&r1=1879073&r2=1879074&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/dav/main/util.c (original)
+++ httpd/httpd/trunk/modules/dav/main/util.c Mon Jun 22 10:29:27 2020
@@ -664,7 +664,12 @@ static dav_error * dav_process_if_header
             /* note that parsed_uri.path is allocated; we can trash it */
 
             /* clean up the URI a bit */
-            ap_getparents(parsed_uri.path);
+            if (!ap_normalize_path(parsed_uri.path,
+                                   AP_NORMALIZE_DECODE_UNRESERVED)) {
+                return dav_new_error(r->pool, HTTP_BAD_REQUEST,
+                                     DAV_ERR_IF_TAGGED, rv,
+                                     "Invalid URI path tagged If-header.");
+            }
 
             /* the resources we will compare to have unencoded paths */
             if (ap_unescape_url(parsed_uri.path) != OK) {

Modified: httpd/httpd/trunk/modules/generators/mod_autoindex.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/generators/mod_autoindex.c?rev=1879074&r1=1879073&r2=1879074&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/generators/mod_autoindex.c (original)
+++ httpd/httpd/trunk/modules/generators/mod_autoindex.c Mon Jun 22 10:29:27 2020
@@ -1266,8 +1266,9 @@ static struct ent *make_parent_entry(apr
     if (!(p->name = ap_make_full_path(r->pool, r->uri, "../"))) {
         return (NULL);
     }
-    ap_getparents(p->name);
-    if (!*p->name) {
+    if (!ap_normalize_path(p->name, AP_NORMALIZE_ALLOW_RELATIVE |
+                                    AP_NORMALIZE_NOT_ABOVE_ROOT)
+            || p->name[0] == '\0') {
         return (NULL);
     }
 

Modified: httpd/httpd/trunk/server/util.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/server/util.c?rev=1879074&r1=1879073&r2=1879074&view=diff
==============================================================================
--- httpd/httpd/trunk/server/util.c (original)
+++ httpd/httpd/trunk/server/util.c Mon Jun 22 10:29:27 2020
@@ -77,7 +77,7 @@
 #include "test_char.h"
 
 /* Win32/NetWare/OS2 need to check for both forward and back slashes
- * in ap_getparents() and ap_escape_url.
+ * in ap_normalize_path() and ap_escape_url().
  */
 #ifdef CASE_BLIND_FILESYSTEM
 #define IS_SLASH(s) ((s == '/') || (s == '\\'))
@@ -492,6 +492,116 @@ AP_DECLARE(apr_status_t) ap_pregsub_ex(a
     return rc;
 }
 
+/* Forward declare */
+static char x2c(const char *what);
+
+#define IS_SLASH_OR_NUL(s) (s == '\0' || IS_SLASH(s))
+
+/*
+ * Inspired by mod_jk's jk_servlet_normalize().
+ */
+AP_DECLARE(int) ap_normalize_path(char *path, unsigned int flags)
+{
+    int ret = 1;
+    apr_size_t l = 1, w = 1;
+
+    if (!IS_SLASH(path[0])) {
+        /* Besides "OPTIONS *", a request-target should start with '/'
+         * per RFC 7230 section 5.3, so anything else is invalid.
+         */
+        if (path[0] == '*' && path[1] == '\0') {
+            return 1;
+        }
+        /* However, AP_NORMALIZE_ALLOW_RELATIVE can be used to bypass
+         * this restriction (e.g. for subrequest file lookups).
+         */
+        if (!(flags & AP_NORMALIZE_ALLOW_RELATIVE) || path[0] == '\0') {
+            return 0;
+        }
+
+        l = w = 0;
+    }
+
+    while (path[l] != '\0') {
+        /* RFC-3986 section 2.3:
+         *  For consistency, percent-encoded octets in the ranges of
+         *  ALPHA (%41-%5A and %61-%7A), DIGIT (%30-%39), hyphen (%2D),
+         *  period (%2E), underscore (%5F), or tilde (%7E) should [...]
+         *  be decoded to their corresponding unreserved characters by
+         *  URI normalizers.
+         */
+        if ((flags & AP_NORMALIZE_DECODE_UNRESERVED)
+                && path[l] == '%' && apr_isxdigit(path[l + 1])
+                                  && apr_isxdigit(path[l + 2])) {
+            const char c = x2c(&path[l + 1]);
+            if (apr_isalnum(c) || (c && strchr("-._~", c))) {
+                /* Replace last char and fall through as the current
+                 * read position */
+                l += 2;
+                path[l] = c;
+            }
+        }
+
+        if ((flags & AP_NORMALIZE_DROP_PARAMETERS) && path[l] == ';') {
+            do {
+                l++;
+            } while (!IS_SLASH_OR_NUL(path[l]));
+            continue;
+        }
+
+        if (w == 0 || IS_SLASH(path[w - 1])) {
+            /* Collapse ///// sequences to / */
+            if ((flags & AP_NORMALIZE_MERGE_SLASHES) && IS_SLASH(path[l])) {
+                do {
+                    l++;
+                } while (IS_SLASH(path[l]));
+                continue;
+            }
+
+            if (path[l] == '.') {
+                /* Remove /./ segments */
+                if (IS_SLASH_OR_NUL(path[l + 1])) {
+                    l++;
+                    if (path[l]) {
+                        l++;
+                    }
+                    continue;
+                }
+
+                /* Remove /xx/../ segments */
+                if (path[l + 1] == '.' && IS_SLASH_OR_NUL(path[l + 2])) {
+                    /* Wind w back to remove the previous segment */
+                    if (w > 1) {
+                        do {
+                            w--;
+                        } while (w && !IS_SLASH(path[w - 1]));
+                    }
+                    else {
+                        /* Already at root, ignore and return a failure
+                         * if asked to.
+                         */
+                        if (flags & AP_NORMALIZE_NOT_ABOVE_ROOT) {
+                            ret = 0;
+                        }
+                    }
+
+                    /* Move l forward to the next segment */
+                    l += 2;
+                    if (path[l]) {
+                        l++;
+                    }
+                    continue;
+                }
+            }
+        }
+
+        path[w++] = path[l++];
+    }
+    path[w] = '\0';
+
+    return ret;
+}
+
 /*
  * Parse .. so we don't compromise security
  */