Commit Graph
641 Commits
Author SHA1 Message Date
Filipe Casal f1e1bcb027 options: refuse aliases for exact option rules
parse_one_refuse_match() marked only the first long_options row whose
long name matched the configured spelling, then broke out for a
non-wildcard rule.  --compress-threads and --zt are separate popt rows
that both write &do_compression_threads, so "refuse options =
compress-threads" disabled the canonical row and left the alias
accepted: the refused capability was still reachable under its other
name.  The same shape covers zc/compress-choice and zl/compress-level.

An exact rule names a capability, not one spelling of it, so mark every
row that does the same thing.  Comparing the raw table fields is not
enough for that: popt's `val` means different things per argInfo.  For
POPT_ARG_VAL it IS the value stored in `arg`, while elsewhere a nonzero
`val` is an action code for the parser's switch, and POPT_ARG_NONE with
a destination stores 1 whatever `val` says.  --del is
POPT_ARG_NONE/&delete_during/0 and --delete-during is
POPT_ARG_VAL/&delete_during/1: the same destination and the same
resulting value, but unequal as table entries, so "refuse options =
delete-during" was still evaded by --del and the mirror held too.

Compare what a row does instead -- the destination and the constant it
assigns, falling back to table-entry equality for rows that store a
runtime value or only dispatch an action.  Enumerating all 258 rows,
this couples exactly one pair the field comparison missed, del and
delete-during, and changes nothing else.  Opposite switches such as
--foo and --no-foo stay distinct because they assign different values.

Two regressions.  The compress-threads one drives the raw daemon
protocol -- not to preserve the spelling, which -M--zt=N would do just as
well, but because it goes on to observe the worker pool the bypass
delivers.  Its oracle is the refusal itself -- the alias connection torn
down and
"configured to refuse --zt" logged -- and deliberately not the resulting
worker count: an accepted --zt is a defeated refuse rule however few
threads it produces, and the daemon worker cap being added alongside
this holds that count to 9, so a count-based assertion passes while the
alias is still accepted.  Run that test against the cap without this
parser fix and it does exactly that; the two changes were covering for
each other.

The delete one needs neither zstd nor a socket: --remote-option puts the
option in the daemon's argv verbatim, which is the reach an ordinary
user already has, so it drives a stock client both ways round against
modules refusing each spelling, with an unrefused module as the control.

The compress-threads test needs --use-tcp, so it skips in every other
column and is declared in the workflows that enforce a skip set, which a
fleet run otherwise reports as an unexpected skip on fourteen cells.

(cherry picked from commit c529163ef0)
2026-08-02 21:33:25 +10:00
Andrew Tridgell fc89bf6ddc rsync: add --drop-D, refusing device/special creation only
-D and --no-D do two jobs at once: they decide whether devices and
special files are created, and they decide whether those entries carry
their rdev fields on the wire.  send_file_entry() and recv_file_entry()
frame those fields with the same condition, but each end evaluates its
own preserve_devices/preserve_specials, so the two only agree because
both normally parse the same command line.

That makes --no-D unusable for a wrapper that controls one end of a
connection and wants to deny creation.  Give it to the receiver alone
and the client's -D sender writes rdev the receiver never reads: the
file list desynchronises from that entry on.  A FIFO or socket breaks
below protocol 31 -- a hang at 29, "File-list index 0 not in 0 - -1" at
30 -- and a device node breaks at EVERY protocol, current ones included,
because its arm of the condition has no protocol clause at all.

--drop-D separates the two jobs: it refuses the creation and leaves the
encoding alone.  The entry is skipped through the existing non-regular
fall-through, so the visible result matches --no-D, and because it
touches no wire state it can be applied to one end by itself.

It has no effect on a sending rsync, which creates nothing.

(cherry picked from commit b607369f5f)
2026-08-02 21:33:25 +10:00
Andrew Tridgell 7821796b58 rsync: confine the daemon files-from open to the module root
A daemon serving a writable, non-chrooted module reads a client-requested
--files-from=:LIST through open_no_attacker_symlinks(), which follows a
symlink owned by uid 0 or the euid.  The module-root confinement in that
resolver (abspath_excluded_by_module) only fires when operator_path_resolve
is set, and this open left it clear -- so a trusted-owned symlink whose
target escapes the module was followed.

