Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 02 Apr 2026 02:17:06 +0000
From:      Konstantin Belousov <kib@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org
Subject:   git: 1e4debcf698f - stable/15 - rtld: properly handle update of several vars in rtld_set_var()
Message-ID:  <69cdd1a2.3413a.6f854c4@gitrepo.freebsd.org>

index | next in thread | raw e-mail

The branch stable/15 has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=1e4debcf698f364fe857f7cbda53272e4fafa161

commit 1e4debcf698f364fe857f7cbda53272e4fafa161
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2026-03-24 01:43:23 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2026-04-02 02:13:50 +0000

    rtld: properly handle update of several vars in rtld_set_var()
    
    (cherry picked from commit b9f046d941c4dbd0e4fc634827ada6e7cf6a6bcf)
---
 libexec/rtld-elf/rtld.c | 188 ++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 152 insertions(+), 36 deletions(-)

diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c
index 8ac897508870..0cdb09f10121 100644
--- a/libexec/rtld-elf/rtld.c
+++ b/libexec/rtld-elf/rtld.c
@@ -187,6 +187,10 @@ static char *origin_subst_one(Obj_Entry *, char *, const char *, const char *,
 static char *origin_subst(Obj_Entry *, const char *);
 static bool obj_resolve_origin(Obj_Entry *obj);
 static void preinit_main(void);
+static void rtld_recalc_bind_not(const char *);
+static void rtld_recalc_dangerous_ld_env(void);
+static void rtld_recalc_debug(const char *);
+static void rtld_recalc_path_rpath(const char *);
 static int rtld_verify_versions(const Objlist *);
 static int rtld_verify_object_versions(Obj_Entry *);
 static void object_add_name(Obj_Entry *, const char *);
@@ -198,6 +202,17 @@ static uint32_t gnu_hash(const char *);
 static bool matched_symbol(SymLook *, const Obj_Entry *, Sym_Match_Result *,
     const unsigned long);
 
+struct ld_env_var_desc;
+static void rtld_set_var_bind_not(struct ld_env_var_desc *lvd);
+static void rtld_set_var_bind_now(struct ld_env_var_desc *lvd);
+static void rtld_set_var_debug(struct ld_env_var_desc *lvd);
+static void rtld_set_var_dynamic_weak(struct ld_env_var_desc *lvd);
+static void rtld_set_var_libmap_disable(struct ld_env_var_desc *lvd);
+static void rtld_set_var_library_path(struct ld_env_var_desc *lvd);
+static void rtld_set_var_library_path_fds(struct ld_env_var_desc *lvd);
+static void rtld_set_var_library_path_rpath(struct ld_env_var_desc *lvd);
+static void rtld_set_var_loadfltr(struct ld_env_var_desc *lvd);
+
 void r_debug_state(struct r_debug *, struct link_map *) __noinline __exported;
 void _r_debug_postinit(struct link_map *) __noinline __exported;
 
@@ -215,7 +230,6 @@ static bool dangerous_ld_env;	    /* True if environment variables have been
 				       used to affect the libraries loaded */
 bool ld_bind_not;		    /* Disable PLT update */
 static const char *ld_bind_now; /* Environment variable for immediate binding */
-static const char *ld_debug;	/* Environment variable for debugging */
 static bool ld_dynamic_weak = true; /* True if non-weak definition overrides
 				       weak definition */
 static const char *ld_library_path; /* Environment variable for search path */
@@ -367,26 +381,35 @@ struct ld_env_var_desc {
 	const char *val;
 	const bool unsecure : 1;
 	const bool can_update : 1;
-	const bool debug : 1;
 	bool owned : 1;
+	void (*const on_update)(struct ld_env_var_desc *);
 };
 #define LD_ENV_DESC(var, unsec, ...) \
 	[LD_##var] = { .n = #var, .unsecure = unsec, __VA_ARGS__ }
 
 static struct ld_env_var_desc ld_env_vars[] = {
-	LD_ENV_DESC(BIND_NOW, false),
+	LD_ENV_DESC(BIND_NOW, false, .can_update = true,
+	    .on_update = rtld_set_var_bind_now),
 	LD_ENV_DESC(PRELOAD, true),
 	LD_ENV_DESC(LIBMAP, true),
-	LD_ENV_DESC(LIBRARY_PATH, true, .can_update = true),
-	LD_ENV_DESC(LIBRARY_PATH_FDS, true, .can_update = true),
-	LD_ENV_DESC(LIBMAP_DISABLE, true),
-	LD_ENV_DESC(BIND_NOT, true),
-	LD_ENV_DESC(DEBUG, true, .can_update = true, .debug = true),
+	LD_ENV_DESC(LIBRARY_PATH, true, .can_update = true,
+	    .on_update = rtld_set_var_library_path),
+	LD_ENV_DESC(LIBRARY_PATH_FDS, true, .can_update = true,
+	    .on_update = rtld_set_var_library_path_fds),
+	LD_ENV_DESC(LIBMAP_DISABLE, true, .can_update = true,
+	    .on_update = rtld_set_var_libmap_disable),
+	LD_ENV_DESC(BIND_NOT, true, .can_update = true,
+	    .on_update = rtld_set_var_bind_not),
+	LD_ENV_DESC(DEBUG, true, .can_update = true,
+	    .on_update = rtld_set_var_debug),
 	LD_ENV_DESC(ELF_HINTS_PATH, true),
-	LD_ENV_DESC(LOADFLTR, true),
-	LD_ENV_DESC(LIBRARY_PATH_RPATH, true, .can_update = true),
+	LD_ENV_DESC(LOADFLTR, true, .can_update = true,
+	    .on_update = rtld_set_var_loadfltr),
+	LD_ENV_DESC(LIBRARY_PATH_RPATH, true, .can_update = true,
+	    .on_update = rtld_set_var_library_path_rpath),
 	LD_ENV_DESC(PRELOAD_FDS, true),
-	LD_ENV_DESC(DYNAMIC_WEAK, true, .can_update = true),
+	LD_ENV_DESC(DYNAMIC_WEAK, true, .can_update = true,
+	    .on_update = rtld_set_var_dynamic_weak),
 	LD_ENV_DESC(TRACE_LOADED_OBJECTS, false),
 	LD_ENV_DESC(UTRACE, false, .can_update = true),
 	LD_ENV_DESC(DUMP_REL_PRE, false, .can_update = true),
@@ -515,7 +538,7 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
 	struct stat st;
 	Elf_Addr *argcp;
 	char **argv, **env, **envp, *kexecpath;
-	const char *argv0, *binpath, *library_path_rpath, *static_tls_extra;
+	const char *argv0, *binpath, *static_tls_extra;
 	struct ld_env_var_desc *lvd;
 	caddr_t imgentry;
 	char buf[MAXPATHLEN];
@@ -720,9 +743,8 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
 		}
 	}
 
-	ld_debug = ld_get_env_var(LD_DEBUG);
-	if (ld_bind_now == NULL)
-		ld_bind_not = ld_get_env_var(LD_BIND_NOT) != NULL;
+	rtld_recalc_debug(ld_get_env_var(LD_DEBUG));
+	rtld_recalc_bind_not(ld_get_env_var(LD_BIND_NOT));
 	ld_dynamic_weak = ld_get_env_var(LD_DYNAMIC_WEAK) == NULL;
 	libmap_disable = ld_get_env_var(LD_LIBMAP_DISABLE) != NULL;
 	libmap_override = ld_get_env_var(LD_LIBMAP);
@@ -732,31 +754,18 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
 	ld_preload_fds = ld_get_env_var(LD_PRELOAD_FDS);
 	ld_elf_hints_path = ld_get_env_var(LD_ELF_HINTS_PATH);
 	ld_loadfltr = ld_get_env_var(LD_LOADFLTR) != NULL;
-	library_path_rpath = ld_get_env_var(LD_LIBRARY_PATH_RPATH);
-	if (library_path_rpath != NULL) {
-		if (library_path_rpath[0] == 'y' ||
-		    library_path_rpath[0] == 'Y' ||
-		    library_path_rpath[0] == '1')
-			ld_library_path_rpath = true;
-		else
-			ld_library_path_rpath = false;
-	}
+	rtld_recalc_path_rpath(ld_get_env_var(LD_LIBRARY_PATH_RPATH));
 	static_tls_extra = ld_get_env_var(LD_STATIC_TLS_EXTRA);
 	if (static_tls_extra != NULL && static_tls_extra[0] != '\0') {
 		sz = parse_integer(static_tls_extra);
 		if (sz >= RTLD_STATIC_TLS_EXTRA && sz <= SIZE_T_MAX)
 			ld_static_tls_extra = sz;
 	}
-	dangerous_ld_env = libmap_disable || libmap_override != NULL ||
-	    ld_library_path != NULL || ld_preload != NULL ||
-	    ld_elf_hints_path != NULL || ld_loadfltr || !ld_dynamic_weak ||
-	    static_tls_extra != NULL;
+	rtld_recalc_dangerous_ld_env();
 	ld_tracing = ld_get_env_var(LD_TRACE_LOADED_OBJECTS);
 	ld_utrace = ld_get_env_var(LD_UTRACE);
 
 	set_ld_elf_hints_path();
-	if (ld_debug != NULL && *ld_debug != '\0')
-		debug = 1;
 	dbg("%s is initialized, base address = %p", __progname,
 	    (caddr_t)aux_info[AT_BASE]->a_un.a_ptr);
 	dbg("RTLD dynamic = %p", obj_rtld.dynamic);
@@ -6615,18 +6624,121 @@ rtld_get_var(const char *name)
 	return (NULL);
 }
 
