Commit Graph
108 Commits
Author SHA1 Message Date
Andrew Tridgell d29344b3fe backup: fail closed when a symlink target is unreadable
The --safe-links guard on the backup hard-link fast path only skipped the
backup when do_readlink() succeeded (llen > 0) and the target escaped.  A
failed readlink (e.g. the link vanished between the lstat and the
readlink) fell through to link_or_rename(), which could hard-link the
symlink into the backup area unchecked -- the same bypass the guard was
added to close.

Fail closed: skip the backup when the target can't be read.

Extend the KI-72 test with a safe (in-tree) symlink case to confirm the
guard doesn't over-block and drop legitimate safe symlinks.
2026-07-20 14:18:55 +10:00
Leonid Bugaev 58171cf715 Fix bypass of --safe-links when --backup hardlinks a symlink
When CAN_HARDLINK_SYMLINK is defined (Linux, macOS), the backup
hardlink fast path at link_or_rename() succeeded for symlinks and
'goto success' skipped the safe_symlinks check.  An escaping symlink
(pointing outside the transfer tree) was silently preserved in the
backup area despite --safe-links.

Fix: check safe_symlinks BEFORE the hardlink path.  If the symlink
target escapes, skip the backup (same as non-hardlink-symlink systems).

Regression test: testsuite/ki72-safe-links-backup_test.py
2026-07-20 14:17:29 +10:00
Andrew Tridgell 8cbfd8a434 xattrs/backup: read source metadata through a held fd, not a path
The hardened receiver confined the destination side of an xattr/ACL copy (the
fsetxattr/acl_set_fd through a held O_NOFOLLOW fd) but still read the SOURCE side
by path: copy_xattrs() did get_xattr_names/get_xattr_data on the source path, and
make_backup() cached the backed-up file's ACL/xattr via get_acl()/get_xattr() by
path.  A local module writer could race the source/basis parent to a symlink
after the confined content/stat open and before that path-based metadata read,
so out-of-module xattrs/ACLs got copied onto an in-module destination or backup.

Thread a source fd through the read side, mirroring the existing dest-fd plumbing:
 - get_xattr_data(), get_xattr() and get_xattr_acl() gain an fd arg (get_xattr_names
   already had one) and use sys_fgetxattr/sys_flistxattr when fd >= 0; this also
   covers the --fake-super ACL-as-xattr read in get_rsync_acl().
 - copy_xattrs() gains a source_fd; copy_file() passes its held source fd (ifd)
   and keeps it open across the xattr copy (closing it on the fsync error path
   too); gen_entry_copy_xattrs() O_NOFOLLOW-opens the basis leaf under the
   confined resolver (with O_DIRECTORY for a directory basis) and passes it.
 - make_backup() pins the source leaf with a confined O_NOFOLLOW fd
   (backup_source_fd, like set_file_attrs's op_leaf_fd) and reads its ACL via
   get_acl_fdat() and its xattrs via get_xattr(fd); the in-place delta-backup in
   the generator pins fname the same way.  On a hardened receiver a raced/absent
   leaf skips the cache rather than reading through a flippable path.

Non-hardened receivers (fd < 0) keep the path-based behaviour unchanged.  The
basis COMPARE reads (the generator deciding a match) stay path-based: they never
copy out-of-module metadata onto a file, so they are not part of this sink.
2026-06-27 18:22:33 +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 TridgellandClaude Opus 4.7 72a6634479 syscall: add symlink-race-safe do_*_at() wrappers and harden secure_relative_open
Add the rest of the path-based syscall wrappers and migrate every
receiver-side caller:
  - do_lchown_at, do_rename_at, do_mkdir_at, do_symlink_at,
    do_mknod_at, do_link_at, do_unlink_at, do_rmdir_at,
    do_utimensat_at, do_stat_at, do_lstat_at

Same shape as do_chmod_at: open each parent under
secure_relative_open(), call the *at() variant against the dirfd,
fall through to the bare path-based syscall in non-daemon /
chrooted / absolute-path / no-parent cases. macOS's
setattrlist-based set_times tier is also routed through the
utimensat_at path on daemon-no-chroot.

Hardenings to secure_relative_open() itself:
  - confine basedir resolution under the same kernel mechanism
    used for relpath (basedirs from --copy-dest / --link-dest are
    sender-controllable in daemon mode)
  - reject any '..' component (bare '..', 'foo/..', 'subdir/..')
    so the per-component O_NOFOLLOW fallback can't escape
  - return the dirfd we built up from the per-component fallback
    when the caller passed O_DIRECTORY (otherwise every do_*_at
    failed with EINVAL on platforms without RESOLVE_BENEATH)

Adds testsuite/alt-dest-symlink-race.test and
testsuite/secure-relpath-validation.test (with t_secure_relpath
helper) as regression coverage for the new hardenings.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 08:20:48 +10:00
Wayne Davison c3b553a93f Preparing for release of 3.2.4pre2 2022-01-15 17:21:01 -08:00
Wayne Davison 3e44bbd313 Preparing for release of 3.2.4pre1 2022-01-02 15:13:19 -08:00
Wayne Davison e4669b81ae Add the --info=NONREG setting. 2021-11-03 09:35:50 -07:00
Wayne Davison d326961290 Fix overzealous setting of mtime & tweak time comparisons
- Stop setting the mtime on a file we didn't transfer (or didn't verify
  the checksum) when the time diff is within the modify window.
