details:   http://freenginx.org/hg/nginx/rev/aae28b083279
branches:  
changeset: 9493:aae28b083279
user:      Maxim Dounin <[email protected]>
date:      Tue Mar 31 06:54:50 2026 +0300
description:
Dav: destination validation for COPY and MOVE with "alias".

If COPY or MOVE methods are enabled, the DAV module assumes that it is
configured for the whole server, and does not try validate that the
destination URI is within the particular location.  This, however, does
not work well if it is in fact configured in a non-root location,
and this location uses the "alias" directive, such as in the following
configuration:

    location /prefix/ {
        dav_methods COPY;
        alias /foo/;
    }

In particular, if the destination URI is shorter than the aliased location
prefix, calling ngx_http_map_uri_to_path() with such destination URI used
to result in segmentation faults (CVE-2026-27654).  And if the destination
URI is longer than the aliased location prefix, but does not match it,
calling ngx_http_map_uri_to_path() resulted in unexpected path values,
including ones above the "alias" directory specified.

The fix is to check destination URI prefix if "alias" is used, similarly
to what we do with "try_files".  Additionally, the ngx_http_map_uri_to_path()
function was updated with additional sanity checking to prevent similar
issues.

See also:
https://github.com/nginx/nginx/commit/9739e755b8dddba82e65ca2a08d079f4c9826b75

diffstat:

 src/http/modules/ngx_http_dav_module.c |  43 +++++++++++++++++++++++----------
 src/http/ngx_http_core_module.c        |   6 ++++
 2 files changed, 36 insertions(+), 13 deletions(-)

diffs (76 lines):

diff --git a/src/http/modules/ngx_http_dav_module.c 
b/src/http/modules/ngx_http_dav_module.c
--- a/src/http/modules/ngx_http_dav_module.c
+++ b/src/http/modules/ngx_http_dav_module.c
@@ -535,19 +535,20 @@ ngx_http_dav_mkcol_handler(ngx_http_requ
 static ngx_int_t
 ngx_http_dav_copy_move_handler(ngx_http_request_t *r)
 {
-    u_char                   *p, *host, *last, ch;
-    size_t                    len, root;
-    ngx_err_t                 err;
-    ngx_int_t                 rc, depth;
-    ngx_uint_t                overwrite, slash, dir, flags;
-    ngx_str_t                 path, uri, duri, args;
-    ngx_tree_ctx_t            tree;
-    ngx_copy_file_t           cf;
-    ngx_file_info_t           fi;
-    ngx_table_elt_t          *dest, *over;
-    ngx_ext_rename_file_t     ext;
-    ngx_http_dav_copy_ctx_t   copy;
-    ngx_http_dav_loc_conf_t  *dlcf;
+    u_char                    *p, *host, *last, ch;
+    size_t                     len, root, alias;
+    ngx_err_t                  err;
+    ngx_int_t                  rc, depth;
+    ngx_uint_t                 overwrite, slash, dir, flags;
+    ngx_str_t                  path, uri, duri, args;
+    ngx_tree_ctx_t             tree;
+    ngx_copy_file_t            cf;
+    ngx_file_info_t            fi;
+    ngx_table_elt_t           *dest, *over;
+    ngx_ext_rename_file_t      ext;
+    ngx_http_dav_copy_ctx_t    copy;
+    ngx_http_dav_loc_conf_t   *dlcf;
+    ngx_http_core_loc_conf_t  *clcf;
 
     if (r->headers_in.content_length_n > 0 || r->headers_in.chunked) {
         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
@@ -644,6 +645,22 @@ destination_done:
         return NGX_HTTP_CONFLICT;
     }
 
+    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+    alias = clcf->alias;
+
+    if (alias && alias != NGX_MAX_SIZE_T_VALUE) {
+
+        if (alias > duri.len
+            || ngx_filename_cmp(duri.data, r->uri.data, alias) != 0)
+        {
+            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                          "\"Destination\" URI \"%V\" must be "
+                          "within location prefix when using \"alias\"",
+                          &dest->value);
+            return NGX_HTTP_BAD_REQUEST;
+        }
+    }
+
     depth = ngx_http_dav_depth(r, NGX_HTTP_DAV_INFINITY_DEPTH);
 
     if (depth != NGX_HTTP_DAV_INFINITY_DEPTH) {
diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -1912,6 +1912,12 @@ ngx_http_map_uri_to_path(ngx_http_reques
         return NULL;
     }
 
+    if (alias > r->uri.len && alias != NGX_MAX_SIZE_T_VALUE) {
+        ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
+                      "URI shorter than aliased URI part");
+        return NULL;
+    }
+
     if (clcf->root_lengths == NULL) {
 
         *root_length = clcf->root.len;

Reply via email to