Commit Graph
59 Commits
Author SHA1 Message Date
Vladimir Marek d903874d63 acls: implement Solaris facl(2)-based ACL helpers
Solaris has facl(2), which performs ACL operations on an already-open file
descriptor.  This adds Solaris fd-based helpers for the ACL operations that
rsync needs while keeping the existing path-based fallback for callers without
a held fd.

On Solaris, setting an ACL on a directory replaces the combined access and
default ACL set.  The path-based sys_acl_set_file() already handled this by
reading the other half of the directory ACL, merging access and default entries,
and then calling acl(..., SETACL, ...).  The new sys_acl_set_fd_type() preserves
that behavior with fd-based operations: it uses fstat() to identify directories,
reads the other ACL half with sys_acl_get_fd_type(), combines the access and
default entries, marks default entries with ACL_DEFAULT, and finally writes the
combined ACL with facl(2).  Deleting a default ACL similarly fetches the access
ACL through the fd and rewrites only that access ACL with facl(2), which removes
the default ACL without re-resolving the path.

Driving the apply off the held fd also closes a symlink-race on the Solaris ACL
apply (the path-based sys_acl_*file re-resolves the path -- the CVE-2026-53799
class, unfixed on Solaris until now).  Added on integration: for a root receiver
a missing held fd on a confined receiver means the leaf was raced to a symlink
(acl_set_file follows it), so refuse the path-based set/delete rather than apply
the ACL to a redirected inode; a plain non-root receiver keeps the path-based
fallback for a legitimately un-pinnable owned leaf (e.g. a 0300 dir), matching
the operator-path op_pin rule.
2026-06-30 08:36:22 +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 893d3f612e acls: route race-safe ACL ops through libacl *_at when available
When configure detects a patched libacl exporting acl_get_file_at /
acl_set_file_at / acl_delete_def_file_at (new HAVE_LIBACL_AT; ACL_1.3), route the
receiver's race-safe ACL get/set/delete through them instead of lib/acl.c's
xacl_* -- held fd via AT_EMPTY_PATH, dirfd+leaf via AT_SYMLINK_NOFOLLOW, reusing
the existing unpack_smb_acl/pack_smb_acl conversion.  libacl's /proc/self/fd
compat makes this race-safe on every Linux kernel.

lib/acl.c stays as the fallback for a stock libacl (macro undefined -> zero change
there); it already closes the same pre-6.13 parent-symlink-race gap via its own
/proc/self/fd compat, so the two paths are equivalent in safety and prefer libacl
only when its newer bindings are present.  -VV reports ACL-libacl-at and keeps
"ACL_at": true.

A stock -lacl lacks these symbols, so HAVE_LIBACL_AT is undefined on real distros
and the build is byte-identical to the lib/acl.c path until libacl ships ACL_1.3;
build against the patched lib via CPPFLAGS/LDFLAGS pointing at its install prefix.
2026-06-15 15:24:42 +10:00
Andrew Tridgell 8fc908ebaf lib/acl: close the pre-6.13 ACL parent-symlink race via /proc/self/fd
On a kernel without the Linux 6.13 *xattrat syscalls, xacl_*_at() returned ENOSYS
so acls.c fell back to the unconfined path-based sys_acl_set_file() -- the
long-standing parent-symlink race for --acls on every pre-6.13 Linux (the
receiver applies a received ACL to a leaf an attacker raced to a symlink ->
arbitrary-ACL LPE; acl-symlink-race only documented it as a residual there).