- Stop computing a time difference (-1|0|1) when all we care about is
  time equality.
2020-06-13 02:41:30 -07:00
Wayne Davison 7dec4029ee Convert a couple files to UTF-8; more Copyright years. 2020-06-13 02:41:04 -07:00
Wayne Davison 3e2e4b5a33 Tweak the copyright year. 2019-03-16 09:15:49 -07:00
Wayne Davison 0f8e9e2d86 Don't force nanoseconds if a file wasn't transferred or checksummed. 2018-01-15 10:58:31 -08:00
Wayne Davison 473108ae6e Tweak copyright date. 2018-01-14 19:55:07 -08:00
Wayne Davison abfb41e63e Avoid creating even the top-level backup dir until needed.
Fixes bug 11423.
2015-08-23 21:58:18 -07:00
Wayne Davison 453914e35b Update the copyright year. 2015-08-08 12:47:03 -07:00
Wayne Davison 81d1ca0683 Don't create so many empty backup dirs.
Fixes bug 10724.
2015-08-08 12:19:42 -07:00
Wayne Davison dfa5b49110 Bump the year to 2014. 2014-01-26 09:29:15 -08:00
Wayne Davison 7e1a9c4d79 Update copyright year. 2013-01-19 11:05:53 -08:00
Wayne Davison 9fbec6e44c May as well use do_mkdir() directly these days. 2010-04-30 12:58:17 -07:00
Matt McCutchen 0b8a9bd69d Minor restructuring/clarification to get_backup_name.
(Tweaked by Wayne to follow his preferred style.)
2010-04-24 09:56:34 -07:00
Matt McCutchen 7a3ce973c3 In "ignoring unsafe symlink" messages, show only the file-list path.
Rsync was showing the full destination path, which was confusing because
nothing is created at that path and was especially bogus in combination
with the source name of a solo file.

http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=506830
2010-04-24 09:51:54 -07:00
Wayne Davison 9b594a530f Handle files that spring up while doing backup path checking. 2010-03-09 11:58:07 -08:00
Wayne Davison 3696674bc6 More backup improvements:
- Changed get_backup_name() to verify the backup path, and make any
  missing directories.  This avoids accidental use of a symlink as a dir
  in a backup path, and gets rid of any other non-dirs that are in the
  way.  It also avoids the need for various operations to retry after
  calling make_bak_dir(), simplifying several pices of code.
- Changed create_directory_path() to make_path(), giving it flags that
  lets the caller decide if it should skip a leading slash or drop the
  trailing filename.
- Mention when we create the backup directory, so the user is not caught
  unaware when rsync uses a directory they didn't expect.
