git: c56df6ce71ae - main - rtld: add rtld_{get,set}_var

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Thu, 07 Nov 2024 05:20:36 UTC
The branch main has been updated by kib:

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

commit c56df6ce71ae96f00b088790d3ad2e0ebebdd59a
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2024-10-31 06:01:39 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2024-11-07 05:15:23 +0000

    rtld: add rtld_{get,set}_var
    
    Reviewed by:    brooks (previous version)
    Discussed with: emaste
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D47351
---
 lib/libc/gen/Symbol.map     |  2 ++
 lib/libc/gen/dlfcn.c        | 17 +++++++++++++
 lib/libdl/Symbol.map        |  5 ++++
 libexec/rtld-elf/Symbol.map |  5 ++++
 libexec/rtld-elf/rtld.c     | 62 +++++++++++++++++++++++++++++++++++++++------
 sys/sys/link_elf.h          |  2 ++
 6 files changed, 85 insertions(+), 8 deletions(-)

diff --git a/lib/libc/gen/Symbol.map b/lib/libc/gen/Symbol.map
index 17d114c96677..df950697cf23 100644
--- a/lib/libc/gen/Symbol.map
+++ b/lib/libc/gen/Symbol.map
@@ -456,6 +456,8 @@ FBSD_1.8 {
 	aio_read2;
 	aio_write2;
 	execvpe;
+	rtld_get_var;
+	rtld_set_var;
 };
 
 FBSDprivate_1.0 {
diff --git a/lib/libc/gen/dlfcn.c b/lib/libc/gen/dlfcn.c
index b678df9eef47..b30cb82e5e43 100644
--- a/lib/libc/gen/dlfcn.c
+++ b/lib/libc/gen/dlfcn.c
@@ -35,6 +35,7 @@
 #include <sys/mman.h>
 #include <machine/atomic.h>
 #include <dlfcn.h>
+#include <errno.h>
 #include <link.h>
 #include <stddef.h>
 #include <string.h>
@@ -337,4 +338,20 @@ _rtld_is_dlopened(void *arg __unused)
 	return (0);
 }
 
+#pragma weak rtld_get_var
+const char *
+rtld_get_var(const char *name __unused)
+{
+	_rtld_error(sorry);
+	return (NULL);
+}
+
+#pragma weak rtld_set_var
+int
+rtld_set_var(const char *name __unused, const char *val __unused)
+{
+	_rtld_error(sorry);
+	return (EINVAL);
+}
+
 #endif /* !defined(IN_LIBDL) || defined(PIC) */
