[PATCH] Dav: destination validation for COPY and MOVE with "alias"
Maxim Dounin
mdounin at mdounin.ru
Mon Mar 30 02:26:30 UTC 2026
# HG changeset patch
# User Maxim Dounin <mdounin at mdounin.ru>
# Date 1774837227 -10800
# Mon Mar 30 05:20:27 2026 +0300
# Node ID 7fdbec4cfc46573e1c9e26680488c27d79664083
# Parent 04172e7f25c62ee20690f369801a1a846ee04ad2
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
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;
More information about the nginx-devel
mailing list