- Got rid of some dir-moving backup code that is not used.
- Added a little more backup-debug output.
2009-04-11 11:51:07 -07:00
Wayne Davison 5e2d51ee06 Fix "just in case" unlink. Prefer renaming of normal files
if hard-linking fails.
2009-04-11 06:37:49 -07:00
Wayne Davison d735fe2014 Improved link_or_rename() to handle prefer_rename better. 2009-04-10 23:33:08 -07:00
Wayne Davison cb197514d9 Fixed an ACL/xattr corruption issue where the --backup option could cause
rsync to associate the wrong ACL/xattr information with received files.
2009-04-10 16:22:44 -07:00
Wayne Davison e6f3a33c5e Make the backup code call unsafe_symlink() correctly. 2009-03-03 08:42:56 -08:00
Wayne Davison 21cddef2b4 Improved the backup code:
- Backups do not interfere with an atomic update (when possible).
- Backing up a file will remove a directory that is in the way
  and visa versa.
- Unify the backup-dir and non-backup-dir code in backup.c.
- Improved the backup tests a little bit.
2009-01-03 12:02:47 -08:00
Wayne Davison b3bf9b9df9 Update the copyright year. 2009-01-03 10:57:14 -08:00
Wayne Davison 09ca0d15d3 Added init_stat_x() to avoid duplication of acl/xattr init code. 2009-01-03 08:53:59 -08:00
Wayne Davison 951e826b75 Added the --info=FLAGS an --debug=FLAGS options, which allows
fine-grained output control (in addition to the coarse -v).
2008-07-13 20:51:08 -07:00
Wayne Davison a64f19e24b Fixed the backing up of a device or socket. 2008-05-22 16:44:01 -07:00
Wayne Davison 88e05f8489 Fixed an "else" in the device-making part of keep_backup(). 2008-05-17 09:57:08 -07:00
Wayne Davison e9489cd6cb Fixed several issues with preserving xattrs when using --backup. 2008-05-17 09:35:46 -07:00
Wayne Davison f1ca7c4429 Preserve the right errno value when trying adjunct functions during
robust backup, copy, and renaming activities.
2008-05-17 08:25:22 -07:00
Wayne Davison d3d07a5e86 Include 2008 in the copyright years. 2008-03-01 12:01:41 -08:00
Wayne Davison 13710874ce Changed "statx" to "stat_x" to try to work around a build problem on AIX. 2007-09-23 22:19:55 +00:00
Wayne Davison e1ac7791fe Changed make_bak_dir() to take a const char *. 2007-09-23 21:03:38 +00:00
Wayne Davison f203266889 Made make_bak_dir() global. 2007-09-23 19:45:19 +00:00
Wayne Davison 8e41b68e8f Tweaking the license text a bit more. 2007-07-10 13:55:49 +00:00
Wayne Davison 4fd842f98d Switching to GPL 3. 2007-07-07 05:33:14 +00:00
Wayne Davison b13505da1d Need to call unmake_file() instead of free() on a file_struct. 2007-04-24 18:43:31 +00:00
Wayne Davison 9439c0cb5a Adding the --fake-super option. 2007-04-24 07:32:44 +00:00
Wayne Davison 16edf86595 The improved --xattrs option is landing on the trunk. 2007-04-07 17:22:25 +00:00
Wayne Davison 1c3344a105 The ACL support has arrived! This version has a brand new protocol
that makes it incompatible with all prior versions.  A patch will be
provided to allow talking with older (patched) rsync versions.
2007-03-11 00:13:34 +00:00
Wayne Davison ba2133d6ad Further modifications to the copyright comment section. 2007-02-04 14:54:58 +00:00
Wayne Davison e238c9977d Use the new device defines: F_RDEV_P(), DEV_MAJOR(), and DEV_MINOR(). 2006-12-07 03:31:31 +00:00
Wayne Davison 7a821d518b Tweaked some externs. 2006-12-05 15:59:46 +00:00
Wayne Davison 6b2a3d5de6 Moved an extern. 2006-12-03 07:58:12 +00:00
Wayne Davison 82ad07c418 - Typical tranfers now save 12-20 bytes per file because several vars
were moved out of file_struct into an optional member-var setup.
- Renamed and reorganized the FLAG_* defines.
- Use NDX_DONE instead of a literal -1 when sending/checking the
  end-of-phase index value.
2006-12-03 06:44:16 +00:00