Add a /proc/self/fd compat to the dirfd dispatchers: when the *xattrat syscall is
absent (runtime ENOSYS or unbuilt), address the leaf as
/proc/self/fd/<dirfd>/<leaf> and use the l*xattr (no-follow-leaf) calls.  The
/proc/self/fd/<dirfd> magic symlink resolves to the pinned parent inode (a raced
parent symlink can't redirect it) and l*xattr does not follow a raced leaf
symlink, so the dirfd+leaf ACL ops are race-safe on every Linux kernel with
procfs -- no libacl dependency and no 6.13 requirement.  xacl_at_available() now
returns true when the syscalls OR the /proc compat are usable, so acls.c takes
the race-safe dirfd path instead of the path-based fallback (now only the BSDs /
a /proc-less namespace).  The held-fd path (fsetxattr) is unchanged.

Verified on ubuntu-2004 (kernel 5.4, HAVE_XATTRAT_SYSCALLS=0): "ACL_at": true and
acl-symlink-race PASSES while asserting (a vacuous pass before); no regression on
a 6.13+ host (native syscalls unchanged) or t_acl.
2026-06-15 15:24:42 +10:00
Andrew Tridgell 144e7902d5 acls: keep --acls functional where the OS lacks a race-safe ACL primitive
When the receiver cannot pin an entry with a held fd and the kernel has no
*xattrat syscalls (pre-6.13 Linux, the BSDs, Solaris, ...), the hardened ACL
path previously skipped the apply with a warning and reported success -- it
silently left the destination ACL stale, so a changed or revoked source ACL
did not propagate yet rsync exited 0.

Per project policy, prefer the documented --acls functionality over refusing it
on platforms that cannot offer the race-safe primitive (Linux 6.13+ takes the
secure xacl_*_at() path, and an operator who needs the guarantee can move
there).  The get / default-ACL-delete / set fallbacks now fall through to the
path-based sys_acl_*file() calls -- the long-standing 3.4.x behaviour -- which
restores correct ACL application at the cost of the parent-symlink race that is
unavoidable on those platforms.

Tests: a new acls-unpinnable test asserts a received ACL updates (and removes a
stale grant from) a no-owner-read (0300) destination directory -- validated on
the path-based fallback via a forced-no-xattrat build and on the xattrat path;
its non-Linux / proto-29 skips are added to the per-platform expect-skip lists.
acl-symlink-race PASSES with a note (rather than skipping) where -VV reports no
race-safe primitive, so its skip set stays kernel-independent -- the same
workflow's RSYNC_EXPECT_SKIPPED is shared by no-xattrat and 6.13+ boxes.
2026-06-15 15:24:42 +10:00
Andrew Tridgell 26783f76fe rsync/acls/xattrs: apply received xattrs and ACLs through the held fd
set_file_attrs() holds an O_RDONLY|O_NOFOLLOW fd (held_fd) for the entry's
regular-file/dir/FIFO inode so metadata is applied to the pinned inode rather
than by re-resolving the path, which a parent-symlink race could redirect.

- xattrs: the set/remove/list of -X xattrs use the f-variant calls on held_fd
  (lib/sysxattrs gains the wrappers); a raced FIFO can't block the open
  (O_NONBLOCK).
- ACLs (real root): get_acl_fdat()/set_acl_fdat() apply the ACL via lib/acl.c's
  fd path (xacl_*_fd), or setxattrat(AT_SYMLINK_NOFOLLOW) on the dirfd+leaf for
  a socket/device, covering both the access and default ACL.  pack_smb_acl()+
  change_sacl_perms() still build the entries, so the bytes written match
  acl_set_file() exactly.  With no safe primitive we skip rather than re-resolve
  the path.  The legacy path-based libacl calls remain only for the cross-tree
  (no held dirfd) and non-Linux cases.
- --fake-super ACL-as-xattr writes/deletes also go through held_fd, closing the
  last path-based metadata write under fake-super.
2026-06-15 15:24:42 +10:00
Andrew TridgellandClaude Opus 4.7 ddd7b59a4f defence-in-depth: bound wire-supplied counts and lengths
Multiple receiver-side fields read from the wire were trusted
without upper-bound checks. A hostile peer could either request
extreme allocations (DoS via --max-alloc) or, on platforms where
read_varint returned a negative value, push ~SIZE_MAX through the
size_t conversion to wrap downstream length checks.

Introduce read_int_bounded(), read_varint_bounded() and
read_varint_size() in io.c so wire-derived integer ranges are
checked at the read site rather than scattered across each
caller, with RERR_PROTOCOL on out-of-range input.

Apply the bounded primitives to:
  - sum->count (checksum count -- previously could overflow
    (size_t)count * xfer_sum_len on 32-bit with raised max-alloc)
  - xattrs: count, name_len, datum_len, plus rel_pos overflow
    detect to stop chain wrapping the num accumulator
  - acls: ida-entry count
  - flist: file mode S_IFMT validation, modtime_nsec range check
  - delete-stat counters in main: per-summand cap so the total
    can't overflow a signed 32-bit accumulator

Reporters include Joshua Rogers (checksum-count overflow finding).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 08:20:48 +10:00
Andrew Tridgell 79ffc5e3c5 acl: fixed ACL ID mapping for non-root
closes issue #618
2026-05-07 06:35:05 +10:00
Carlo Marcelo Arenas Belón 62bb9bba02 acls: correct type/size for orig_umask
Since 05278935 (- Call mkdir_defmode() instead of do_mkdir(). - Define
orig_umask in this file, not options.c. - Made orig_umask a mode_t, not an
int., 2006-02-24), the type for the global was changed, and therefore on
systems where sizeof(mode_t) != sizeof(int), writes or reads to them will
overflow to adjacent bytes.

Change the type to the one used everywhere else and avoid this problem.

While at it, silence again a warning that is being triggered by
Apple's clang 15.
2024-11-14 07:15:14 +11:00
Rose 85c906f964 Silence unused var warning
recv_ida_entries still needs to be called regardless, so we cannot take that out. Let's just quiet the compiler instead.
2024-04-07 09:28:03 +10:00
Wayne Davison 81c5c81381 Mention the filename when unpack_smb_acl() returns an error. 2022-09-11 10:04:26 -07: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 78b5bc6629 Enable --atimes on macOS. 2021-10-02 15:23:30 -07:00
Wayne Davison 11eb67eec9 Some memory allocation improvements
- All the memory-allocation macros now auto-check for failure and exit
   with a failure message that incudes the caller's file and lineno
   info.  This includes strdup().

 - Added the `--max-alloc=SIZE` option to be able to override the memory
   allocator's sanity-check limit.  It defaults to 1G (as before).
   Fixes bugzilla bug 12769.
2020-06-25 20:54:21 -07:00
Wayne Davison e63ff70eae Some indentation fixes. 2020-06-13 19:15:02 -07:00
Wayne Davison 3ba4db7030 Two more spelling fixes and some year updates. 2020-04-16 09:31:02 -07:00
Wayne Davison d29702134a Spelling fixes from a Fossies run done by Jens. 2020-04-15 17:42:23 -07:00
Wayne Davison 3e2e4b5a33 Tweak the copyright year. 2019-03-16 09:15:49 -07:00
Wayne Davison ad17b21889 Silence fall-through warnings. 2019-01-04 15:06:30 -08:00
Wayne Davison 473108ae6e Tweak copyright date. 2018-01-14 19:55:07 -08:00
Wayne Davison 453914e35b Update the copyright year. 2015-08-08 12:47:03 -07:00
Wayne Davison dfa5b49110 Bump the year to 2014. 2014-01-26 09:29:15 -08:00
Wayne Davison bba31ddf12 Avoid ACL and/or xattr lookups on IS_MISSING_FILE() entries.
Fixes bug 10381.
2014-01-19 12:24:01 -08:00
Wayne Davison d34eaa8183 Use 0 (not NULL) for a non-pointer arg. 2013-12-25 14:19:30 -08:00
Wayne Davison 7e1a9c4d79 Update copyright year. 2013-01-19 11:05:53 -08:00
Wayne Davison 582aead623 Expand NO_ENTRY items from fake-super ACLs in get_rsync_acl(). 2011-05-25 08:59:47 -07:00
Wayne Davison 2792a83d58 Don't send user/group names for ACLs with --numeric-ids.
Fixes bug 8020.
2011-03-18 14:59:03 -07:00
Wayne Davison 7766e67321 Allow a failure of EINVAL to mean no ACLs are available.
(If our POSIX types aren't valid, we can't handle the ACLs.)
2011-02-22 08:52:48 -08:00
Wayne Davison 6500e0769a Avoid reading ACL/xattr info on filetypes not being copied.
Make OS X avoid xattr access on device/special files.
Fixes bug 5458.
2011-01-03 11:20:04 -08:00
Wayne Davison e8bb37f567 Better mask handling, including some changes to help solaris. 2009-09-12 09:40:31 -07:00
Wayne Davison ee1c00fea8 Pass "new_mode" to set_acl() and change its return values. 2009-09-12 09:27:07 -07:00
Wayne Davison 1b502f3ec2 Put file descriptor arg at the start of the arg list for consistency. 2009-09-12 09:13:38 -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 5eb8bd4962 Don't try to simplify an ACL that has a mask w/o any named values. 2009-04-09 22:49:24 -07:00
Wayne Davison b3bf9b9df9 Update the copyright year. 2009-01-03 10:57:14 -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 d3d07a5e86 Include 2008 in the copyright years. 2008-03-01 12:01:41 -08:00
Wayne Davison d07edfc895 Added a default to the new switch in str_acl_type(). 2008-02-23 08:14:56 -08:00
Wayne Davison a2c473bb59 Tweaked the ACL type-names returned by str_acl_type()
so that error messages are a little clearer.
2008-02-23 07:33:32 -08:00
Wayne Davison c78cb8f349 Made some user-/group-name pointers "const". 2007-12-29 22:52:42 -08:00
Wayne Davison 3f0211b63a New logging categories added to allow differentiation between
transfer errors, normal errors, and warnings.  New messages are
translated into old FERROR/FINFO categories for older protocols.
2007-11-22 10:05:36 -08:00
Wayne Davison 4b1553e2d4 If the xattr data is bogus in get_rsync_acl(), free the buffer. 2007-11-05 18:15:01 +00:00
Wayne Davison 6be5ac61bd Simplified a SMB_ACL_NEED_SORT conditional because some preprocessors
couldn't handle an #if embedded in a macro.
2007-10-05 02:45:09 +00:00
Wayne Davison f57ab2f718 When running with --fake-super, get/put ACLs from/to an xattr and don't
range-check the incoming values.
2007-09-29 16:06:34 +00:00
Wayne Davison 5b934f5133 Added OS X ACL support, using slightly tweaked sys_acl_*()
functions.
2007-09-28 21:54:07 +00: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 19531e1f74 Got rid of some unneeded externs. 2007-09-23 02:03:20 +00:00
Wayne Davison 8e41b68e8f Tweaking the license text a bit more. 2007-07-10 13:55:49 +00:00
Wayne Davison e434f0ebfe Use the latest F_DIR_*() defines (whose names were tweaked). 2007-07-08 20:53:35 +00:00