diff options
author | Konstantin Belousov <kib@FreeBSD.org> | 2016-01-20 07:21:33 +0000 |
---|---|---|
committer | Konstantin Belousov <kib@FreeBSD.org> | 2016-01-20 07:21:33 +0000 |
commit | 9fee0541f2815c1ea70ccc13402f3ed6c4ed9fdf (patch) | |
tree | 80a3a7f9f52931a90d1e9533d93f368fdd3ed703 | |
parent | a63987426ff03a08080457524bc453a8d69ec526 (diff) | |
download | src-9fee0541f2815c1ea70ccc13402f3ed6c4ed9fdf.tar.gz src-9fee0541f2815c1ea70ccc13402f3ed6c4ed9fdf.zip |
Do not call callbacks for dl_iterate_phdr(3) with the rtld bind and
phdr locks locked. This allows to call rtld services from the
callback, which is only reasonable for dlopen(path, RTLD_NOLOAD) to
test existence of the library in the image, and for dlsym(). The
later might still be not quite safe, due to the lazy resolution of
filters.
To allow dropping the locks around iteration in dl_iterate_phdr(3), we
insert markers to track current position between relocks. The global
objects list is converted to tailq and all iterators skip markers,
globallist_next() and globallist_curr() helpers are added.
Reported and tested by: davide
Reviewed by: kan
Sponsored by: The FreeBSD Foundation
MFC after: 3 weeks
Notes
Notes:
svn path=/head/; revision=294373
-rw-r--r-- | libexec/rtld-elf/aarch64/reloc.c | 4 | ||||
-rw-r--r-- | libexec/rtld-elf/amd64/reloc.c | 3 | ||||
-rw-r--r-- | libexec/rtld-elf/arm/reloc.c | 4 | ||||
-rw-r--r-- | libexec/rtld-elf/debug.c | 3 | ||||
-rw-r--r-- | libexec/rtld-elf/i386/reloc.c | 3 | ||||
-rw-r--r-- | libexec/rtld-elf/powerpc/reloc.c | 4 | ||||
-rw-r--r-- | libexec/rtld-elf/powerpc64/reloc.c | 4 | ||||
-rw-r--r-- | libexec/rtld-elf/riscv/reloc.c | 4 | ||||
-rw-r--r-- | libexec/rtld-elf/rtld.c | 247 | ||||
-rw-r--r-- | libexec/rtld-elf/rtld.h | 7 | ||||
-rw-r--r-- | libexec/rtld-elf/sparc64/reloc.c | 4 |
11 files changed, 182 insertions, 105 deletions
diff --git a/libexec/rtld-elf/aarch64/reloc.c b/libexec/rtld-elf/aarch64/reloc.c index 7a9ce97e3ce9..de7ffd594821 100644 --- a/libexec/rtld-elf/aarch64/reloc.c +++ b/libexec/rtld-elf/aarch64/reloc.c @@ -99,8 +99,8 @@ do_copy_relocations(Obj_Entry *dstobj) req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info)); req.flags = SYMLOOK_EARLY; - for (srcobj = dstobj->next; srcobj != NULL; - srcobj = srcobj->next) { + for (srcobj = globallist_next(dstobj); srcobj != NULL; + srcobj = globallist_next(srcobj)) { res = symlook_obj(&req, srcobj); if (res == 0) { srcsym = req.sym_out; diff --git a/libexec/rtld-elf/amd64/reloc.c b/libexec/rtld-elf/amd64/reloc.c index 989594469b48..80a3c35d6596 100644 --- a/libexec/rtld-elf/amd64/reloc.c +++ b/libexec/rtld-elf/amd64/reloc.c @@ -85,7 +85,8 @@ do_copy_relocations(Obj_Entry *dstobj) req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info)); req.flags = SYMLOOK_EARLY; - for (srcobj = dstobj->next; srcobj != NULL; srcobj = srcobj->next) { + for (srcobj = globallist_next(dstobj); srcobj != NULL; + srcobj = globallist_next(srcobj)) { res = symlook_obj(&req, srcobj); if (res == 0) { srcsym = req.sym_out; diff --git a/libexec/rtld-elf/arm/reloc.c b/libexec/rtld-elf/arm/reloc.c index 286e493ff87a..5e21ca56cf44 100644 --- a/libexec/rtld-elf/arm/reloc.c +++ b/libexec/rtld-elf/arm/reloc.c @@ -101,8 +101,8 @@ do_copy_relocations(Obj_Entry *dstobj) ELF_R_SYM(rel->r_info)); req.flags = SYMLOOK_EARLY; - for (srcobj = dstobj->next; srcobj != NULL; - srcobj = srcobj->next) { + for (srcobj = globallist_next(dstobj); srcobj != NULL; + srcobj = globallist_next(srcobj)) { res = symlook_obj(&req, srcobj); if (res == 0) { srcsym = req.sym_out; diff --git a/libexec/rtld-elf/debug.c b/libexec/rtld-elf/debug.c index 8f8311c7793b..3c37b7f63e1c 100644 --- a/libexec/rtld-elf/debug.c +++ b/libexec/rtld-elf/debug.c @@ -62,7 +62,8 @@ dump_relocations (Obj_Entry *obj0) { Obj_Entry *obj; - for (obj = obj0; obj != NULL; obj = obj->next) { + for (obj = globallist_curr(obj0); obj != NULL; + obj = globallist_next(obj)) { dump_obj_relocations(obj); } } diff --git a/libexec/rtld-elf/i386/reloc.c b/libexec/rtld-elf/i386/reloc.c index 55b653713242..2d6021c97796 100644 --- a/libexec/rtld-elf/i386/reloc.c +++ b/libexec/rtld-elf/i386/reloc.c @@ -86,7 +86,8 @@ do_copy_relocations(Obj_Entry *dstobj) req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rel->r_info)); req.flags = SYMLOOK_EARLY; - for (srcobj = dstobj->next; srcobj != NULL; srcobj = srcobj->next) { + for (srcobj = globallist_next(dstobj); srcobj != NULL; + srcobj = globallist_next(srcobj)) { res = symlook_obj(&req, srcobj); if (res == 0) { srcsym = req.sym_out; diff --git a/libexec/rtld-elf/powerpc/reloc.c b/libexec/rtld-elf/powerpc/reloc.c index 1fe96764c56f..89a00894ca1d 100644 --- a/libexec/rtld-elf/powerpc/reloc.c +++ b/libexec/rtld-elf/powerpc/reloc.c @@ -94,8 +94,8 @@ do_copy_relocations(Obj_Entry *dstobj) req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info)); req.flags = SYMLOOK_EARLY; - for (srcobj = dstobj->next; srcobj != NULL; - srcobj = srcobj->next) { + for (srcobj = globallist_next(dstobj); srcobj != NULL; + srcobj = globallist_next(srcobj)) { res = symlook_obj(&req, srcobj); if (res == 0) { srcsym = req.sym_out; diff --git a/libexec/rtld-elf/powerpc64/reloc.c b/libexec/rtld-elf/powerpc64/reloc.c index c428d6b2a975..5cef3f8c59c7 100644 --- a/libexec/rtld-elf/powerpc64/reloc.c +++ b/libexec/rtld-elf/powerpc64/reloc.c @@ -90,8 +90,8 @@ do_copy_relocations(Obj_Entry *dstobj) req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info)); req.flags = SYMLOOK_EARLY; - for (srcobj = dstobj->next; srcobj != NULL; - srcobj = srcobj->next) { + for (srcobj = globallist_next(dstobj); srcobj != NULL; + srcobj = globallist_next(srcobj)) { res = symlook_obj(&req, srcobj); if (res == 0) { srcsym = req.sym_out; diff --git a/libexec/rtld-elf/riscv/reloc.c b/libexec/rtld-elf/riscv/reloc.c index c43800a9407d..92c4276df08b 100644 --- a/libexec/rtld-elf/riscv/reloc.c +++ b/libexec/rtld-elf/riscv/reloc.c @@ -120,8 +120,8 @@ do_copy_relocations(Obj_Entry *dstobj) req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info)); req.flags = SYMLOOK_EARLY; - for (srcobj = dstobj->next; srcobj != NULL; - srcobj = srcobj->next) { + for (srcobj = globallist_next(dstobj); srcobj != NULL; + srcobj = globallist_next(srcobj)) { res = symlook_obj(&req, srcobj); if (res == 0) { srcsym = req.sym_out; diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c index 66edc157d393..06690ff22b1e 100644 --- a/libexec/rtld-elf/rtld.c +++ b/libexec/rtld-elf/rtld.c @@ -90,7 +90,7 @@ static void init_dag(Obj_Entry *); static void init_pagesizes(Elf_Auxinfo **aux_info); static void init_rtld(caddr_t, Elf_Auxinfo **); 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 void linkmap_add(Obj_Entry *); static void linkmap_delete(Obj_Entry *); static void load_filtees(Obj_Entry *, int flags, RtldLockState *); @@ -180,12 +180,11 @@ static char *ld_preload; /* Environment variable for libraries to static char *ld_elf_hints_path; /* Environment variable for alternative hints path */ static char *ld_tracing; /* Called from ldd to print libs */ static char *ld_utrace; /* Use utrace() to log events. */ -static Obj_Entry *obj_list; /* Head of linked list of shared objects */ -static Obj_Entry **obj_tail; /* Link field of last object in list */ +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_rtld; /* The dynamic linker shared object */ static unsigned int obj_count; /* Number of objects in obj_list */ -static unsigned int obj_loads; /* Number of objects in obj_list */ +static unsigned int obj_loads; /* Number of loads of objects (gen count) */ static Objlist list_global = /* Objects dlopened with RTLD_GLOBAL */ STAILQ_HEAD_INITIALIZER(list_global); @@ -370,7 +369,7 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp) const char *argv0; Objlist_Entry *entry; Obj_Entry *obj; - Obj_Entry **preload_tail; + Obj_Entry *preload_tail; Obj_Entry *last_interposer; Objlist initlist; RtldLockState lockstate; @@ -569,8 +568,7 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp) linkmap_add(&obj_rtld); /* Link the main program into the list of objects. */ - *obj_tail = obj_main; - obj_tail = &obj_main->next; + TAILQ_INSERT_HEAD(&obj_list, obj_main, next); obj_count++; obj_loads++; @@ -585,7 +583,7 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp) dbg("loading LD_PRELOAD libraries"); if (load_preload_objects() == -1) rtld_die(); - preload_tail = obj_tail; + preload_tail = globallist_curr(TAILQ_LAST(&obj_list, obj_entry_q)); dbg("loading needed objects"); if (load_needed_objects(obj_main, 0) == -1) @@ -593,7 +591,9 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp) /* Make a list of all objects loaded at startup. */ last_interposer = obj_main; - for (obj = obj_list; obj != NULL; obj = obj->next) { + TAILQ_FOREACH(obj, &obj_list, next) { + if (obj->marker) + continue; if (obj->z_interpose && obj != obj_main) { objlist_put_after(&list_main, last_interposer, obj); last_interposer = obj; @@ -651,7 +651,7 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp) * might be the subject for relocations. */ dbg("initializing initial thread local storage"); - allocate_initial_tls(obj_list); + allocate_initial_tls(globallist_curr(TAILQ_FIRST(&obj_list))); dbg("initializing key program variables"); set_program_var("__progname", argv[0] != NULL ? basename(argv[0]) : ""); @@ -660,7 +660,8 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp) /* Make a list of init functions to call. */ objlist_init(&initlist); - initlist_add_objects(obj_list, preload_tail, &initlist); + initlist_add_objects(globallist_curr(TAILQ_FIRST(&obj_list)), + preload_tail, &initlist); r_debug_state(NULL, &obj_main->linkmap); /* say hello to gdb! */ @@ -690,7 +691,9 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp) _r_debug_postinit(&obj_main->linkmap); objlist_clear(&initlist); dbg("loading filtees"); - for (obj = obj_list->next; obj != NULL; obj = obj->next) { + TAILQ_FOREACH(obj, &obj_list, next) { + if (obj->marker) + continue; if (ld_loadfltr || obj->z_loadfltr) load_filtees(obj, 0, &lockstate); } @@ -1410,9 +1413,10 @@ dlcheck(void *handle) { Obj_Entry *obj; - for (obj = obj_list; obj != NULL; obj = obj->next) + TAILQ_FOREACH(obj, &obj_list, next) { if (obj == (Obj_Entry *) handle) break; + } if (obj == NULL || obj->refcount == 0 || obj->dl_refcount == 0) { _rtld_error("Invalid shared object handle %p", handle); @@ -1823,6 +1827,32 @@ init_dag(Obj_Entry *root) root->dag_inited = true; } +Obj_Entry * +globallist_curr(const Obj_Entry *obj) +{ + + for (;;) { + if (obj == NULL) + return (NULL); + if (!obj->marker) + return (__DECONST(Obj_Entry *, obj)); + obj = TAILQ_PREV(obj, obj_entry_q, next); + } +} + +Obj_Entry * +globallist_next(const Obj_Entry *obj) +{ + + for (;;) { + obj = TAILQ_NEXT(obj, next); + if (obj == NULL) + return (NULL); + if (!obj->marker) + return (__DECONST(Obj_Entry *, obj)); + } +} + static void process_z(Obj_Entry *root) { @@ -1905,7 +1935,7 @@ init_rtld(caddr_t mapbase, Elf_Auxinfo **aux_info) } /* Initialize the object list. */ - obj_tail = &obj_list; + TAILQ_INIT(&obj_list); /* Now that non-local variables can be accesses, copy out obj_rtld. */ memcpy(&obj_rtld, &objtmp, sizeof(obj_rtld)); @@ -1986,7 +2016,7 @@ initlist_add_neededs(Needed_Entry *needed, Objlist *list) /* Process the current needed object. */ if (needed->obj != NULL) - initlist_add_objects(needed->obj, &needed->obj->next, list); + initlist_add_objects(needed->obj, globallist_next(needed->obj), list); } /* @@ -1999,16 +2029,18 @@ initlist_add_neededs(Needed_Entry *needed, Objlist *list) * held when this function is called. */ static void -initlist_add_objects(Obj_Entry *obj, Obj_Entry **tail, Objlist *list) +initlist_add_objects(Obj_Entry *obj, Obj_Entry *tail, Objlist *list) { + Obj_Entry *nobj; if (obj->init_scanned || obj->init_done) return; obj->init_scanned = true; /* Recursively process the successor objects. */ - if (&obj->next != tail) - initlist_add_objects(obj->next, tail, list); + nobj = globallist_next(obj); + if (nobj != NULL && nobj != tail) + initlist_add_objects(nobj, tail, list); /* Recursively process the needed objects. */ if (obj->needed != NULL) @@ -2111,7 +2143,10 @@ load_needed_objects(Obj_Entry *first, int flags) { Obj_Entry *obj; - for (obj = first; obj != NULL; obj = obj->next) { + obj = first; + TAILQ_FOREACH_FROM(obj, &obj_list, next) { + if (obj->marker) + continue; if (process_needed(obj, obj->needed, flags) == -1) return (-1); } @@ -2173,7 +2208,9 @@ load_object(const char *name, int fd_u, const Obj_Entry *refobj, int flags) fd = -1; if (name != NULL) { - for (obj = obj_list->next; obj != NULL; obj = obj->next) { + TAILQ_FOREACH(obj, &obj_list, next) { + if (obj->marker) + continue; if (object_match_name(obj, name)) return (obj); } @@ -2218,9 +2255,12 @@ load_object(const char *name, int fd_u, const Obj_Entry *refobj, int flags) free(path); return NULL; } - for (obj = obj_list->next; obj != NULL; obj = obj->next) + TAILQ_FOREACH(obj, &obj_list, next) { + if (obj->marker) + continue; if (obj->ino == sb.st_ino && obj->dev == sb.st_dev) break; + } if (obj != NULL && name != NULL) { object_add_name(obj, name); free(path); @@ -2288,8 +2328,7 @@ do_load_object(int fd, const char *name, char *path, struct stat *sbp, } obj->dlopened = (flags & RTLD_LO_DLOPEN) != 0; - *obj_tail = obj; - obj_tail = &obj->next; + TAILQ_INSERT_TAIL(&obj_list, obj, next); obj_count++; obj_loads++; linkmap_add(obj); /* for GDB & dlinfo() */ @@ -2310,7 +2349,9 @@ obj_from_addr(const void *addr) { Obj_Entry *obj; - for (obj = obj_list; obj != NULL; obj = obj->next) { + TAILQ_FOREACH(obj, &obj_list, next) { + if (obj->marker) + continue; if (addr < (void *) obj->mapbase) continue; if (addr < (void *) (obj->mapbase + obj->mapsize)) @@ -2436,8 +2477,11 @@ objlist_call_init(Objlist *list, RtldLockState *lockstate) * possibly initialized earlier if any of vectors called below * cause the change by using dlopen. */ - for (obj = obj_list; obj != NULL; obj = obj->next) + TAILQ_FOREACH(obj, &obj_list, next) { + if (obj->marker) + continue; obj->init_scanned = false; + } /* * Preserve the current error message since an init function might @@ -2681,7 +2725,11 @@ relocate_objects(Obj_Entry *first, bool bind_now, Obj_Entry *rtldobj, Obj_Entry *obj; int error; - for (error = 0, obj = first; obj != NULL; obj = obj->next) { + error = 0; + obj = first; + TAILQ_FOREACH_FROM(obj, &obj_list, next) { + if (obj->marker) + continue; error = relocate_object(obj, bind_now, rtldobj, flags, lockstate); if (error == -1) @@ -2719,7 +2767,10 @@ resolve_objects_ifunc(Obj_Entry *first, bool bind_now, int flags, { Obj_Entry *obj; - for (obj = first; obj != NULL; obj = obj->next) { + obj = first; + TAILQ_FOREACH_FROM(obj, &obj_list, next) { + if (obj->marker) + continue; if (resolve_object_ifunc(obj, bind_now, flags, lockstate) == -1) return (-1); } @@ -3033,7 +3084,7 @@ static Obj_Entry * dlopen_object(const char *name, int fd, Obj_Entry *refobj, int lo_flags, int mode, RtldLockState *lockstate) { - Obj_Entry **old_obj_tail; + Obj_Entry *old_obj_tail; Obj_Entry *obj; Objlist initlist; RtldLockState mlockstate; @@ -3047,7 +3098,7 @@ dlopen_object(const char *name, int fd, Obj_Entry *refobj, int lo_flags, } GDB_STATE(RT_ADD,NULL); - old_obj_tail = obj_tail; + old_obj_tail = globallist_curr(TAILQ_LAST(&obj_list, obj_entry_q)); obj = NULL; if (name == NULL && fd == -1) { obj = obj_main; @@ -3060,8 +3111,9 @@ dlopen_object(const char *name, int fd, Obj_Entry *refobj, int lo_flags, obj->dl_refcount++; if (mode & RTLD_GLOBAL && objlist_find(&list_global, obj) == NULL) objlist_push_tail(&list_global, obj); - if (*old_obj_tail != NULL) { /* We loaded something new. */ - assert(*old_obj_tail == obj); + if (globallist_next(old_obj_tail) != NULL) { + /* We loaded something new. */ + assert(globallist_next(old_obj_tail) == obj); result = load_needed_objects(obj, lo_flags & (RTLD_LO_DLOPEN | RTLD_LO_EARLY)); init_dag(obj); @@ -3088,7 +3140,7 @@ dlopen_object(const char *name, int fd, Obj_Entry *refobj, int lo_flags, */ } else { /* Make list of init functions to call. */ - initlist_add_objects(obj, &obj->next, &initlist); + initlist_add_objects(obj, globallist_next(obj), &initlist); } /* * Process all no_delete or global objects here, given @@ -3194,8 +3246,10 @@ do_dlsym(void *handle, const char *name, void *retaddr, const Ver_Entry *ve, } else if (handle == RTLD_NEXT || /* Objects after caller's */ handle == RTLD_SELF) { /* ... caller included */ if (handle == RTLD_NEXT) - obj = obj->next; - for (; obj != NULL; obj = obj->next) { + obj = globallist_next(obj); + TAILQ_FOREACH_FROM(obj, &obj_list, next) { + if (obj->marker) + continue; res = symlook_obj(&req, obj); if (res == 0) { if (def == NULL || @@ -3464,31 +3518,43 @@ rtld_fill_dl_phdr_info(const Obj_Entry *obj, struct dl_phdr_info *phdr_info) int dl_iterate_phdr(__dl_iterate_hdr_callback callback, void *param) { - struct dl_phdr_info phdr_info; - const Obj_Entry *obj; - RtldLockState bind_lockstate, phdr_lockstate; - int error; - - wlock_acquire(rtld_phdr_lock, &phdr_lockstate); - rlock_acquire(rtld_bind_lock, &bind_lockstate); - - error = 0; - - for (obj = obj_list; obj != NULL; obj = obj->next) { - rtld_fill_dl_phdr_info(obj, &phdr_info); - if ((error = callback(&phdr_info, sizeof phdr_info, param)) != 0) - break; + struct dl_phdr_info phdr_info; + Obj_Entry *obj, marker; + RtldLockState bind_lockstate, phdr_lockstate; + int error; - } - if (error == 0) { - rtld_fill_dl_phdr_info(&obj_rtld, &phdr_info); - error = callback(&phdr_info, sizeof(phdr_info), param); - } + bzero(&marker, sizeof(marker)); + marker.marker = true; + error = 0; - lock_release(rtld_bind_lock, &bind_lockstate); - lock_release(rtld_phdr_lock, &phdr_lockstate); + wlock_acquire(rtld_phdr_lock, &phdr_lockstate); + rlock_acquire(rtld_bind_lock, &bind_lockstate); + for (obj = globallist_curr(TAILQ_FIRST(&obj_list)); obj != NULL;) { + TAILQ_INSERT_AFTER(&obj_list, obj, &marker, next); + rtld_fill_dl_phdr_info(obj, &phdr_info); + lock_release(rtld_bind_lock, &bind_lockstate); + lock_release(rtld_phdr_lock, &phdr_lockstate); + + error = callback(&phdr_info, sizeof phdr_info, param); + + wlock_acquire(rtld_phdr_lock, &phdr_lockstate); + rlock_acquire(rtld_bind_lock, &bind_lockstate); + obj = globallist_next(&marker); + TAILQ_REMOVE(&obj_list, &marker, next); + if (error != 0) { + lock_release(rtld_bind_lock, &bind_lockstate); + lock_release(rtld_phdr_lock, &phdr_lockstate); + return (error); + } + } - return (error); + if (error == 0) { + rtld_fill_dl_phdr_info(&obj_rtld, &phdr_info); + lock_release(rtld_bind_lock, &bind_lockstate); + lock_release(rtld_phdr_lock, &phdr_lockstate); + error = callback(&phdr_info, sizeof(phdr_info), param); + } + return (error); } static void * @@ -4208,11 +4274,13 @@ trace_loaded_objects(Obj_Entry *obj) list_containers = getenv(_LD("TRACE_LOADED_OBJECTS_ALL")); - for (; obj; obj = obj->next) { + TAILQ_FOREACH_FROM(obj, &obj_list, next) { Needed_Entry *needed; char *name, *path; bool is_lib; + if (obj->marker) + continue; if (list_containers && obj->needed != NULL) rtld_printf("%s:\n", obj->path); for (needed = obj->needed; needed; needed = needed->next) { @@ -4295,34 +4363,30 @@ trace_loaded_objects(Obj_Entry *obj) static void unload_object(Obj_Entry *root) { - Obj_Entry *obj; - Obj_Entry **linkp; + Obj_Entry *obj, *obj1; - assert(root->refcount == 0); + assert(root->refcount == 0); - /* - * Pass over the DAG removing unreferenced objects from - * appropriate lists. - */ - unlink_object(root); - - /* Unmap all objects that are no longer referenced. */ - linkp = &obj_list->next; - while ((obj = *linkp) != NULL) { - if (obj->refcount == 0) { - LD_UTRACE(UTRACE_UNLOAD_OBJECT, obj, obj->mapbase, obj->mapsize, 0, - obj->path); - dbg("unloading \"%s\"", obj->path); - unload_filtees(root); - munmap(obj->mapbase, obj->mapsize); - linkmap_delete(obj); - *linkp = obj->next; - obj_count--; - obj_free(obj); - } else - linkp = &obj->next; - } - obj_tail = linkp; + /* + * Pass over the DAG removing unreferenced objects from + * appropriate lists. + */ + unlink_object(root); + + /* Unmap all objects that are no longer referenced. */ + TAILQ_FOREACH_SAFE(obj, &obj_list, next, obj1) { + if (obj->marker || obj->refcount != 0) + continue; + LD_UTRACE(UTRACE_UNLOAD_OBJECT, obj, obj->mapbase, + obj->mapsize, 0, obj->path); + dbg("unloading \"%s\"", obj->path); + unload_filtees(root); + munmap(obj->mapbase, obj->mapsize); + linkmap_delete(obj); + TAILQ_REMOVE(&obj_list, obj, next); + obj_count--; + obj_free(obj); + } } static void @@ -4455,7 +4519,8 @@ allocate_tls(Obj_Entry *objs, void *oldtcb, size_t tcbsize, size_t tcbalign) dtv[0] = tls_dtv_generation; dtv[1] = tls_max_index; - for (obj = objs; obj; obj = obj->next) { + for (obj = globallist_curr(objs); obj != NULL; + obj = globallist_next(obj)) { if (obj->tlsoffset > 0) { addr = (Elf_Addr)tls + obj->tlsoffset; if (obj->tlsinitsize > 0) @@ -4554,15 +4619,16 @@ allocate_tls(Obj_Entry *objs, void *oldtls, size_t tcbsize, size_t tcbalign) */ free_tls(oldtls, 2*sizeof(Elf_Addr), sizeof(Elf_Addr)); } else { - for (obj = objs; obj; obj = obj->next) { - if (obj->tlsoffset) { + obj = objs; + TAILQ_FOREACH_FROM(obj, &obj_list, next) { + if (obj->marker || obj->tlsoffset == 0) + continue; addr = segbase - obj->tlsoffset; memset((void*) (addr + obj->tlsinitsize), 0, obj->tlssize - obj->tlsinitsize); if (obj->tlsinit) memcpy((void*) addr, obj->tlsinit, obj->tlsinitsize); dtv[obj->tlsindex + 1] = addr; - } } } @@ -4611,7 +4677,9 @@ allocate_module_tls(int index) Obj_Entry* obj; char* p; - for (obj = obj_list; obj; obj = obj->next) { + TAILQ_FOREACH(obj, &obj_list, next) { + if (obj->marker) + continue; if (obj->tlsindex == index) break; } @@ -4690,7 +4758,8 @@ _rtld_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign) RtldLockState lockstate; wlock_acquire(rtld_bind_lock, &lockstate); - ret = allocate_tls(obj_list, oldtls, tcbsize, tcbalign); + ret = allocate_tls(globallist_curr(TAILQ_FIRST(&obj_list)), oldtls, + tcbsize, tcbalign); lock_release(rtld_bind_lock, &lockstate); return (ret); } diff --git a/libexec/rtld-elf/rtld.h b/libexec/rtld-elf/rtld.h index 72a632e912e6..5fbfb271a3bf 100644 --- a/libexec/rtld-elf/rtld.h +++ b/libexec/rtld-elf/rtld.h @@ -139,7 +139,7 @@ typedef struct Struct_Obj_Entry { Elf_Size magic; /* Magic number (sanity check) */ Elf_Size version; /* Version number of struct format */ - struct Struct_Obj_Entry *next; + TAILQ_ENTRY(Struct_Obj_Entry) next; char *path; /* Pathname of underlying file (%) */ char *origin_path; /* Directory path of origin file */ int refcount; @@ -264,6 +264,7 @@ typedef struct Struct_Obj_Entry { bool valid_hash_sysv : 1; /* A valid System V hash hash tag is available */ bool valid_hash_gnu : 1; /* A valid GNU hash tag is available */ bool dlopened : 1; /* dlopen()-ed (vs. load statically) */ + bool marker : 1; /* marker on the global obj list */ struct link_map linkmap; /* For GDB and dlinfo() */ Objlist dldags; /* Object belongs to these dlopened DAGs (%) */ @@ -276,6 +277,8 @@ typedef struct Struct_Obj_Entry { #define RTLD_MAGIC 0xd550b87a #define RTLD_VERSION 1 +TAILQ_HEAD(obj_entry_q, Struct_Obj_Entry); + #define RTLD_STATIC_TLS_EXTRA 128 /* Flags to be passed into symlook_ family of functions. */ @@ -367,6 +370,8 @@ const Elf_Sym *find_symdef(unsigned long, const Obj_Entry *, void init_pltgot(Obj_Entry *); void lockdflt_init(void); void digest_notes(Obj_Entry *, Elf_Addr, Elf_Addr); +Obj_Entry *globallist_curr(const Obj_Entry *obj); +Obj_Entry *globallist_next(const Obj_Entry *obj); void obj_free(Obj_Entry *); Obj_Entry *obj_new(void); void _rtld_bind_start(void); diff --git a/libexec/rtld-elf/sparc64/reloc.c b/libexec/rtld-elf/sparc64/reloc.c index 738a847d1d08..242fb8e4d948 100644 --- a/libexec/rtld-elf/sparc64/reloc.c +++ b/libexec/rtld-elf/sparc64/reloc.c @@ -266,8 +266,8 @@ do_copy_relocations(Obj_Entry *dstobj) ELF_R_SYM(rela->r_info)); req.flags = SYMLOOK_EARLY; - for (srcobj = dstobj->next; srcobj != NULL; - srcobj = srcobj->next) { + for (srcobj = globallist_next(dstobj); srcobj != NULL; + srcobj = globallist_next(srcobj)) { res = symlook_obj(&req, srcobj); if (res == 0) { srcsym = req.sym_out; |