Description:
* SECURITY UPDATE: peer-driven one-byte heap out-of-bounds write in
add_implied_include() from a files-from entry carrying both an interior
and a trailing backslash:
- debian/patches/els/0009-CVE-2026-70461.patch: count a trailing
backslash when sizing the appended-wildcard pattern.
- CVE-2026-70461.
* SECURITY UPDATE: heap out-of-bounds write in read_args() when the peer's
argument count lands exactly on the argv allocation:
- debian/patches/els/0010-CVE-2026-70456.patch: reserve room for the
trailing NULL terminator.
- CVE-2026-70456.
* SECURITY UPDATE: out-of-bounds write from a file entry marked
FLAG_HLINKED that the receiver accepted with hard-link preservation
inactive:
- debian/patches/els/0011-CVE-2026-70458.patch: gate FLAG_HLINKED on
preserve_hard_links and exclude directories.
- CVE-2026-70458.
* SECURITY UPDATE: sender-side out-of-bounds read driven by a malicious
receiver's checksum header with a non-zero block count and a zero block
length:
- debian/patches/els/0012-CVE-2026-53792.patch: reject a zero block
length in read_sum_head().
- CVE-2026-53792.
* SECURITY UPDATE: CPU exhaustion in the sending process via
quadratic-time behaviour in hash_search(), driven by a malicious
receiver's crafted equal-weak-checksum block list. The attacker is the
receiver, but the cycles burned are the sender's: hash_search() is
reached only through match_sums(), whose sole caller is send_files() in
sender.c. NVD's text attributes the CPU to the receiver; the direction
stated here is what the code does:
- debian/patches/els/0013-CVE-2026-70453.patch: bound the per-offset
chain walk.
- CVE-2026-70453.
* SECURITY UPDATE: daemon "hosts deny" failing open when a configured
hostname token cannot be resolved:
- debian/patches/els/0014-CVE-2026-70452.patch: treat an unresolvable
deny-list token as a match.
- CVE-2026-70452.
* SECURITY UPDATE: daemon "auth users" ignoring its documented comma-only
parsing, silently discarding a deny rule that names a group whose name
contains a space:
- debian/patches/els/0015-CVE-2026-70463.patch: parse the list with
conf_strtok().
- CVE-2026-70463.
* SECURITY UPDATE: peer-supplied MSG_IO_TIMEOUT disabling the client's own
I/O timeout through a non-positive or overflowing value:
- debian/patches/els/0016-CVE-2026-70462.patch: cap the received value
and make set_io_timeout() arithmetic overflow-safe.
- CVE-2026-70462.
* SECURITY UPDATE: client-supplied --filter merge file bypassing the daemon
module filter list:
- debian/patches/els/0017-CVE-2026-53786.patch: strip the module-dir
prefix before the daemon-filter check.
- CVE-2026-53786.
* SECURITY UPDATE: per-connection daemon child crash on a crafted first
incremental file list whose transfer root is a non-directory dot entry:
- debian/patches/els/0018-CVE-2026-70459.patch: reject a non-directory
transfer-root entry and require a dir_flist entry before trusting
parent_ndx 0.
- CVE-2026-70459.
* SECURITY UPDATE: malicious sender widening the receiver's --delete scope
beyond the destination subtree via implied-parent reclassification:
- debian/patches/els/0019-CVE-2026-53789.patch: force implied-parent
directories non-content on the receiver, including the synthetic
transfer root and the pre-protocol-30 encoding.
- CVE-2026-53789.
* SECURITY UPDATE: unauthenticated pre-transfer handshake stall holding a
per-connection daemon child past the module's max connections limit:
- debian/patches/els/0020-CVE-2026-70464.patch: bound every
peer-controlled handshake read with an absolute deadline and cap the
early-protocol argument count.
- CVE-2026-70464.
* SECURITY UPDATE: command and argument injection through the
RSYNC_CONNECT_PROG %H host substitution, through unquoted arguments in a
--write-batch replay script, and through remote-shell argument quoting
that did not escape the newline, the carriage return or the backtick:
- debian/patches/els/0021-CVE-2026-53790.patch: shell-quote and validate
the connect host, and quote every replay-script argument.
- debian/patches/els/0025-CVE-2026-53790-safe-arg-shell-chars.patch: add
the newline, the carriage return and the backtick to safe_arg()'s
SHELL_CHARS escape set. safe_arg() escapes metacharacters because the
remote end is reached as "ssh rsync --server ...", where ssh
joins the command words and the remote sshd hands the string to the
remote user's login shell, which re-parses it; an unescaped newline
therefore ended the transfer command and ran what followed, and an
unescaped backtick opened a command substitution. This package
acquired safe_arg() from els/0001-CVE-2022-29154.patch, whose donor
predates the backtick's addition upstream.
- Partial fix: the daemon %RSYNC_*% exec-hook expansions do not exist in
3.1.3 and rsync-ssl is not installed by debian/rules, so those two of
the four sinks named in the advisory are not present in this package.
- CVE-2026-53790.
* SECURITY UPDATE: further out-of-bounds F_SUM() reads where the checksum
extra slot was never reserved -- a daemon sender with "%C" in its log
format, a hard-linked non-regular entry compared against a basis dir,
and "%C" on a deletion:
- debian/patches/els/0022-CVE-2026-70458.patch: set
sender_keeps_checksum in start_server(), require S_ISREG(file->mode)
before the content compare in hard_link_check(), and skip the
checksum for an ITEM_DELETED entry.
- CVE-2026-70458.
* Drop two peer-reachable assert() aborts (no CVE assigned; carried from
the same upstream commit as several of the fixes above, and live in the
shipped binary because nothing in the build defines NDEBUG):
- debian/patches/els/0023-peer-reachable-asserts.patch: turn an
undeclared cross-flist hard-link gnum into a protocol error instead of
an assert, and stop asserting !is_utf8 when a daemon receiver
forwards a peer message to the generator.
* Bound merge-file include recursion (no CVE assigned; the remaining
peer-reachable crash hunk of the same upstream commit several of the
fixes above come from). A merge file's content may name another merge
file, so parse_filter_file() re-enters itself with a BIGPATHBUFLEN
stack buffer per level; a self-referencing per-directory merge file,
whose content the peer supplies through the transferred tree, recursed
until the stack was exhausted (SIGSEGV):
- debian/patches/els/0024-merge-file-depth-cap.patch: add
MAX_MERGE_DEPTH and a nesting counter.
* Add committed regression tests to the shipped test suite for the six
fixes that a black-box test can observe, each carried by the patch it
proves and each failing without that patch:
- testsuite/cve-2026-70452.test (els/0014), an unresolvable "hosts deny"
token must deny.
- testsuite/cve-2026-70463.test (els/0015), the first word of a
space-bearing "auth users" entry must not become an allow rule.
- testsuite/cve-2026-53786.test (els/0017), a daemon filter rule must
govern a client merge file, and an "exclude from" path that only shares
the module path's textual prefix must not be truncated.
- testsuite/cve-2026-53790.test (els/0021), a newline-bearing filter rule
must not reach the replay script and an injected RSYNC_CONNECT_PROG %H
host must not execute.
- testsuite/cve-2026-53790-shell-chars.test (els/0025), a newline, a
carriage return or a backtick in a path must not execute a command on
the remote shell, and an ordinary transfer over the same remote shell
must still work.
- testsuite/cve-2026-70458.test (els/0022), the daemon's logged "%C" must
be the file's checksum, not adjacent pool memory.
- testsuite/merge-depth.test (els/0024), a self-referencing merge file
must be refused, not crash the process.
- testsuite/cve-2026-53790-safe-arg-uninit.test (els/0027), a trailing
backslash in a path must reach the remote shell doubled, and no stray
byte may follow a path that carries a backslash.
* SECURITY UPDATE: safe_arg() sized its result one byte larger than it
wrote for every backslash that precedes a wildcard and for a trailing
backslash, so the closing NUL landed past the last byte written and
uninitialised heap was returned inside the string handed to the remote
shell (--protect-args is off by default in 3.1.3). The same defect left a
trailing backslash unescaped there, where it escapes the following space
and joins the next word:
- debian/patches/els/0027-CVE-2026-53790-safe-arg-uninit.patch: make the
escape counter mirror the writer and guard the WILD_CHARS lookup with
f[1]. Upstream's own stable-branch backport (1aef79e1 on
v3.2.7-sec-patches3, from 22efd249), applied unchanged.
- CVE-2026-53790.
* SECURITY UPDATE: a fourth out-of-bounds F_SUM() read, specific to this
package. generator.c unchanged_file() guards the checksum compare on the
destination's on-disk mode while the slot is reserved from the
peer-supplied file->mode; Debian's copy-devices.diff lets a device entry
reach it, so with -c --copy-devices a sender's device entry whose
destination is an existing regular file reads below its pool slot:
- debian/patches/els/0030-CVE-2026-70458-copy-devices.patch: require
S_ISREG(file->mode) as well.
- CVE-2026-70458.
* Carry the four remaining hunks of upstream 3eeedf8d that land in
functions this series already patches (no CVE assigned; the same
malicious-peer hardening commit seven of the patches above cite):
- debian/patches/els/0026-donor-parity-3eeedf8d.patch: re-check the block
length before adopting want_i in hash_search(), clamp a peer-supplied
s->flength to the local length in match_sums(), and refuse a sub-flist
that arrives after the final flist was freed or that names a cleared
dir_flist slot in recv_file_list().
* Fix secure_relative_open() never returning a directory descriptor. The
per-component walk only assigned the result in its ENOTDIR arm, so a
path that resolved to a directory fell through to "errno = EINVAL" and
returned -1. Every permission change on a daemon receiver running with
"use chroot = no" therefore failed with "failed to set permissions ...
Invalid argument (22)" and the transfer exited 23. Introduced by
els/0006-CVE-2026-29518.patch, which added both the helper and its
O_DIRECTORY callers:
- debian/patches/els/0029-secure-relative-open-dirfd.patch.
* Run the upstream testsuite during the build, so the regression tests
above are load-bearing:
- debian/patches/els/0028-testsuite-harness.patch: add the missing
syscall.o stubs (noatime, am_daemon, am_chrooted) to tls.c,
trimslash.c and t_unsafe.c, without which "make check" could not even
link its helper programs, and let runtests.sh honour a $skiptests list.
- debian/rules: run "make check" from build-stamp unless
DEB_BUILD_OPTIONS=nocheck, excluding devices and devices-fake, which
fail identically on 3.1.3 with only the Debian patches applied.