An attacker can obtain such a symlink without owning it: a --backup-dir push
makes the daemon back up the old destination symlink with the daemon's own
(root) ownership, and a parent-swap race can leave that root-owned backup
symlink pointing outside the module.  A later --files-from=:backup/... then
reads out-of-module file content as the file list, bypassing the same-uid
ownership constraint that normally protects files-from.

Set operator_path_resolve around the files-from open so the ownership walk
also refuses a trusted-owned symlink that redirects the list outside the
module root.  A daemon has no rsyncd.conf "files from" of its own, so this
path is always client-requested and confining it is unconditional.  No-op off
a daemon (the module-root check only fires when am_daemon).

The same ownership-walk opener backs the daemon merge/--exclude-from reads in
exclude.c, but those also load the module's own "include from"/"exclude from"
admin files, which on a non-chrooted module may legitimately live outside the
module; confining them there needs a client-vs-admin distinction and is left
to a separate change.
2026-07-24 16:39:13 +10:00
Andrew TridgellandGreg Kroah-Hartman 8190f47173 options/token: bound the -v repetition, output level, and suffix token
Cap -v repetition so the argstr[64] global can't overflow, clamp a
negative --info/--debug level out of counts[], and cap a --skip-compress
suffix token at 32 bytes.

Co-authored-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2026-06-22 09:21:59 +10:00
Andrew Tridgell ad2ccf95ce daemon: treat exclude=/filter as a name filter, not a symlink boundary
The daemon exclude/filter chain is a name-based visibility filter, exactly as in
stock rsync: a symlink whose own name is not excluded is still followed to an
excluded target (the documented defense for a writable module is "munge symlinks").
Drop the in-module physical-path refusal from abspath_excluded_by_module() (it now
only confines operator/peer paths to the module ROOT) and restore stock rsync's
NAME-based ".." collapse for the daemon-filter checks on the destination,
basis/partial dirs and --temp-dir/--backup-dir via sanitize_path().
2026-06-21 18:25:28 +10:00
Andrew Tridgell a74cce06a7 confine operator- and peer-supplied paths to the served module
Route operator-supplied paths (--partial-dir, --backup-dir, alt/copy/link-dest,
--temp-dir, --files-from, --log-file, config and secrets files) and the sender's
own enumeration through the race-safe resolver and an ownership walk that refuses a
target redirected outside the module root.  open_tmpfile() now creates the temp via
the cached held dir fd (do_mkstemp_atfd) so an in-tree dir symlink is followed
safely instead of refused.  Adds --insecure-links to opt back into legacy following;
the daemon hard-refuses the client flag (use the "insecure links" module param).
2026-06-21 18:25:28 +10:00
Andrew Tridgell ada5da09e2 options: clamp snprintf length before err_buf[len] write in parse_size_arg
C99 snprintf returns the would-have-written length on truncation, so when a
daemon client sends an oversized --max-size/--min-size/--bwlimit/--block-size/
--max-alloc value (each arg can be up to BIGPATHBUFLEN-1 = 5119 bytes via
clientserver.c:read_args), len at the failure: label can far exceed
sizeof err_buf (200).  The trailing

    err_buf[len] = '\n';
    err_buf[len+1] = '\0';

then write 0x0A,0x00 at a byte-precise attacker-chosen offset up to ~4.9KB
past err_buf into adjacent .bss.  The same happens via the second snprintf
when the first lands len in [~140,189] and the (min/max: ...) suffix is
truncated.

Clamp len to sizeof err_buf - 2 before the trailing writes, covering both
paths.  Reachable from an unauthenticated client against any daemon module
before chroot/privilege-drop; introduced in 66ca4fc97b (2020-07-10).

(cherry picked from commit 3b81103d7ec98145710f8845dd676ba34458169a)
2026-06-15 17:15:28 +10:00
Andrew Tridgell 0d5e8a0614 options: bound size args and escape remote-shell newlines
Backport of the 3.5.0 option-parsing hardening:
 - bound parse_size_arg() against integer overflow;
 - reject a zero --max-alloc (which would disable the per-allocation
   sanity cap);
 - escape newlines in remote-shell argument expansion.

Tests: daemon-max-alloc-zero, max-alloc-zero-rejected,
remote-shell-newline-escaping.

