git: 4872b48b175c - main - setcred(): Fix 32-bit compatibility copy-in

From: Olivier Certner <olce_at_FreeBSD.org>
Date: Sat, 15 Nov 2025 09:30:20 UTC
The branch main has been updated by olce:

URL: https://cgit.FreeBSD.org/src/commit/?id=4872b48b175cc637ee38f645d68b8207d9335474

commit 4872b48b175cc637ee38f645d68b8207d9335474
Author:     Olivier Certner <olce@FreeBSD.org>
AuthorDate: 2025-11-14 20:20:12 +0000
Commit:     Olivier Certner <olce@FreeBSD.org>
CommitDate: 2025-11-15 09:29:49 +0000

    setcred(): Fix 32-bit compatibility copy-in
    
    For 32-bit processes on 64-bit architectures, a difference of 'int'
    pointers was wrongly used as a number of bytes to copy in a memcpy()
    used to internally construct a 64-bit 'struct setcred' from the 32-bit
    variant, leading to copying only part of the 32-bit structure, and thus
    to requesting credentials with garbage IDs except for the real and
    effective user IDs.
    
    This bug was spotted by jhb@, who produced a slightly more invasive fix
    in D53757 (a switch to using CP() on all fields).  In the interest of
    minimizing the diff for possible inclusion in 15.0, the commit here just
    limits itself to fixing the number of bytes to copy.
    
    Tested successfully on a VM with 32-bit mdo(1) (and in passing also
    tested that the same executable on a kernel without this change exhibits
    the bug in practice, in the form of setcred() failing with EINVAL).
    
    Reported by:    jhb
    Reviewed by:    jhb
    Fixes:          ddb3eb4efe55 ("New setcred() system call and associated MAC hooks")
    MFC after:      3 days
    Sponsored by:   The FreeBSD Foundation
    Differential Revision:  https://reviews.freebsd.org/D53767
---
 sys/kern/kern_prot.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/sys/kern/kern_prot.c b/sys/kern/kern_prot.c
index 06696612f8c4..81099aa7d28d 100644
--- a/sys/kern/kern_prot.c
+++ b/sys/kern/kern_prot.c
@@ -603,8 +603,8 @@ user_setcred(struct thread *td, const u_int flags,
 		if (error != 0)
 			return (error);
 		/* These fields have exactly the same sizes and positions. */
-		memcpy(&wcred, &wcred32, &wcred32.setcred32_copy_end -
-		    &wcred32.setcred32_copy_start);
+		memcpy(&wcred, &wcred32, __rangeof(struct setcred32,
+		    setcred32_copy_start, setcred32_copy_end));
 		/* Remaining fields are pointers and need PTRIN*(). */
 		PTRIN_CP(wcred32, wcred, sc_supp_groups);
 		PTRIN_CP(wcred32, wcred, sc_label);