Changeset View
Changeset View
Standalone View
Standalone View
libexec/rtld-elf/rtld.c
Show First 20 Lines • Show All 113 Lines • ▼ Show 20 Lines | |||||
static void initlist_add_neededs(Needed_Entry *, Objlist *); | static void initlist_add_neededs(Needed_Entry *, Objlist *); | ||||
static void initlist_add_objects(Obj_Entry *, Obj_Entry *, Objlist *); | static void initlist_add_objects(Obj_Entry *, Obj_Entry *, Objlist *); | ||||
static int initlist_objects_ifunc(Objlist *, bool, int, RtldLockState *); | static int initlist_objects_ifunc(Objlist *, bool, int, RtldLockState *); | ||||
static void linkmap_add(Obj_Entry *); | static void linkmap_add(Obj_Entry *); | ||||
static void linkmap_delete(Obj_Entry *); | static void linkmap_delete(Obj_Entry *); | ||||
static void load_filtees(Obj_Entry *, int flags, RtldLockState *); | static void load_filtees(Obj_Entry *, int flags, RtldLockState *); | ||||
static void unload_filtees(Obj_Entry *, RtldLockState *); | static void unload_filtees(Obj_Entry *, RtldLockState *); | ||||
static int load_needed_objects(Obj_Entry *, int); | static int load_needed_objects(Obj_Entry *, int); | ||||
static int load_preload_objects(void); | static int load_preload_objects(char *, bool); | ||||
static Obj_Entry *load_object(const char *, int fd, const Obj_Entry *, int); | static Obj_Entry *load_object(const char *, int fd, const Obj_Entry *, int); | ||||
static void map_stacks_exec(RtldLockState *); | static void map_stacks_exec(RtldLockState *); | ||||
static int obj_disable_relro(Obj_Entry *); | static int obj_disable_relro(Obj_Entry *); | ||||
static int obj_enforce_relro(Obj_Entry *); | static int obj_enforce_relro(Obj_Entry *); | ||||
static Obj_Entry *obj_from_addr(const void *); | static Obj_Entry *obj_from_addr(const void *); | ||||
static void objlist_call_fini(Objlist *, Obj_Entry *, RtldLockState *); | static void objlist_call_fini(Objlist *, Obj_Entry *, RtldLockState *); | ||||
static void objlist_call_init(Objlist *, RtldLockState *); | static void objlist_call_init(Objlist *, RtldLockState *); | ||||
static void objlist_clear(Objlist *); | static void objlist_clear(Objlist *); | ||||
▲ Show 20 Lines • Show All 74 Lines • ▼ Show 20 Lines | 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 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 | |||||
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 */ | ||||
static char *ld_utrace; /* Use utrace() to log events. */ | static char *ld_utrace; /* Use utrace() to log events. */ | ||||
static struct obj_entry_q obj_list; /* Queue of all loaded objects */ | static struct obj_entry_q obj_list; /* Queue of all loaded objects */ | ||||
static Obj_Entry *obj_main; /* The main program shared object */ | static Obj_Entry *obj_main; /* The main program shared object */ | ||||
static Obj_Entry obj_rtld; /* The dynamic linker shared object */ | static Obj_Entry obj_rtld; /* The dynamic linker shared object */ | ||||
static unsigned int obj_count; /* Number of objects in obj_list */ | static unsigned int obj_count; /* Number of objects in obj_list */ | ||||
static unsigned int obj_loads; /* Number of loads of objects (gen count) */ | static unsigned int obj_loads; /* Number of loads of objects (gen count) */ | ||||
▲ Show 20 Lines • Show All 338 Lines • ▼ Show 20 Lines | if (phdr == obj_rtld.phdr) { | ||||
_rtld_error("No binary"); | _rtld_error("No binary"); | ||||
rtld_die(); | rtld_die(); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
ld_bind_now = getenv(_LD("BIND_NOW")); | ld_bind_now = getenv(_LD("BIND_NOW")); | ||||
/* | /* | ||||
* If the process is tainted, then we un-set the dangerous environment | * If the process is tainted, then we un-set the dangerous environment | ||||
* variables. The process will be marked as tainted until setuid(2) | * variables. The process will be marked as tainted until setuid(2) | ||||
* is called. If any child process calls setuid(2) we do not want any | * is called. If any child process calls setuid(2) we do not want any | ||||
* 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"))) { | |||||
_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; | ||||
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_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; | ||||
▲ Show 20 Lines • Show All 98 Lines • ▼ Show 20 Lines | obj_main->dynsymcount); | ||||
/* Initialize a fake symbol for resolving undefined weak references. */ | /* Initialize a fake symbol for resolving undefined weak references. */ | ||||
sym_zero.st_info = ELF_ST_INFO(STB_GLOBAL, STT_NOTYPE); | sym_zero.st_info = ELF_ST_INFO(STB_GLOBAL, STT_NOTYPE); | ||||
sym_zero.st_shndx = SHN_UNDEF; | sym_zero.st_shndx = SHN_UNDEF; | ||||
sym_zero.st_value = -(uintptr_t)obj_main->relocbase; | sym_zero.st_value = -(uintptr_t)obj_main->relocbase; | ||||
if (!libmap_disable) | if (!libmap_disable) | ||||
libmap_disable = (bool)lm_init(libmap_override); | libmap_disable = (bool)lm_init(libmap_override); | ||||
dbg("loading LD_PRELOAD_FDS libraries"); | |||||
if (load_preload_objects(ld_preload_fds, true) == -1) | |||||
rtld_die(); | |||||
dbg("loading LD_PRELOAD libraries"); | dbg("loading LD_PRELOAD libraries"); | ||||
if (load_preload_objects() == -1) | if (load_preload_objects(ld_preload, false) == -1) | ||||
rtld_die(); | rtld_die(); | ||||
preload_tail = globallist_curr(TAILQ_LAST(&obj_list, obj_entry_q)); | preload_tail = globallist_curr(TAILQ_LAST(&obj_list, obj_entry_q)); | ||||
dbg("loading needed objects"); | dbg("loading needed objects"); | ||||
if (load_needed_objects(obj_main, ld_tracing != NULL ? RTLD_LO_TRACE : | if (load_needed_objects(obj_main, ld_tracing != NULL ? RTLD_LO_TRACE : | ||||
0) == -1) | 0) == -1) | ||||
rtld_die(); | rtld_die(); | ||||
▲ Show 20 Lines • Show All 1,748 Lines • ▼ Show 20 Lines | if (obj->marker) | ||||
continue; | continue; | ||||
if (process_needed(obj, obj->needed, flags) == -1) | if (process_needed(obj, obj->needed, flags) == -1) | ||||
return (-1); | return (-1); | ||||
} | } | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
load_preload_objects(void) | load_preload_objects(char *p, bool isfd) | ||||
{ | { | ||||
char *p = ld_preload; | |||||
Obj_Entry *obj; | Obj_Entry *obj; | ||||
static const char delim[] = " \t:;"; | static const char delim[] = " \t:;"; | ||||
if (p == NULL) | if (p == NULL) | ||||
return 0; | return 0; | ||||
p += strspn(p, delim); | p += strspn(p, delim); | ||||
while (*p != '\0') { | while (*p != '\0') { | ||||
const char *name; | |||||
size_t len = strcspn(p, delim); | size_t len = strcspn(p, delim); | ||||
char savech; | char savech; | ||||
int fd; | |||||
savech = p[len]; | savech = p[len]; | ||||
p[len] = '\0'; | p[len] = '\0'; | ||||
obj = load_object(p, -1, NULL, 0); | |||||
if (isfd) { | |||||
name = NULL; | |||||
fd = parse_integer(p); | |||||
if (fd == -1) | |||||
return -1; | |||||
kib: `return (-1);`
You can stage a pre-patch changing other returns in this function, if you… | |||||
} else { | |||||
name = p; | |||||
fd = -1; | |||||
} | |||||
obj = load_object(name, fd, NULL, 0); | |||||
if (obj == NULL) | if (obj == NULL) | ||||
return -1; /* XXX - cleanup */ | return -1; /* XXX - cleanup */ | ||||
obj->z_interpose = true; | obj->z_interpose = true; | ||||
p[len] = savech; | p[len] = savech; | ||||
p += len; | p += len; | ||||
p += strspn(p, delim); | p += strspn(p, delim); | ||||
} | } | ||||
LD_UTRACE(UTRACE_PRELOAD_FINISHED, NULL, NULL, 0, 0, NULL); | LD_UTRACE(UTRACE_PRELOAD_FINISHED, NULL, NULL, 0, 0, NULL); | ||||
▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | load_object(const char *name, int fd_u, const Obj_Entry *refobj, int flags) | ||||
* using stat(). | * using stat(). | ||||
*/ | */ | ||||
if ((fd = open(path, O_RDONLY | O_CLOEXEC | O_VERIFY)) == -1) { | if ((fd = open(path, O_RDONLY | O_CLOEXEC | O_VERIFY)) == -1) { | ||||
_rtld_error("Cannot open \"%s\"", path); | _rtld_error("Cannot open \"%s\"", path); | ||||
free(path); | free(path); | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
} else { | } else { | ||||
fd = fcntl(fd_u, F_DUPFD_CLOEXEC, 0); | fd = fcntl(fd_u, F_DUPFD_CLOEXEC, 0); | ||||
markjUnsubmitted Not Done Inline ActionsSo here we dup the passed fd to set CLOEXEC. Does the original fd get closed somehow? markj: So here we dup the passed fd to set CLOEXEC. Does the original fd get closed somehow? | |||||
oshogboAuthorUnsubmitted Not Done Inline ActionsNo, we do not. oshogbo: No, we do not.
I did the same think like in case of LD_LIBARARY_PATH_FDS.
We don't close… | |||||
markjUnsubmitted Not Done Inline ActionsI misread the code, I didn't see that fd is closed below. markj: I misread the code, I didn't see that `fd` is closed below. | |||||
if (fd == -1) { | if (fd == -1) { | ||||
_rtld_error("Cannot dup fd"); | _rtld_error("Cannot dup fd"); | ||||
free(path); | free(path); | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
} | } | ||||
if (fstat(fd, &sb) == -1) { | if (fstat(fd, &sb) == -1) { | ||||
_rtld_error("Cannot fstat \"%s\"", printable_path(path)); | _rtld_error("Cannot fstat \"%s\"", printable_path(path)); | ||||
▲ Show 20 Lines • Show All 3,329 Lines • Show Last 20 Lines |
return (-1);
You can stage a pre-patch changing other returns in this function, if you prefer common style. Or better, convert the function to style (mostly indents).