Reported-by: Azizcan Dastan <azizcan.dastan5@gmail.com>
2026-06-12 15:55:30 +10:00
Andrew TridgellandClaude Opus 4.7 f629772cc6 syscall+clientserver: am_chrooted and use_secure_symlinks for daemon-no-chroot (CVE-2026-29518)
CVE-2026-29518: an rsync daemon configured with "use chroot = no"
is exposed to a TOCTOU race on parent path components. A local
attacker with write access to a module can replace a parent
directory component with a symlink between the receiver's check
and its open(), redirecting reads (basis-file disclosure) and
writes (file overwrite) outside the module. Under elevated daemon
privilege this allows privilege escalation. Default
"use chroot = yes" is not exposed.

Add secure_relative_open() in syscall.c. It walks the parent
components under RESOLVE_BENEATH (Linux 5.6+) /
O_RESOLVE_BENEATH (FreeBSD 13+, macOS 15+) / per-component
O_NOFOLLOW elsewhere, anchored at a trusted dirfd, so a parent-
symlink swap is rejected by the kernel. Route the receiver's
basis-file open in receiver.c through it when use_secure_symlinks
is set in clientserver.c rsync_module().

Reporters: Nullx3D (Batuhan SANCAK); Damien Neil; Michael Stapelberg.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 08:20:48 +10:00
Michal Ruprich c966f3864d Using a correct time in log file 2026-05-07 06:33:16 +10:00
Ronnie Sahlberg bbecd5bc1a options.c: Fix segv if poptGetContext returns NULL
If poptGetContext returns NULL, perhaps due to OOM,
a NULL pointer is passed into poptReadDefaultConfig()
which in turns SEGVs when trying to dereference it.

This was found using https://github.com/sahlberg/malloc-fail-tester.git
$ ./test_malloc_failure.sh rsync -Pav crash crosh

Signed-off-by: Ronnie Sahlberg <ronniesahlberg@gmail.com>
2026-05-07 06:33:16 +10:00
Wayne Davison bcf0738f98 Indentation tweak. 2024-11-05 11:20:17 -08:00
Wayne Davison 2f9b963aba Make --max-alloc=0 safer.
Always do size checking in my_alloc(), even for `--max-alloc=0`.
2023-06-27 09:01:25 -07:00
Wayne Davison 9a06b2edb0 Preparing for release of 3.3.0pre1 [buildall] 2023-04-29 09:01:43 -07:00
Wayne Davison 0698ea9aeb Fix flist string comparison issue in tr_TR.utf-8 locale. 2023-02-05 19:46:45 -08:00
Wayne Davison 5c93dedf45 Add backtick to SHELL_CHARS. 2023-01-04 21:52:48 -08:00
Wayne Davison 8990ad96de Duplicate argv data before poptFreeContext(). 2022-11-22 22:21:15 -08:00
Wayne Davison 5374994089 Avoid quoting of tilde when it's a destination arg. 2022-11-05 09:22:10 -07:00
Wayne Davison 0efa63f2e6 Use JSON output if --version (-V) is repeated (client side only). 2022-09-10 13:14:42 -07:00
Wayne Davison 0a09df2c5e Rename --protect-args to --secluded-args. 2022-08-23 14:56:23 -07:00
Wayne Davison db4f919ebe Allow ~/remote/./path with -R if the path has /./ in it. 2022-08-15 18:55:05 -07:00
Wayne Davison cff8f04477 Add --trust-sender option. 2022-08-09 11:45:56 -07:00
Wayne Davison db8034f12e Escape leading tilde char when "~" or with -R. 2022-08-09 11:42:32 -07:00
Wayne Davison 38e1b075b4 Fix some issues with backslashed wildcards in args. 2022-08-08 19:26:05 -07:00
Wayne Davison 7e5424b806 More improvements to file-list checking
- Avoid implied rules on generator and (with extra certainty) on server
- Add -R implied-directory path elements as directory includes
- Log about extra file-list checking using a new --debug=FILTER3 level
2022-08-01 07:00:51 -07:00
Wayne Davison 8aa465117f Add new & improved --copy-devices option. 2022-03-27 14:04:59 -07:00
Wayne Davison d9eaffe564 Complain about --old-args with --protect-args. 2022-01-17 18:09:36 -08:00
Wayne Davison 635d8c0632 A repeated --old-args does more escape disabling. 2022-01-09 18:20:23 -08:00
Wayne Davison 6b8db0f644 Add an arg-protection idiom using backslash-escapes
The new default is to protect args and options from unintended shell
interpretation using backslash escapes.  See the new `--old-args` option
for a way to get the old-style splitting.  This idiom was chosen over
making `--protect-args` enabled by default because it is more backward
compatible (e.g. it works with rrsync). Fixes #272.
2022-01-09 17:47:24 -08:00
Wayne Davison f1a6998df2 Only send the --no-W kluge to a receiver. 2022-01-02 23:51:35 -08:00
Wayne Davison 3e44bbd313 Preparing for release of 3.2.4pre1 2022-01-02 15:13:19 -08:00
Wayne Davison 4adfdaaf12 Tweak stderr handling for older BackupPC versions
This makes the default for a protocol-28 server process be --stderr=client
instead of --stderr=errors.  See rsync's github issue #95.
2022-01-02 14:48:04 -08:00
Wayne Davison e4669b81ae Add the --info=NONREG setting. 2021-11-03 09:35:50 -07:00
Wayne Davison 7956070f2b Make --chown|--usermap|--groupmap imply -o|-g (as appropriate). 2021-10-19 21:10:12 -07:00
Wayne Davison b774dbc1c0 Improve --omit-dir-times & --omit-link-times
The code now better handles skipping time setting on dirs and/or links
when --atimes and/or --crtimes is specified without --times.
2021-10-10 13:39:09 -07:00
Wayne Davison 82f023d7e3 Add --fsync option (promoted from patches). 2021-09-27 10:30:00 -07:00
Wayne Davison ec57c57baf Help avoid a --sparse --inplace bug in older rsyncs. 2021-09-27 10:16:15 -07:00
Wayne Davison d2a97a7ab4 Various file comparison improvements
- Rename unchanged_file() to quick_check_ok().
- Enhance quick_check_ok() to work with non-regular files.
- Add a get_file_type() function to the generator.
- Use the new functions in the generator code to make the logic simpler.
- Fix a bug where the `--alt-dest` functions were not checking if a
  special file fully matched the non-permission mode bits before
  deciding if we have found an alt-dest match.
