git: 8e8ae9ac48cc - stable/14 - rtld-elf: Fix executable's TLS module index for direct exec
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Mon, 15 Dec 2025 17:00:26 UTC
The branch stable/14 has been updated by jrtc27:
URL: https://cgit.FreeBSD.org/src/commit/?id=8e8ae9ac48cc59615dd83d2b5fe1368036ff8808
commit 8e8ae9ac48cc59615dd83d2b5fe1368036ff8808
Author: Jessica Clarke <jrtc27@FreeBSD.org>
AuthorDate: 2025-05-06 22:14:51 +0000
Commit: Jessica Clarke <jrtc27@FreeBSD.org>
CommitDate: 2025-12-15 16:58:44 +0000
rtld-elf: Fix executable's TLS module index for direct exec
For direct exec mode we reuse map_object, but tls_max_index is
initialised to 1. As a result, the executable ends up being assigned
module 2 (and the generation is pointlessly incremented, unlike in
digest_phdr for the normal case). For most architectures this is
harmless, since TLS linker relaxation will optimise General Dynamic
accesses to Initial Exec or Local Exec for executables, but on RISC-V
this relaxation does not exist, yet the linker will initialise the
tls_index in the GOT with module 1, and at run time the call to
__tls_get_addr will fail with:
ld-elf.so.1: Can't find module with TLS index 1
Fix this by making map_object use 1 for obj->tlsindex when it's loading
the main executable, and don't bother to increment tls_dtv_generation
either, matching digest_phdr (though that one is harmless).
(Note this also applies to MIPS on stable/13)
Reviewed by: kib
Fixes: 0fc65b0ab82c ("Make ld-elf.so.1 directly executable.")
MFC after: 1 week
Differential Revision: https://reviews.freebsd.org/D50186
(cherry picked from commit a08d92def20a41243d4afc97cf4a2124be5386b9)
---
libexec/rtld-elf/map_object.c | 10 +++++++---
libexec/rtld-elf/rtld.c | 4 ++--
libexec/rtld-elf/rtld.h | 2 +-
3 files changed, 10 insertions(+), 6 deletions(-)
diff --git a/libexec/rtld-elf/map_object.c b/libexec/rtld-elf/map_object.c
index 06be8c02137e..d8583cb67e5a 100644
--- a/libexec/rtld-elf/map_object.c
+++ b/libexec/rtld-elf/map_object.c
@@ -60,7 +60,7 @@ phdr_in_zero_page(const Elf_Ehdr *hdr)
* for the shared object. Returns NULL on failure.
*/
Obj_Entry *
-map_object(int fd, const char *path, const struct stat *sb)
+map_object(int fd, const char *path, const struct stat *sb, bool ismain)
{
Obj_Entry *obj;
Elf_Ehdr *hdr;
@@ -314,8 +314,12 @@ map_object(int fd, const char *path, const struct stat *sb)
if (phinterp != NULL)
obj->interp = (const char *)(obj->relocbase + phinterp->p_vaddr);
if (phtls != NULL) {
- tls_dtv_generation++;
- obj->tlsindex = ++tls_max_index;
+ if (ismain)
+ obj->tlsindex = 1;
+ else {
+ tls_dtv_generation++;
+ obj->tlsindex = ++tls_max_index;
+ }
obj->tlssize = phtls->p_memsz;
obj->tlsalign = phtls->p_align;
obj->tlspoffset = phtls->p_offset;
diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c
index 1a5cb0a6fce9..a7fdc153eca8 100644
--- a/libexec/rtld-elf/rtld.c
+++ b/libexec/rtld-elf/rtld.c
@@ -765,7 +765,7 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
*/
if (fd != -1) { /* Load the main program. */
dbg("loading main program");
- obj_main = map_object(fd, argv0, NULL);
+ obj_main = map_object(fd, argv0, NULL, true);
close(fd);
if (obj_main == NULL)
rtld_die();
@@ -2897,7 +2897,7 @@ do_load_object(int fd, const char *name, char *path, struct stat *sbp,
}
dbg("loading \"%s\"", printable_path(path));
- obj = map_object(fd, printable_path(path), sbp);
+ obj = map_object(fd, printable_path(path), sbp, false);
if (obj == NULL)
return (NULL);
diff --git a/libexec/rtld-elf/rtld.h b/libexec/rtld-elf/rtld.h
index 527ecf9d84e7..b51bbb427a79 100644
--- a/libexec/rtld-elf/rtld.h
+++ b/libexec/rtld-elf/rtld.h
@@ -390,7 +390,7 @@ enum {
void _rtld_error(const char *, ...) __printflike(1, 2) __exported;
void rtld_die(void) __dead2;
const char *rtld_strerror(int);
-Obj_Entry *map_object(int, const char *, const struct stat *);
+Obj_Entry *map_object(int, const char *, const struct stat *, bool);
void *xcalloc(size_t, size_t);
void *xmalloc(size_t);
char *xstrdup(const char *);