From 5fd885b07b45050297993233267a0f2fa1f20f07 Mon Sep 17 00:00:00 2001 From: Konstantin Belousov Date: Tue, 19 Sep 2006 12:47:13 +0000 Subject: Fix the buggy rev. 1.117. dagmembers are only initialized for dlopen'ed dso that are actually loading. If dso a.so depends on b.so, then dlsym with handle from dlopen("b.so") will fail unconditionally. Correct implementation shall use the Obj_Entry.needed list to walk dependencies DAG. Test provided by: jkim Tested (prev. version) by: jkim, Nicolas Blais , h.blanke at chello nl Pointy hat to: kib Approved by: kan (mentor) --- libexec/rtld-elf/rtld.c | 68 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 63 insertions(+), 5 deletions(-) (limited to 'libexec') diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c index 61fbbf6633d1..3059eaeefe70 100644 --- a/libexec/rtld-elf/rtld.c +++ b/libexec/rtld-elf/rtld.c @@ -125,6 +125,9 @@ static const Elf_Sym *symlook_default(const char *, unsigned long, const Obj_Entry *, const Obj_Entry **, const Ver_Entry *, int); static const Elf_Sym *symlook_list(const char *, unsigned long, const Objlist *, const Obj_Entry **, const Ver_Entry *, int flags, DoneList *); +static const Elf_Sym *symlook_needed(const char *, unsigned long, + const Needed_Entry *, const Obj_Entry **, const Ver_Entry *, + int flags, DoneList *dlp); static void trace_loaded_objects(Obj_Entry *obj); static void unlink_object(Obj_Entry *); static void unload_object(Obj_Entry *); @@ -1852,17 +1855,21 @@ do_dlsym(void *handle, const char *name, void *retaddr, const Ver_Entry *ve, } DoneList donelist; - const Objlist *srch_list; donelist_init(&donelist); if (obj->mainprog) { /* Search main program and all libraries loaded by it. */ - srch_list = &list_main; + def = symlook_list(name, hash, &list_main, &defobj, ve, flags, + &donelist); } else { + Needed_Entry fake; + /* Search the whole DAG rooted at the given object. */ - srch_list = &(obj->dagmembers); + fake.next = NULL; + fake.obj = (Obj_Entry *)obj; + fake.name = 0; + def = symlook_needed(name, hash, &fake, &defobj, ve, flags, + &donelist); } - def = symlook_list(name, hash, srch_list, &defobj, ve, flags, - &donelist); } if (def != NULL) { @@ -2361,6 +2368,57 @@ symlook_list(const char *name, unsigned long hash, const Objlist *objlist, return def; } +/* + * Search the symbol table of a shared object and all objects needed + * by it for a symbol of the given name. Search order is + * breadth-first. Returns a pointer to the symbol, or NULL if no + * definition was found. + */ +static const Elf_Sym * +symlook_needed(const char *name, unsigned long hash, const Needed_Entry *needed, + const Obj_Entry **defobj_out, const Ver_Entry *ventry, int flags, + DoneList *dlp) +{ + const Elf_Sym *def, *def_w; + const Needed_Entry *n; + const Obj_Entry *obj, *defobj, *defobj1; + + def = def_w = NULL; + defobj = NULL; + for (n = needed; n != NULL; n = n->next) { + if ((obj = n->obj) == NULL || + donelist_check(dlp, obj) || + (def = symlook_obj(name, hash, obj, ventry, flags)) == NULL) + continue; + defobj = obj; + if (ELF_ST_BIND(def->st_info) != STB_WEAK) { + *defobj_out = defobj; + return (def); + } + } + /* + * There we come when either symbol definition is not found in + * directly needed objects, or found symbol is weak. + */ + for (n = needed; n != NULL; n = n->next) { + if ((obj = n->obj) == NULL) + continue; + def_w = symlook_needed(name, hash, obj->needed, &defobj1, + ventry, flags, dlp); + if (def_w == NULL) + continue; + if (def == NULL || ELF_ST_BIND(def_w->st_info) != STB_WEAK) { + def = def_w; + defobj = defobj1; + } + if (ELF_ST_BIND(def_w->st_info) != STB_WEAK) + break; + } + if (def != NULL) + *defobj_out = defobj; + return def; +} + /* * Search the symbol table of a single shared object for a symbol of * the given name and version, if requested. Returns a pointer to the -- cgit v1.3