diff --git a/lib/libdl/Symbol.map b/lib/libdl/Symbol.map
index 67d26c1f1dfe..dd9a8252e4a3 100644
--- a/lib/libdl/Symbol.map
+++ b/lib/libdl/Symbol.map
@@ -17,3 +17,8 @@ FBSD_1.0 {
 FBSD_1.3 {
 	fdlopen;
 };
+
+FBSD_1.8 {
+	rtld_get_var;
+	rtld_set_var;
+};
diff --git a/libexec/rtld-elf/Symbol.map b/libexec/rtld-elf/Symbol.map
index 0b7ad63f60a7..3cdbb30d04a0 100644
--- a/libexec/rtld-elf/Symbol.map
+++ b/libexec/rtld-elf/Symbol.map
@@ -21,6 +21,11 @@ FBSD_1.3 {
     fdlopen;
 };
 
+FBSD_1.8 {
+    rtld_get_var;
+    rtld_set_var;
+};
+
 FBSDprivate_1.0 {
     _rtld_thread_init;
     _rtld_allocate_tls;
diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c
index 7c61fec44ef7..f1075bc75d5f 100644
--- a/libexec/rtld-elf/rtld.c
+++ b/libexec/rtld-elf/rtld.c
@@ -257,6 +257,8 @@ int _rtld_addr_phdr(const void *, struct dl_phdr_info *) __exported;
 int _rtld_get_stack_prot(void) __exported;
 int _rtld_is_dlopened(void *) __exported;
 void _rtld_error(const char *, ...) __exported;
+const char *rtld_get_var(const char *name) __exported;
+int rtld_set_var(const char *name, const char *val) __exported;
 
 /* Only here to fix -Wmissing-prototypes warnings */
 int __getosreldate(void);
@@ -347,31 +349,35 @@ struct ld_env_var_desc {
 	const char * const n;
 	const char *val;
 	const bool unsecure:1;
+	const bool can_update:1;
+	const bool debug:1;
+	bool owned:1;
 };
 #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(PRELOAD, true),
 	LD_ENV_DESC(LIBMAP, true),
-	LD_ENV_DESC(LIBRARY_PATH, true),
-	LD_ENV_DESC(LIBRARY_PATH_FDS, 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),
+	LD_ENV_DESC(DEBUG, true, .can_update = true, .debug = true),
 	LD_ENV_DESC(ELF_HINTS_PATH, true),
 	LD_ENV_DESC(LOADFLTR, true),
-	LD_ENV_DESC(LIBRARY_PATH_RPATH, true),
+	LD_ENV_DESC(LIBRARY_PATH_RPATH, true, .can_update = true),
 	LD_ENV_DESC(PRELOAD_FDS, true),
-	LD_ENV_DESC(DYNAMIC_WEAK, true),
+	LD_ENV_DESC(DYNAMIC_WEAK, true, .can_update = true),
 	LD_ENV_DESC(TRACE_LOADED_OBJECTS, false),
-	LD_ENV_DESC(UTRACE, false),
-	LD_ENV_DESC(DUMP_REL_PRE, false),
-	LD_ENV_DESC(DUMP_REL_POST, false),
+	LD_ENV_DESC(UTRACE, false, .can_update = true),
+	LD_ENV_DESC(DUMP_REL_PRE, false, .can_update = true),
+	LD_ENV_DESC(DUMP_REL_POST, false, .can_update = true),
 	LD_ENV_DESC(TRACE_LOADED_OBJECTS_PROGNAME, false),
 	LD_ENV_DESC(TRACE_LOADED_OBJECTS_FMT1, false),
 	LD_ENV_DESC(TRACE_LOADED_OBJECTS_FMT2, false),
@@ -6329,6 +6335,46 @@ dump_auxv(Elf_Auxinfo **aux_info)
 	}
 }
 
+const char *
+rtld_get_var(const char *name)
+{
+	const struct ld_env_var_desc *lvd;
+	u_int i;
+
+	for (i = 0; i < nitems(ld_env_vars); i++) {
+		lvd = &ld_env_vars[i];
+		if (strcmp(lvd->n, name) == 0)
+			return (lvd->val);
+	}
+	return (NULL);
+}
+
+int
+rtld_set_var(const char *name, const char *val)
+{
+	struct ld_env_var_desc *lvd;
+	u_int i;
+
+	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->owned)
+			free(__DECONST(char *, lvd->val));
+		if (val != NULL)
+			lvd->val = xstrdup(val);
+		else
+			lvd->val = NULL;
+		lvd->owned = true;
+		if (lvd->debug)
+			debug = lvd->val != NULL && *lvd->val != '\0';
+		return (0);
+	}
+	return (ENOENT);
+}
+
 /*
  * Overrides for libc_pic-provided functions.
  */
diff --git a/sys/sys/link_elf.h b/sys/sys/link_elf.h
index 7b51b3e87d1d..996e1f70a9f1 100644
--- a/sys/sys/link_elf.h
+++ b/sys/sys/link_elf.h
@@ -97,6 +97,8 @@ int dl_iterate_phdr(__dl_iterate_hdr_callback, void *);
 int _rtld_addr_phdr(const void *, struct dl_phdr_info *);
 int _rtld_get_stack_prot(void);
 int _rtld_is_dlopened(void *);
+const char *rtld_get_var(const char *name);
+int rtld_set_var(const char *name, const char *val);
 
 #ifdef __ARM_EABI__
 void * dl_unwind_find_exidx(const void *, int *);