exclude: count trailing backslash in add_implied_include

Phase 1 of add_implied_include() decides whether a '\' is escaping a wildcard
via !strchr("*[?", cp[1]).  strchr() returns a pointer to the string literal's
NUL terminator when cp[1]=='\0', so a trailing backslash matches neither branch:
it is emitted into new_pat via the fall-through but backslash_cnt is not
incremented.  The phase-2 recurse/xfer_dirs '/**' rule then allocates
arg_len + backslash_cnt + 3 + 1 and doubles every '\' in new_pat, including the
uncounted trailing one, so the closing '*p = '\0'' lands one byte past the heap
buffer.

Reachable on a standard 'rsync --daemon' deployment (am_server==0 at the
per-module parse_arguments(), so trust_sender_args stays 0) by a remote
unauthenticated client that sends '-r --files-from=-' and a files-from name with
both an interior and a trailing backslash (e.g. 'a\b\').  Count the trailing
backslash so the allocation reserves the doubled slot.

(cherry picked from commit e377e7dc4f3e752723e5fbf9623a8315034e49ab)
(cherry picked from commit 355c115e80)
This commit is contained in:
Andrew Tridgell committed 2026-06-15 17:16:06 +10:00
1 parent b47530c9a8
commit dadecc8e1e
1 file changed
+1 -1
+1 -1
View File
@@ -430,7 +430,7 @@ void add_implied_include(const char *arg, int skip_daemon_module)
if (cp[1] == ']') {
if (!saw_wild)
cp++; /* A \] in a non-wild filter causes a problem, so drop the \ . */
} else if (!strchr("*[?", cp[1])) {
} else if (!cp[1] || !strchr("*[?", cp[1])) {
backslash_cnt++;
if (saw_wild)
*p++ = '\\';