mirror of
https://github.com/RsyncProject/rsync.git
synced 2026-09-15 14:51:20 -04:00
rrsync: protect no-overwrite auxiliary paths
--ignore-existing protects the live transfer destination, but three
peer-selectable options reach other existing objects inside the
restricted directory: --log-file appends to one, --partial-dir consumes
and then renames or unlinks one, and --delay-updates does the same
through its implicit .~tmp~ directory. Refuse all three under
-no-overwrite.
Refusal rather than confinement, because confining these paths does not
help: keeping the --log-file append inside the tree still appends to an
existing file, and for the partial directories the peer controls both
the directory and the transferred basename, so a collision is always
reachable. A pre-exec emptiness check would be raceable. The cost is
that a push naming --partial-dir on the remote receiver, or using
--delay-updates, is now refused for a -no-overwrite account.
Each regression drives the option through a wrapper WITHOUT
-no-overwrite as well, and requires that to be accepted. Without that
control the tests cannot tell "refused under -no-overwrite" from
"refused always", and would still pass if the options were disabled for
every rrsync deployment -- verified by making the refusal unconditional,
which the controls then catch.
The wrapper is handed a shim rather than RSYNC directly: RSYNC is a
multi-word command whenever the runner forces --protocol=N, and rrsync
execlp()s its RSYNC as a single executable name, so every one of these
tests died before reaching the policy under test. A fleet run caught it
on the protocol columns of three targets.
Backup mode belongs in the same set. Publishing a backup onto a name
that already exists deletes what is there (backup.c make_backup()), and
deleting a file backs it up first (delete.c), so a --delete of an
unrelated file can land on a protected name -- overwriting a file that
--ignore-existing was holding, with rc=0 and no diagnostic. Disable -b
and --backup-dir. --suffix is left enabled: with both of those refused
nothing can turn backups on, so it is inert.
The short option must be disabled before short_no_arg_re is built, since
a stock client sends b inside the remote short-option bundle and the
regex is snapshotted there; the whole -no-overwrite block therefore
moves up beside the other policy gates rather than sitting after the
chdir. Its regression drives the collision through a wrapper without
-no-overwrite, passing --ignore-existing by hand, which both proves the
refusal is conditional and shows the primitive defeating the very
protection -no-overwrite forces.
rrsync.1.md now states what -no-overwrite costs: no explicit
--partial-dir, no --delay-updates, no server-side --log-file, no backups.
(cherry picked from commit c3abc6c095)
This commit is contained in:
500 Internal Server Error
Gitea Version: 1.28.0+dev-477-g8b6ad49a5f