- Enhance the `--info=skip --ignore-existing` output to include extra
  info on if the existing file differs in type or passes the standard
  quick-check logic.
- Add `--info=skip2` that authorizes rsync to perform a slow checksum
  "quick check" when ignoring existing files. This provides the uptodate
  and differs info even if we need to checksum a file to get it.
2020-09-22 12:48:02 -07:00
Wayne Davison 25526eb3fe Simplify the compat logic for local_server
Change the logic in compat.c to construct the client_info string value
for a local copy so that the various checks of the string don't need to
make an exception for local_server.
2020-08-27 19:23:13 -07:00
Wayne Davison 6c89f00d1b Move SUPPORT_ATIMES to rsync.h. 2020-08-03 13:27:00 -07:00
Wayne Davison dee0993286 Create usage.c for smaller awk-dep rebuilds. 2020-08-03 12:23:18 -07:00
Wayne Davison 47351c2b16 Use RSYNC_GITVER in more output 2020-08-03 10:46:31 -07:00
Wayne Davison d73c26d2b7 Put git version in a file for between-release versioning. 2020-08-01 00:15:06 -07:00
Wayne Davison 21ecc833ea Change new stderr options to --stderr=MODE. 2020-07-25 10:03:32 -07:00
Wayne Davison f9bb8f76ee Change daemon variable & simplify some option code
- Rename daemon_over_rsh -> daemon_connection since it is also used to
  indicate if a non-rsh daemon connection is active.
- Move the daemon-over-rsh exception out of server_options() to the one
  caller that needs that behavior.
- Don't allow noop_io_until_death() to be short-circuited when talking
  to a daemon over a socket, because it can't send errors via stderr.
2020-07-25 09:36:42 -07:00
Wayne Davison 0a255771f4 Add --errors2stderr & --msgs2protocol options. 2020-07-24 22:48:37 -07:00
Wayne Davison 842d6edfdc Fix devices-fake test if rsync can't link specials
- Add info about hardlinked specials to --version output.
- Use "no hardlink-special" info to ensure that the devices-fake
  test will not fail.
2020-07-24 11:33:21 -07:00
Wayne Davison 01742c07e6 Add --mkpath option. Fixes bugzilla bug 4621. 2020-07-23 20:54:38 -07:00
Wayne Davison d8941be8cb Simplify the msgs2stderr default logic. 2020-07-23 12:15:50 -07:00
Wayne Davison 592059c8fd Improve error output for local & remote-shell xfers 2020-07-23 11:23:47 -07:00