The branch main has been updated by kib:

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

commit 7da378f9de1a042ec0c81ba7ad39a392540d4721
Author:     Fangrui Song <[email protected]>
AuthorDate: 2021-08-15 04:13:33 +0000
Commit:     Konstantin Belousov <[email protected]>
CommitDate: 2021-08-16 10:55:35 +0000

    rtld: Switch to the standard symbol lookup behavior if LD_DYNAMIC_WEAK is 
set
    
    The current lookup prefers a strong definition to a STB_WEAK definition
    (similar to glibc pre-2.2 behavior) which does not conform to the ELF
    specification.
    
    The non-compliant behavior provoked https://reviews.llvm.org/D4418
    which was intended to fix -shared-libasan but introduced
    new problems (and caused some sanitizer tests (e.g.
    test/asan/TestCases/interception_failure_test.cpp) to fail): sanitizer
    interceptors are STB_GLOBAL instead of STB_WEAK, so defining a second
    STB_GLOBAL interceptor can lead to a multiple definition linker error.
    For example, in a -fsanitize={address,memory,...} build, libc functions
    like malloc/free/strtol/... cannot be provided by user object files.
    
    See
    
https://docs.freebsd.org/cgi/getmsg.cgi?fetch=16483939+0+archive/2014/freebsd-current/20140716.freebsd-current
    for discussions.
    
    This patch implements the ELF-compliant behavior when LD_DYNAMIC_WEAK is
    set. STB_WEAK wrestling in symbol lookups in `Search the dynamic linker
    itself` are untouched.
    
    Reviewed by:    kib
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D26352
---
 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 2d262f77aa13..8bc4cfade070 100644
--- a/libexec/rtld-elf/rtld.1
+++ b/libexec/rtld-elf/rtld.1
@@ -28,7 +28,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd June 2, 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;
        }
     }
_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/dev-commits-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to