From nobody Thu Mar 26 23:42:27 2026 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4fhgLC39KDz6WKPJ for ; Thu, 26 Mar 2026 23:42:27 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R12" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4fhgLC231Qz3lmJ for ; Thu, 26 Mar 2026 23:42:27 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1774568547; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=2k1K0F1+qtOmLy6HhQvOtZNPBDMLTGeOi6Y7vKVcgvA=; b=xYaj163pyyaL84XmraNV+/QzIfK9qIdAHdWwcHbmbeWemDNHDwTptSGHvQvZLPq8SQhKwH 20D8b+CxRymv4SPJVLsHIK4mwJs69A+9Ny3vlw/ygSC11DX++fE4aHX0CN5sgE9QiT54Qm rtxVTst/cg4GyBHZsLMopXzKMxu5BqgnSvgTdvtwvdkxlBZnWuadWK1eXyI9nuKzUWOf0e 5uT9ynbrktkbCrpDOAOptagRf6xbX5pUIw2dd5AAbP3NCSDV1u8i+UVJZkXsBMaQvEmfon JiUhkYnnjlpYzOTt2/SI5k4FYzMT06aYUjvHRfoeSxhmul98dQagEqITdOhXYA== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1774568547; a=rsa-sha256; cv=none; b=IeQyagAlcftpKJc3z/r+pAjo8WnyuiWSaOmue7C5kTCFVCtlMWofTpomgl7jOFu0PbhDKF NN+/UzjlIRavlW2H/jJm8bR8qV2MEBZQHh8dbq/nXjwMPdJAXwM9g5lByiOYFcbJa4D8GK A1rJhFVpFLCeSabP0Cte8mV0pZ7PwQTSeJ+j8j+HGihwmNQHvD88ZcgpJQIA5jNu96QYTq KRbZC69NW6pzxozyKl44CiDqVOPhG8j68++tIcByOmBstbBcfobLT5Jwj3wI8Xe5S/ohuZ AHjdm5DYX6Ax+iLgj7eL+daSj1oM5NEV1K0l55VfPttp2YtC6HKgFEBXvkugyw== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1774568547; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=2k1K0F1+qtOmLy6HhQvOtZNPBDMLTGeOi6Y7vKVcgvA=; b=lTujFLhFP2PFrjYn3nv2MXG7QHER+FfeofctgGOMWrHXJgCqUrM4DueXTHXXVwd8TmKCCt fh/+sem9eiDTgHjUCqiVrxNTZu+jMQLBxrcCA/NwAB7TUZemIEU4xIOCQblmZpj1JbFKyt s/7/lMj/esl3PVkEclxUYiMmOxxgk1vpA3RI9IXRXUhOG+E79KmAZtTQ0uyqx65EnIyydh AQnw1awsm4EmEgUEhq7MJnn/+Io70snHZCqHsc4tno+Uu3+kSQsTKxPtYPVoOS3UWBmzPs yCt8109dGaTdVkUX1iUrUDHce93Wpvo+K5d/x6SxYuGPwnDbJ6xgOjwRkyuE7Q== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4fhgLC1dGgzNT for ; Thu, 26 Mar 2026 23:42:27 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 40cf1 by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Thu, 26 Mar 2026 23:42:27 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Konstantin Belousov Subject: git: b9f046d941c4 - main - rtld: properly handle update of several vars in rtld_set_var() List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: kib X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: b9f046d941c4dbd0e4fc634827ada6e7cf6a6bcf Auto-Submitted: auto-generated Date: Thu, 26 Mar 2026 23:42:27 +0000 Message-Id: <69c5c463.40cf1.352be003@gitrepo.freebsd.org> The branch main has been updated by kib: URL: https://cgit.FreeBSD.org/src/commit/?id=b9f046d941c4dbd0e4fc634827ada6e7cf6a6bcf commit b9f046d941c4dbd0e4fc634827ada6e7cf6a6bcf Author: Konstantin Belousov AuthorDate: 2026-03-24 01:43:23 +0000 Commit: Konstantin Belousov CommitDate: 2026-03-26 23:41:23 +0000 rtld: properly handle update of several vars in rtld_set_var() Besides setting the value in the array of the values, rtld sometimes needs to recalculate some internal control variable for the change to take effect. Allow the variable description to supply a method called on the update. Lock the function with the bind lock for safe operation. Mark several variables as allowed for update, since the on_update method is provided for them. The list is LD_BIND_NOW, LD_BIND_NOT, LD_LIBMAP_DISABLE, LD_LOADFLTR. Reviewed by: markj Sponsored by: The FreeBSD Foundation MFC after: 1 week Differential revision: https://reviews.freebsd.org/D56055 --- 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 5e15ba996ec8..e0de6d2e2214 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 */ @@ -368,26 +382,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), @@ -516,7 +539,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]; @@ -721,9 +744,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); @@ -733,31 +755,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); @@ -6611,18 +6620,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) @@ -6630,11 +6742,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); } /*