Date: Thu, 12 Apr 2012 10:32:22 +0000 (UTC) From: Konstantin Belousov <kib@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r234170 - head/libexec/rtld-elf Message-ID: <201204121032.q3CAWM0W024351@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: kib Date: Thu Apr 12 10:32:22 2012 New Revision: 234170 URL: http://svn.freebsd.org/changeset/base/234170 Log: Propagate the current state of rtld_bind_lock to dlopen_object() calls through the filter loading call chain. This fixes attempts to write-lock the already locked rtld_bind_lock when filter loading is initiated by relocation of dlopening dso. Reported and tested by: Taku YAMAMOTO <taku tackymt homeip net> MFC after: 1 week Modified: head/libexec/rtld-elf/rtld.c Modified: head/libexec/rtld-elf/rtld.c ============================================================================== --- head/libexec/rtld-elf/rtld.c Thu Apr 12 08:54:01 2012 (r234169) +++ head/libexec/rtld-elf/rtld.c Thu Apr 12 10:32:22 2012 (r234170) @@ -85,7 +85,7 @@ static void digest_dynamic(Obj_Entry *, static Obj_Entry *digest_phdr(const Elf_Phdr *, int, caddr_t, const char *); static Obj_Entry *dlcheck(void *); static Obj_Entry *dlopen_object(const char *name, int fd, Obj_Entry *refobj, - int lo_flags, int mode); + int lo_flags, int mode, RtldLockState *lockstate); static Obj_Entry *do_load_object(int, const char *, char *, struct stat *, int); static int do_search_info(const Obj_Entry *obj, int, struct dl_serinfo *); static bool donelist_check(DoneList *, const Obj_Entry *); @@ -1672,13 +1672,14 @@ unload_filtees(Obj_Entry *obj) } static void -load_filtee1(Obj_Entry *obj, Needed_Entry *needed, int flags) +load_filtee1(Obj_Entry *obj, Needed_Entry *needed, int flags, + RtldLockState *lockstate) { for (; needed != NULL; needed = needed->next) { needed->obj = dlopen_object(obj->strtab + needed->name, -1, obj, flags, ((ld_loadfltr || obj->z_loadfltr) ? RTLD_NOW : RTLD_LAZY) | - RTLD_LOCAL); + RTLD_LOCAL, lockstate); } } @@ -1688,8 +1689,8 @@ load_filtees(Obj_Entry *obj, int flags, lock_restart_for_upgrade(lockstate); if (!obj->filtees_loaded) { - load_filtee1(obj, obj->needed_filtees, flags); - load_filtee1(obj, obj->needed_aux_filtees, flags); + load_filtee1(obj, obj->needed_filtees, flags, lockstate); + load_filtee1(obj, obj->needed_aux_filtees, flags, lockstate); obj->filtees_loaded = true; } } @@ -2489,7 +2490,7 @@ rtld_dlopen(const char *name, int fd, in lo_flags |= RTLD_LO_TRACE; return (dlopen_object(name, fd, obj_main, lo_flags, - mode & (RTLD_MODEMASK | RTLD_GLOBAL))); + mode & (RTLD_MODEMASK | RTLD_GLOBAL), NULL)); } static void @@ -2504,17 +2505,20 @@ dlopen_cleanup(Obj_Entry *obj) static Obj_Entry * dlopen_object(const char *name, int fd, Obj_Entry *refobj, int lo_flags, - int mode) + int mode, RtldLockState *lockstate) { Obj_Entry **old_obj_tail; Obj_Entry *obj; Objlist initlist; - RtldLockState lockstate; + RtldLockState mlockstate; int result; objlist_init(&initlist); - wlock_acquire(rtld_bind_lock, &lockstate); + if (lockstate == NULL && !(lo_flags & RTLD_LO_EARLY)) { + wlock_acquire(rtld_bind_lock, &mlockstate); + lockstate = &mlockstate; + } GDB_STATE(RT_ADD,NULL); old_obj_tail = obj_tail; @@ -2543,7 +2547,7 @@ dlopen_object(const char *name, int fd, if (result == -1 || (relocate_objects(obj, (mode & RTLD_MODEMASK) == RTLD_NOW, &obj_rtld, (lo_flags & RTLD_LO_EARLY) ? SYMLOOK_EARLY : 0, - &lockstate)) == -1) { + lockstate)) == -1) { dlopen_cleanup(obj); obj = NULL; } else if (lo_flags & RTLD_LO_EARLY) { @@ -2587,28 +2591,31 @@ dlopen_object(const char *name, int fd, GDB_STATE(RT_CONSISTENT,obj ? &obj->linkmap : NULL); if (!(lo_flags & RTLD_LO_EARLY)) { - map_stacks_exec(&lockstate); + map_stacks_exec(lockstate); } if (initlist_objects_ifunc(&initlist, (mode & RTLD_MODEMASK) == RTLD_NOW, (lo_flags & RTLD_LO_EARLY) ? SYMLOOK_EARLY : 0, - &lockstate) == -1) { + lockstate) == -1) { objlist_clear(&initlist); dlopen_cleanup(obj); - lock_release(rtld_bind_lock, &lockstate); + if (lockstate == &mlockstate) + lock_release(rtld_bind_lock, lockstate); return (NULL); } if (!(lo_flags & RTLD_LO_EARLY)) { /* Call the init functions. */ - objlist_call_init(&initlist, &lockstate); + objlist_call_init(&initlist, lockstate); } objlist_clear(&initlist); - lock_release(rtld_bind_lock, &lockstate); + if (lockstate == &mlockstate) + lock_release(rtld_bind_lock, lockstate); return obj; trace: trace_loaded_objects(obj); - lock_release(rtld_bind_lock, &lockstate); + if (lockstate == &mlockstate) + lock_release(rtld_bind_lock, lockstate); exit(0); }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201204121032.q3CAWM0W024351>