flist: gate FLAG_HLINKED on preserve_hard_links in recv_file_entry

A malicious sender can set XMIT_HLINKED on a file-list entry even when
the receiver was not invoked with -H.  recv_file_entry() only reserves
the (inc_recurse+1) hard-link extras slots when preserve_hard_links is
set (the gate at create_object), but it set FLAG_HLINKED on the struct
unconditionally from the peer's xflags.  HLINK_BUMP() then offsets
F_SUM() and F_RDEV_P() past the start of the pool_alloc()'d region,
and the subsequent read_buf(f, F_SUM(file), flist_csum_len) writes 16
attacker-controlled checksum bytes 8 bytes below the allocation — into
the adjacent file_struct in the same pool extent.

Vanilla ASAN does not see this because lib/pool_alloc.c bumps inside a
single 32 KiB malloc; it surfaces as use-after-poison once the pool is
instrumented with ASAN_POISON_MEMORY_REGION/ASAN_UNPOISON_MEMORY_REGION.

Mirror the gating already present at the extra_len computation and at
the F_HL_GNUM/F_HL_PREV write site: only set FLAG_HLINKED when
preserve_hard_links is enabled.  This also closes the symmetric
F_RDEV_P() underflow for device entries and the F_SUM(first)/
F_RDEV_P(first) reads in the first_hlink_ndx copy path.

(cherry picked from commit adfae919876c9f3454ce12a1b7becbed47415ff7)
(cherry picked from commit 3c49c401cd)
This commit is contained in:
Andrew Tridgell committed 2026-06-15 17:16:06 +10:00
1 parent f89bd22473
commit 07acd4961a
1 file changed
+1 -1
+1 -1
View File
@@ -1118,7 +1118,7 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x
memcpy(bp, basename, basename_len);
#ifdef SUPPORT_HARD_LINKS
if (xflags & XMIT_HLINKED
if (preserve_hard_links && xflags & XMIT_HLINKED
#ifndef CAN_HARDLINK_SYMLINK
&& !S_ISLNK(mode)
#endif