Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 23 Aug 2021 09:21:53 GMT
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: edb509a026bd - stable/13 - rtld: Switch to the standard symbol lookup behavior if LD_DYNAMIC_WEAK is set
Message-ID:  <202108230921.17N9Lr3k067132@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch stable/13 has been updated by kib:

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

commit edb509a026bd9cd2f6a81fd4d5af1a332f96a00d
Author:     Fangrui Song <i@maskray.me>
AuthorDate: 2021-08-15 04:13:33 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2021-08-23 09:20:56 +0000

    rtld: Switch to the standard symbol lookup behavior if LD_DYNAMIC_WEAK is set
    
    (cherry picked from commit 7da378f9de1a042ec0c81ba7ad39a392540d4721)
---
 libexec/rtld-elf/rtld.1 | 20 +++++++++++++++++++-
 libexec/rtld-elf/rtld.c | 40 ++++++++++++++++++++++++----------------
 2 files changed, 43 insertions(+), 17 deletions(-)

diff --git a/libexec/rtld-elf/rtld.1 b/libexec/rtld-elf/rtld.1
index b6572caac811..8bc4cfade070 100644
--- a/libexec/rtld-elf/rtld.1
+++ b/libexec/rtld-elf/rtld.1
@@ -28,7 +28,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd March 24, 2021
+.Dd August 15, 2021
 .Dt RTLD 1
 .Os
 .Sh NAME
@@ -143,6 +143,24 @@ If set,
 .Nm
 will print a table containing all relocations before symbol
 binding and relocation.
+.It Ev LD_DYNAMIC_WEAK
+If set, use the ELF standard-compliant symbol lookup behavior:
+resolve to the first found symbol definition.
+.Pp
+By default,
+.Fx
+provides the non-standard symbol lookup behavior:
+when a weak symbol definition is found, remember the definition and
+keep searching in the remaining shared objects for a non-weak definition.
+If found, the non-weak definition is preferred, otherwise the remembered
+weak definition is returned.
+.Pp
+Symbols exported by dynamic linker itself (see
+.Xr dlfcn 3 )
+are always resolved using
+.Fx
+rules regardless of the presence of the variable.
+This variable is unset for set-user-ID and set-group-ID programs.
 .It Ev LD_LIBMAP
 A library replacement list in the same format as
 .Xr libmap.conf 5 .
diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c
index 23482e07fc5f..61b823aaacf8 100644
--- a/libexec/rtld-elf/rtld.c
+++ b/libexec/rtld-elf/rtld.c
@@ -209,6 +209,8 @@ static bool dangerous_ld_env;	/* True if environment variables have been
 bool ld_bind_not;		/* Disable PLT update */
 static char *ld_bind_now;	/* Environment variable for immediate binding */
 static char *ld_debug;		/* Environment variable for debugging */