+static void
+rtld_recalc_dangerous_ld_env(void)
+{
+	/*
+	 * Never reset dangerous_ld_env back to false if rtld was ever
+	 * contaminated with it set to true.
+	 */
+	dangerous_ld_env |= libmap_disable || libmap_override != NULL ||
+	    ld_library_path != NULL || ld_preload != NULL ||
+	    ld_elf_hints_path != NULL || ld_loadfltr || !ld_dynamic_weak ||
+	    ld_get_env_var(LD_STATIC_TLS_EXTRA) != NULL;
+}
+
+static void
+rtld_recalc_debug(const char *ld_debug)
+{
+	if (ld_debug != NULL && *ld_debug != '\0')
+		debug = 1;
+}
+
+static void
+rtld_set_var_debug(struct ld_env_var_desc *lvd)
+{
+	rtld_recalc_debug(lvd->val);
+}
+
+static void
+rtld_set_var_library_path(struct ld_env_var_desc *lvd)
+{
+	ld_library_path = lvd->val;
+}
+
+static void
+rtld_set_var_library_path_fds(struct ld_env_var_desc *lvd)
+{
+	ld_library_dirs = lvd->val;
+}
+
+static void
+rtld_recalc_path_rpath(const char *library_path_rpath)
+{
+	if (library_path_rpath != NULL) {
+		if (library_path_rpath[0] == 'y' ||
+		    library_path_rpath[0] == 'Y' ||
+		    library_path_rpath[0] == '1')
+			ld_library_path_rpath = true;
+		else
+			ld_library_path_rpath = false;
+	} else {
+		ld_library_path_rpath = false;
+	}
+}
+
+static void
+rtld_set_var_library_path_rpath(struct ld_env_var_desc *lvd)
+{
+	rtld_recalc_path_rpath(lvd->val);
+}
+
+static void
+rtld_recalc_bind_not(const char *bind_not_val)
+{
+	if (ld_bind_now == NULL)
+		ld_bind_not = bind_not_val != NULL;
+}
+
+static void
+rtld_set_var_bind_now(struct ld_env_var_desc *lvd)
+{
+	ld_bind_now = lvd->val;
+	rtld_recalc_bind_not(ld_get_env_var(LD_BIND_NOT));
+}
+
+static void
+rtld_set_var_bind_not(struct ld_env_var_desc *lvd)
+{
+	rtld_recalc_bind_not(lvd->val);
+}
+
+static void
+rtld_set_var_dynamic_weak(struct ld_env_var_desc *lvd)
+{
+	ld_dynamic_weak = lvd->val == NULL;
+}
+
+static void
+rtld_set_var_loadfltr(struct ld_env_var_desc *lvd)
+{
+	ld_loadfltr = lvd->val != NULL;
+}
+
+static void
+rtld_set_var_libmap_disable(struct ld_env_var_desc *lvd)
+{
+	libmap_disable = lvd->val != NULL;
+}
+
 int
 rtld_set_var(const char *name, const char *val)
 {
+	RtldLockState lockstate;
 	struct ld_env_var_desc *lvd;
 	u_int i;
+	int error;
 
+	error = ENOENT;
+	wlock_acquire(rtld_bind_lock, &lockstate);
 	for (i = 0; i < nitems(ld_env_vars); i++) {
 		lvd = &ld_env_vars[i];
 		if (strcmp(lvd->n, name) != 0)
 			continue;
-		if (!lvd->can_update || (lvd->unsecure && !trust))
-			return (EPERM);
+		if (!lvd->can_update || (lvd->unsecure && !trust)) {
+			error = EPERM;
+			break;
+		}
 		if (lvd->owned)
 			free(__DECONST(char *, lvd->val));
 		if (val != NULL)
@@ -6634,11 +6746,15 @@ rtld_set_var(const char *name, const char *val)
 		else
 			lvd->val = NULL;
 		lvd->owned = true;
-		if (lvd->debug)
-			debug = lvd->val != NULL && *lvd->val != '\0';
-		return (0);
+		if (lvd->on_update != NULL)
+			lvd->on_update(lvd);
+		error = 0;
+		break;
 	}
-	return (ENOENT);
+	if (error == 0)
+		rtld_recalc_dangerous_ld_env();
+	lock_release(rtld_bind_lock, &lockstate);
+	return (error);
 }
 
 /*


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?69cdd1a2.3413a.6f854c4>