Changeset View
Changeset View
Standalone View
Standalone View
libexec/rtld-elf/rtld.c
Show First 20 Lines • Show All 203 Lines • ▼ Show 20 Lines | |||||
static bool ld_loadfltr; /* Immediate filters processing */ | static bool ld_loadfltr; /* Immediate filters processing */ | ||||
static char *libmap_override; /* Maps to use in addition to libmap.conf */ | static char *libmap_override; /* Maps to use in addition to libmap.conf */ | ||||
static bool trust; /* False for setuid and setgid programs */ | static bool trust; /* False for setuid and setgid programs */ | ||||
static bool dangerous_ld_env; /* True if environment variables have been | static bool dangerous_ld_env; /* True if environment variables have been | ||||
used to affect the libraries loaded */ | used to affect the libraries loaded */ | ||||
bool ld_bind_not; /* Disable PLT update */ | bool ld_bind_not; /* Disable PLT update */ | ||||
static char *ld_bind_now; /* Environment variable for immediate binding */ | static char *ld_bind_now; /* Environment variable for immediate binding */ | ||||
static char *ld_debug; /* Environment variable for debugging */ | 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_path; /* Environment variable for search path */ | ||||
static char *ld_library_dirs; /* Environment variable for library descriptors */ | static char *ld_library_dirs; /* Environment variable for library descriptors */ | ||||
static char *ld_preload; /* Environment variable for libraries to | static char *ld_preload; /* Environment variable for libraries to | ||||
load first */ | load first */ | ||||
static char *ld_preload_fds; /* Environment variable for libraries represented by | static char *ld_preload_fds; /* Environment variable for libraries represented by | ||||
descriptors */ | descriptors */ | ||||
static const char *ld_elf_hints_path; /* Environment variable for alternative hints path */ | static const char *ld_elf_hints_path; /* Environment variable for alternative hints path */ | ||||
static const char *ld_tracing; /* Called from ldd to print libs */ | static const char *ld_tracing; /* Called from ldd to print libs */ | ||||
▲ Show 20 Lines • Show All 358 Lines • ▼ Show 20 Lines | if (phdr == obj_rtld.phdr) { | ||||
* future processes to honor the potentially un-safe variables. | * future processes to honor the potentially un-safe variables. | ||||
*/ | */ | ||||
if (!trust) { | if (!trust) { | ||||
if (unsetenv(_LD("PRELOAD")) || unsetenv(_LD("LIBMAP")) || | if (unsetenv(_LD("PRELOAD")) || unsetenv(_LD("LIBMAP")) || | ||||
unsetenv(_LD("LIBRARY_PATH")) || unsetenv(_LD("LIBRARY_PATH_FDS")) || | unsetenv(_LD("LIBRARY_PATH")) || unsetenv(_LD("LIBRARY_PATH_FDS")) || | ||||
unsetenv(_LD("LIBMAP_DISABLE")) || unsetenv(_LD("BIND_NOT")) || | unsetenv(_LD("LIBMAP_DISABLE")) || unsetenv(_LD("BIND_NOT")) || | ||||
unsetenv(_LD("DEBUG")) || unsetenv(_LD("ELF_HINTS_PATH")) || | unsetenv(_LD("DEBUG")) || unsetenv(_LD("ELF_HINTS_PATH")) || | ||||
unsetenv(_LD("LOADFLTR")) || unsetenv(_LD("LIBRARY_PATH_RPATH")) || | 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_error("environment corrupt; aborting"); | ||||
rtld_die(); | rtld_die(); | ||||
} | } | ||||
} | } | ||||
ld_debug = getenv(_LD("DEBUG")); | ld_debug = getenv(_LD("DEBUG")); | ||||
if (ld_bind_now == NULL) | if (ld_bind_now == NULL) | ||||
ld_bind_not = getenv(_LD("BIND_NOT")) != 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_disable = getenv(_LD("LIBMAP_DISABLE")) != NULL; | ||||
libmap_override = getenv(_LD("LIBMAP")); | libmap_override = getenv(_LD("LIBMAP")); | ||||
ld_library_path = getenv(_LD("LIBRARY_PATH")); | ld_library_path = getenv(_LD("LIBRARY_PATH")); | ||||
ld_library_dirs = getenv(_LD("LIBRARY_PATH_FDS")); | ld_library_dirs = getenv(_LD("LIBRARY_PATH_FDS")); | ||||
ld_preload = getenv(_LD("PRELOAD")); | ld_preload = getenv(_LD("PRELOAD")); | ||||
ld_preload_fds = getenv(_LD("PRELOAD_FDS")); | ld_preload_fds = getenv(_LD("PRELOAD_FDS")); | ||||
ld_elf_hints_path = getenv(_LD("ELF_HINTS_PATH")); | ld_elf_hints_path = getenv(_LD("ELF_HINTS_PATH")); | ||||
ld_loadfltr = getenv(_LD("LOADFLTR")) != NULL; | ld_loadfltr = getenv(_LD("LOADFLTR")) != NULL; | ||||
library_path_rpath = getenv(_LD("LIBRARY_PATH_RPATH")); | library_path_rpath = getenv(_LD("LIBRARY_PATH_RPATH")); | ||||
if (library_path_rpath != NULL) { | if (library_path_rpath != NULL) { | ||||
if (library_path_rpath[0] == 'y' || | if (library_path_rpath[0] == 'y' || | ||||
library_path_rpath[0] == 'Y' || | library_path_rpath[0] == 'Y' || | ||||
library_path_rpath[0] == '1') | library_path_rpath[0] == '1') | ||||
ld_library_path_rpath = true; | ld_library_path_rpath = true; | ||||
else | else | ||||
ld_library_path_rpath = false; | ld_library_path_rpath = false; | ||||
} | } | ||||
dangerous_ld_env = libmap_disable || (libmap_override != NULL) || | dangerous_ld_env = libmap_disable || (libmap_override != NULL) || | ||||
(ld_library_path != NULL) || (ld_preload != 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_tracing = getenv(_LD("TRACE_LOADED_OBJECTS")); | ||||
ld_utrace = getenv(_LD("UTRACE")); | ld_utrace = getenv(_LD("UTRACE")); | ||||
if ((ld_elf_hints_path == NULL) || strlen(ld_elf_hints_path) == 0) | if ((ld_elf_hints_path == NULL) || strlen(ld_elf_hints_path) == 0) | ||||
ld_elf_hints_path = ld_elf_hints_default; | ld_elf_hints_path = ld_elf_hints_default; | ||||
if (ld_debug != NULL && *ld_debug != '\0') | if (ld_debug != NULL && *ld_debug != '\0') | ||||
debug = 1; | debug = 1; | ||||
▲ Show 20 Lines • Show All 3,046 Lines • ▼ Show 20 Lines | defobj = req.defobj_out; | ||||
handle == RTLD_SELF) { /* ... caller included */ | handle == RTLD_SELF) { /* ... caller included */ | ||||
if (handle == RTLD_NEXT) | if (handle == RTLD_NEXT) | ||||
obj = globallist_next(obj); | obj = globallist_next(obj); | ||||
for (; obj != NULL; obj = TAILQ_NEXT(obj, next)) { | for (; obj != NULL; obj = TAILQ_NEXT(obj, next)) { | ||||
if (obj->marker) | if (obj->marker) | ||||
continue; | continue; | ||||
res = symlook_obj(&req, obj); | res = symlook_obj(&req, obj); | ||||
if (res == 0) { | if (res == 0) { | ||||
if (def == NULL || | if (def == NULL || (ld_dynamic_weak && | ||||
ELF_ST_BIND(req.sym_out->st_info) != STB_WEAK) { | ELF_ST_BIND(req.sym_out->st_info) != STB_WEAK)) { | ||||
def = req.sym_out; | def = req.sym_out; | ||||
defobj = req.defobj_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; | break; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* Search the dynamic linker itself, and possibly resolve the | * Search the dynamic linker itself, and possibly resolve the | ||||
* symbol from there. This is how the application links to | * symbol from there. This is how the application links to | ||||
* dynamic linker services such as dlopen. | * 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) { | if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) { | ||||
kib: I suggest you to leave this (and all similar 'search the dynamic linker itself') places intact. | |||||
Done Inline ActionsAnd one more thing. Perhaps, old behavior should not be removed completely. I suggest to add e.g. the variable ${LD}_WEAK_OLD, which if set, restores the old mode of operation where strong overrides weak (feel free to suggest more adequate name). kib: And one more thing. Perhaps, old behavior should not be removed completely. I suggest to add… | |||||
res = symlook_obj(&req, &obj_rtld); | res = symlook_obj(&req, &obj_rtld); | ||||
if (res == 0) { | if (res == 0) { | ||||
def = req.sym_out; | def = req.sym_out; | ||||
defobj = req.defobj_out; | defobj = req.defobj_out; | ||||
} | } | ||||
} | } | ||||
} else { | } else { | ||||
assert(handle == RTLD_DEFAULT); | assert(handle == RTLD_DEFAULT); | ||||
▲ Show 20 Lines • Show All 584 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
SymLook req1; | SymLook req1; | ||||
const Objlist_Entry *elm; | const Objlist_Entry *elm; | ||||
int res; | int res; | ||||
symlook_init_from_req(&req1, req); | symlook_init_from_req(&req1, req); | ||||
/* Search all objects loaded at program start up. */ | /* Search all objects loaded at program start up. */ | ||||
if (req->defobj_out == NULL || | if (req->defobj_out == NULL || (ld_dynamic_weak && | ||||
ELF_ST_BIND(req->sym_out->st_info) == STB_WEAK) { | ELF_ST_BIND(req->sym_out->st_info) == STB_WEAK)) { | ||||
res = symlook_list(&req1, &list_main, donelist); | 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)) { | ELF_ST_BIND(req1.sym_out->st_info) != STB_WEAK)) { | ||||
req->sym_out = req1.sym_out; | req->sym_out = req1.sym_out; | ||||
req->defobj_out = req1.defobj_out; | req->defobj_out = req1.defobj_out; | ||||
assert(req->defobj_out != NULL); | assert(req->defobj_out != NULL); | ||||
} | } | ||||
} | } | ||||
/* Search all DAGs whose roots are RTLD_GLOBAL objects. */ | /* Search all DAGs whose roots are RTLD_GLOBAL objects. */ | ||||
STAILQ_FOREACH(elm, &list_global, link) { | STAILQ_FOREACH(elm, &list_global, link) { | ||||
if (req->defobj_out != NULL && | if (req->defobj_out != NULL && (!ld_dynamic_weak || | ||||
ELF_ST_BIND(req->sym_out->st_info) != STB_WEAK) | ELF_ST_BIND(req->sym_out->st_info) != STB_WEAK)) | ||||
break; | break; | ||||
res = symlook_list(&req1, &elm->obj->dagmembers, donelist); | res = symlook_list(&req1, &elm->obj->dagmembers, donelist); | ||||
if (res == 0 && (req->defobj_out == NULL || | if (res == 0 && (req->defobj_out == NULL || | ||||
ELF_ST_BIND(req1.sym_out->st_info) != STB_WEAK)) { | ELF_ST_BIND(req1.sym_out->st_info) != STB_WEAK)) { | ||||
req->sym_out = req1.sym_out; | req->sym_out = req1.sym_out; | ||||
req->defobj_out = req1.defobj_out; | req->defobj_out = req1.defobj_out; | ||||
assert(req->defobj_out != NULL); | assert(req->defobj_out != NULL); | ||||
} | } | ||||
Show All 32 Lines | assert(req->defobj_out != NULL); | ||||
} | } | ||||
if (refobj->symbolic || req->defobj_out != NULL) | if (refobj->symbolic || req->defobj_out != NULL) | ||||
donelist_check(&donelist, refobj); | donelist_check(&donelist, refobj); | ||||
symlook_global(req, &donelist); | symlook_global(req, &donelist); | ||||
/* Search all dlopened DAGs containing the referencing object. */ | /* Search all dlopened DAGs containing the referencing object. */ | ||||
STAILQ_FOREACH(elm, &refobj->dldags, link) { | STAILQ_FOREACH(elm, &refobj->dldags, link) { | ||||
if (req->sym_out != NULL && | if (req->sym_out != NULL && (!ld_dynamic_weak || | ||||
ELF_ST_BIND(req->sym_out->st_info) != STB_WEAK) | ELF_ST_BIND(req->sym_out->st_info) != STB_WEAK)) | ||||
break; | break; | ||||
res = symlook_list(&req1, &elm->obj->dagmembers, &donelist); | res = symlook_list(&req1, &elm->obj->dagmembers, &donelist); | ||||
if (res == 0 && (req->sym_out == NULL || | if (res == 0 && (req->sym_out == NULL || | ||||
ELF_ST_BIND(req1.sym_out->st_info) != STB_WEAK)) { | ELF_ST_BIND(req1.sym_out->st_info) != STB_WEAK)) { | ||||
req->sym_out = req1.sym_out; | req->sym_out = req1.sym_out; | ||||
req->defobj_out = req1.defobj_out; | req->defobj_out = req1.defobj_out; | ||||
assert(req->defobj_out != NULL); | assert(req->defobj_out != NULL); | ||||
} | } | ||||
Show All 28 Lines | symlook_list(SymLook *req, const Objlist *objlist, DoneList *dlp) | ||||
def = NULL; | def = NULL; | ||||
defobj = NULL; | defobj = NULL; | ||||
STAILQ_FOREACH(elm, objlist, link) { | STAILQ_FOREACH(elm, objlist, link) { | ||||
if (donelist_check(dlp, elm->obj)) | if (donelist_check(dlp, elm->obj)) | ||||
continue; | continue; | ||||
symlook_init_from_req(&req1, req); | symlook_init_from_req(&req1, req); | ||||
if ((res = symlook_obj(&req1, elm->obj)) == 0) { | 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; | def = req1.sym_out; | ||||
defobj = req1.defobj_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; | break; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
if (def != NULL) { | if (def != NULL) { | ||||
req->sym_out = def; | req->sym_out = def; | ||||
req->defobj_out = defobj; | req->defobj_out = defobj; | ||||
return (0); | return (0); | ||||
Show All 18 Lines | symlook_needed(SymLook *req, const Needed_Entry *needed, DoneList *dlp) | ||||
def = NULL; | def = NULL; | ||||
defobj = NULL; | defobj = NULL; | ||||
symlook_init_from_req(&req1, req); | symlook_init_from_req(&req1, req); | ||||
for (n = needed; n != NULL; n = n->next) { | for (n = needed; n != NULL; n = n->next) { | ||||
if (n->obj == NULL || | if (n->obj == NULL || | ||||
(res = symlook_list(&req1, &n->obj->dagmembers, dlp)) != 0) | (res = symlook_list(&req1, &n->obj->dagmembers, dlp)) != 0) | ||||
continue; | 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; | def = req1.sym_out; | ||||
defobj = req1.defobj_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; | break; | ||||
} | } | ||||
} | } | ||||
if (def != NULL) { | if (def != NULL) { | ||||
req->sym_out = def; | req->sym_out = def; | ||||
req->defobj_out = defobj; | req->defobj_out = defobj; | ||||
return (0); | return (0); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 1,503 Lines • Show Last 20 Lines |
I suggest you to leave this (and all similar 'search the dynamic linker itself') places intact. Basically, the biggest issue I am aware of where FreeBSD depends on the strong override of weak, is rtld export. We provide weak symbols like dlopen exported from libc weak, and rtld links to its own definition of the symbols.
If you leave this chunk as is, rtld export should still work. Then I suspect there is nothing else left that depends on this behavior in the base system.