+static bool ld_dynamic_weak = true; /* True if non-weak definition overrides
+				       weak definition */
 static char *ld_library_path;	/* Environment variable for search path */
 static char *ld_library_dirs;	/* Environment variable for library descriptors */
 static char *ld_preload;	/* Environment variable for libraries to
@@ -583,7 +585,7 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
 	    unsetenv(_LD("LIBMAP_DISABLE")) || unsetenv(_LD("BIND_NOT")) ||
 	    unsetenv(_LD("DEBUG")) || unsetenv(_LD("ELF_HINTS_PATH")) ||
 	    unsetenv(_LD("LOADFLTR")) || unsetenv(_LD("LIBRARY_PATH_RPATH")) ||
-	    unsetenv(_LD("PRELOAD_FDS"))) {
+	    unsetenv(_LD("PRELOAD_FDS")) || unsetenv(_LD("DYNAMIC_WEAK"))) {
 		_rtld_error("environment corrupt; aborting");
 		rtld_die();
 	}
@@ -591,6 +593,7 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
     ld_debug = getenv(_LD("DEBUG"));
     if (ld_bind_now == NULL)
 	    ld_bind_not = getenv(_LD("BIND_NOT")) != NULL;
+    ld_dynamic_weak = getenv(_LD("DYNAMIC_WEAK")) == NULL;
     libmap_disable = getenv(_LD("LIBMAP_DISABLE")) != NULL;
     libmap_override = getenv(_LD("LIBMAP"));
     ld_library_path = getenv(_LD("LIBRARY_PATH"));
@@ -610,7 +613,7 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
     }
     dangerous_ld_env = libmap_disable || (libmap_override != NULL) ||
 	(ld_library_path != NULL) || (ld_preload != NULL) ||
-	(ld_elf_hints_path != NULL) || ld_loadfltr;
+	(ld_elf_hints_path != NULL) || ld_loadfltr || ld_dynamic_weak;
     ld_tracing = getenv(_LD("TRACE_LOADED_OBJECTS"));
     ld_utrace = getenv(_LD("UTRACE"));
 
@@ -3673,11 +3676,12 @@ do_dlsym(void *handle, const char *name, void *retaddr, const Ver_Entry *ve,
 		    continue;
 		res = symlook_obj(&req, obj);
 		if (res == 0) {
-		    if (def == NULL ||
-		      ELF_ST_BIND(req.sym_out->st_info) != STB_WEAK) {
+		    if (def == NULL || (ld_dynamic_weak &&
+                      ELF_ST_BIND(req.sym_out->st_info) != STB_WEAK)) {
 			def = req.sym_out;
 			defobj = req.defobj_out;
-			if (ELF_ST_BIND(def->st_info) != STB_WEAK)
+			if (!ld_dynamic_weak ||
+			  ELF_ST_BIND(def->st_info) != STB_WEAK)
 			    break;
 		    }
 		}
@@ -3686,6 +3690,8 @@ do_dlsym(void *handle, const char *name, void *retaddr, const Ver_Entry *ve,
 	     * Search the dynamic linker itself, and possibly resolve the
 	     * symbol from there.  This is how the application links to
 	     * dynamic linker services such as dlopen.
+	     * Note that we ignore ld_dynamic_weak == false case,
+	     * always overriding weak symbols by rtld definitions.
 	     */
 	    if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) {
 		res = symlook_obj(&req, &obj_rtld);
@@ -4288,10 +4294,10 @@ symlook_global(SymLook *req, DoneList *donelist)
     symlook_init_from_req(&req1, req);
 
     /* Search all objects loaded at program start up. */
-    if (req->defobj_out == NULL ||
-      ELF_ST_BIND(req->sym_out->st_info) == STB_WEAK) {
+    if (req->defobj_out == NULL || (ld_dynamic_weak &&
+      ELF_ST_BIND(req->sym_out->st_info) == STB_WEAK)) {
 	res = symlook_list(&req1, &list_main, donelist);
-	if (res == 0 && (req->defobj_out == NULL ||
+	if (res == 0 && (!ld_dynamic_weak || req->defobj_out == NULL ||
 	  ELF_ST_BIND(req1.sym_out->st_info) != STB_WEAK)) {
 	    req->sym_out = req1.sym_out;
 	    req->defobj_out = req1.defobj_out;
@@ -4301,8 +4307,8 @@ symlook_global(SymLook *req, DoneList *donelist)
 
     /* Search all DAGs whose roots are RTLD_GLOBAL objects. */
     STAILQ_FOREACH(elm, &list_global, link) {
-	if (req->defobj_out != NULL &&
-	  ELF_ST_BIND(req->sym_out->st_info) != STB_WEAK)
+	if (req->defobj_out != NULL && (!ld_dynamic_weak ||
+          ELF_ST_BIND(req->sym_out->st_info) != STB_WEAK))
 	    break;
 	res = symlook_list(&req1, &elm->obj->dagmembers, donelist);
 	if (res == 0 && (req->defobj_out == NULL ||
@@ -4351,8 +4357,8 @@ symlook_default(SymLook *req, const Obj_Entry *refobj)
 
     /* Search all dlopened DAGs containing the referencing object. */
     STAILQ_FOREACH(elm, &refobj->dldags, link) {
-	if (req->sym_out != NULL &&
-	  ELF_ST_BIND(req->sym_out->st_info) != STB_WEAK)
+	if (req->sym_out != NULL && (!ld_dynamic_weak ||
+          ELF_ST_BIND(req->sym_out->st_info) != STB_WEAK))
 	    break;
 	res = symlook_list(&req1, &elm->obj->dagmembers, &donelist);
 	if (res == 0 && (req->sym_out == NULL ||
@@ -4397,10 +4403,11 @@ symlook_list(SymLook *req, const Objlist *objlist, DoneList *dlp)
 	    continue;
 	symlook_init_from_req(&req1, req);
 	if ((res = symlook_obj(&req1, elm->obj)) == 0) {
-	    if (def == NULL || ELF_ST_BIND(req1.sym_out->st_info) != STB_WEAK) {
+	    if (def == NULL || (ld_dynamic_weak &&
+              ELF_ST_BIND(req1.sym_out->st_info) != STB_WEAK)) {
 		def = req1.sym_out;
 		defobj = req1.defobj_out;
-		if (ELF_ST_BIND(def->st_info) != STB_WEAK)
+		if (!ld_dynamic_weak || ELF_ST_BIND(def->st_info) != STB_WEAK)
 		    break;
 	    }
 	}
@@ -4435,10 +4442,11 @@ symlook_needed(SymLook *req, const Needed_Entry *needed, DoneList *dlp)
 	if (n->obj == NULL ||
 	    (res = symlook_list(&req1, &n->obj->dagmembers, dlp)) != 0)
 	    continue;
-	if (def == NULL || ELF_ST_BIND(req1.sym_out->st_info) != STB_WEAK) {
+	if (def == NULL || (ld_dynamic_weak &&
+          ELF_ST_BIND(req1.sym_out->st_info) != STB_WEAK)) {
 	    def = req1.sym_out;
 	    defobj = req1.defobj_out;
-	    if (ELF_ST_BIND(def->st_info) != STB_WEAK)
+	    if (!ld_dynamic_weak || ELF_ST_BIND(def->st_info) != STB_WEAK)
 		break;
 	}
     }



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