From 07acd4961afee33ddd778a5fea9991121c8db2e2 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sat, 13 Jun 2026 09:22:47 +0200 Subject: [PATCH] flist: gate FLAG_HLINKED on preserve_hard_links in recv_file_entry MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 3c49c401cd5fc153dd310b56dbb9fcce8c7f2a52) --- flist.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flist.c b/flist.c index b6428f16..4eea6c8d 100644 --- a/flist.c +++ b/flist.c @@ -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