1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
|
From 9739e755b8dddba82e65ca2a08d079f4c9826b75 Mon Sep 17 00:00:00 2001
From: Roman Arutyunyan <arut@nginx.com>
Date: Mon, 16 Mar 2026 20:13:03 +0400
Subject: [PATCH] Dav: destination length validation for COPY and MOVE.
Previously, when alias was used in a location with Dav COPY or MOVE
enabled, and the destination URI was shorter than the alias, integer
underflow could happen in ngx_http_map_uri_to_path(), which could
result in heap buffer overwrite, followed by a possible segfault.
With some implementations of memcpy(), the segfault could be avoided
and the overwrite could result in a change of the source or destination
file names to be outside of the location root.
Reported by Calif.io in collaboration with Claude and Anthropic Research.
---
src/http/modules/ngx_http_dav_module.c | 39 +++++++++++++++++---------
1 file changed, 26 insertions(+), 13 deletions(-)
diff --git a/src/http/modules/ngx_http_dav_module.c b/src/http/modules/ngx_http_dav_module.c
index cfb98929e9..4619b139a2 100644
--- 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_request_t *r, ngx_http_dav_loc_conf_t *dlcf)
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;
+ 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,18 @@ ngx_http_dav_copy_move_handler(ngx_http_request_t *r)
return NGX_HTTP_CONFLICT;
}
+ clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+
+ if (clcf->alias
+ && clcf->alias != NGX_MAX_SIZE_T_VALUE
+ && duri.len < clcf->alias)
+ {
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "client sent invalid \"Destination\" header: \"%V\"",
+ &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) {
|