Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 6 May 2025 22:15:33 GMT
From:      Jessica Clarke <jrtc27@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: 2b04ba6e08b9 - main - rtld-elf: Fix UB for direct exec with no extra rtld arguments
Message-ID:  <202505062215.546MFXkq063035@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch main has been updated by jrtc27:

URL: https://cgit.FreeBSD.org/src/commit/?id=2b04ba6e08b983d8756552286846059507bca7a3

commit 2b04ba6e08b983d8756552286846059507bca7a3
Author:     Jessica Clarke <jrtc27@FreeBSD.org>
AuthorDate: 2025-05-06 22:14:51 +0000
Commit:     Jessica Clarke <jrtc27@FreeBSD.org>
CommitDate: 2025-05-06 22:14:51 +0000

    rtld-elf: Fix UB for direct exec with no extra rtld arguments
    
    If no extra rtld arguments are provided, rtld_argc will be 1 (for
    argv[0] and so we are shifting the entire memory range down by a single
    pointer. However, unlike argv and envp, auxp's entries are two pointers
    in size, not one, and so in this case the source and destination
    overlap, meaning simple assignment is UB (C99 6.5.16.1p3). On many
    architectures this ends up being harmless as the compiler will emit
    double machine word loads and stores, or if it splits them it may still
    schedule them such that it works in this case, but our RISC-V baseline
    does not include such instructions and LLVM ends up picking a schedule
    that copies the second word before the first word, thereby replacing the
    first word with a copy of the second word. This results in direct exec
    mode segfaulting on RISC-V when given no arguments.
    
    Fix this by using a temporary in the source and let the compiler safely
    elide its use.
    
    Reviewed by:    kib
    Fixes:          0fc65b0ab82c ("Make ld-elf.so.1 directly executable.")
    MFC after:      1 week
    Differential Revision:  https://reviews.freebsd.org/D50185
---
 libexec/rtld-elf/rtld.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c
index e4e14edbb5c8..d7ac1e36d70f 100644
--- a/libexec/rtld-elf/rtld.c
+++ b/libexec/rtld-elf/rtld.c
@@ -496,7 +496,7 @@ rtld_trunc_page(uintptr_t x)
 func_ptr_type
 _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
 {
-	Elf_Auxinfo *aux, *auxp, *auxpf, *aux_info[AT_COUNT];
+	Elf_Auxinfo *aux, *auxp, *auxpf, *aux_info[AT_COUNT], auxtmp;
 	Objlist_Entry *entry;
 	Obj_Entry *last_interposer, *obj, *preload_tail;
 	const Elf_Phdr *phdr;
@@ -673,7 +673,12 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
 				 * present
 				 */
 				for (;; auxp++, auxpf++) {
-					*auxp = *auxpf;
+					/*
+					 * NB: Use a temporary since *auxpf and
+					 * *auxp overlap if rtld_argc is 1
+					 */
+					auxtmp = *auxpf;
+					*auxp = auxtmp;
 					if (auxp->a_type == AT_NULL)
 						break;
 				}



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202505062215.546MFXkq063035>