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
This commit is contained in:
parent
8827ec0618
commit
238a397e46
@ -85,7 +85,7 @@ static void digest_dynamic(Obj_Entry *, int);
|
|||||||
static Obj_Entry *digest_phdr(const Elf_Phdr *, int, caddr_t, const char *);
|
static Obj_Entry *digest_phdr(const Elf_Phdr *, int, caddr_t, const char *);
|
||||||
static Obj_Entry *dlcheck(void *);
|
static Obj_Entry *dlcheck(void *);
|
||||||
static Obj_Entry *dlopen_object(const char *name, int fd, Obj_Entry *refobj,
|
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 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 int do_search_info(const Obj_Entry *obj, int, struct dl_serinfo *);
|
||||||
static bool donelist_check(DoneList *, const Obj_Entry *);
|
static bool donelist_check(DoneList *, const Obj_Entry *);
|
||||||
@ -1672,13 +1672,14 @@ unload_filtees(Obj_Entry *obj)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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) {
|
for (; needed != NULL; needed = needed->next) {
|
||||||
needed->obj = dlopen_object(obj->strtab + needed->name, -1, obj,
|
needed->obj = dlopen_object(obj->strtab + needed->name, -1, obj,
|
||||||
flags, ((ld_loadfltr || obj->z_loadfltr) ? RTLD_NOW : RTLD_LAZY) |
|
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, RtldLockState *lockstate)
|
|||||||
|
|
||||||
lock_restart_for_upgrade(lockstate);
|
lock_restart_for_upgrade(lockstate);
|
||||||
if (!obj->filtees_loaded) {
|
if (!obj->filtees_loaded) {
|
||||||
load_filtee1(obj, obj->needed_filtees, flags);
|
load_filtee1(obj, obj->needed_filtees, flags, lockstate);
|
||||||
load_filtee1(obj, obj->needed_aux_filtees, flags);
|
load_filtee1(obj, obj->needed_aux_filtees, flags, lockstate);
|
||||||
obj->filtees_loaded = true;
|
obj->filtees_loaded = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2489,7 +2490,7 @@ rtld_dlopen(const char *name, int fd, int mode)
|
|||||||
lo_flags |= RTLD_LO_TRACE;
|
lo_flags |= RTLD_LO_TRACE;
|
||||||
|
|
||||||
return (dlopen_object(name, fd, obj_main, lo_flags,
|
return (dlopen_object(name, fd, obj_main, lo_flags,
|
||||||
mode & (RTLD_MODEMASK | RTLD_GLOBAL)));
|
mode & (RTLD_MODEMASK | RTLD_GLOBAL), NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -2504,17 +2505,20 @@ dlopen_cleanup(Obj_Entry *obj)
|
|||||||
|
|
||||||
static Obj_Entry *
|
static Obj_Entry *
|
||||||
dlopen_object(const char *name, int fd, Obj_Entry *refobj, int lo_flags,
|
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 **old_obj_tail;
|
||||||
Obj_Entry *obj;
|
Obj_Entry *obj;
|
||||||
Objlist initlist;
|
Objlist initlist;
|
||||||
RtldLockState lockstate;
|
RtldLockState mlockstate;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
objlist_init(&initlist);
|
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);
|
GDB_STATE(RT_ADD,NULL);
|
||||||
|
|
||||||
old_obj_tail = obj_tail;
|
old_obj_tail = obj_tail;
|
||||||
@ -2543,7 +2547,7 @@ dlopen_object(const char *name, int fd, Obj_Entry *refobj, int lo_flags,
|
|||||||
if (result == -1 || (relocate_objects(obj,
|
if (result == -1 || (relocate_objects(obj,
|
||||||
(mode & RTLD_MODEMASK) == RTLD_NOW, &obj_rtld,
|
(mode & RTLD_MODEMASK) == RTLD_NOW, &obj_rtld,
|
||||||
(lo_flags & RTLD_LO_EARLY) ? SYMLOOK_EARLY : 0,
|
(lo_flags & RTLD_LO_EARLY) ? SYMLOOK_EARLY : 0,
|
||||||
&lockstate)) == -1) {
|
lockstate)) == -1) {
|
||||||
dlopen_cleanup(obj);
|
dlopen_cleanup(obj);
|
||||||
obj = NULL;
|
obj = NULL;
|
||||||
} else if (lo_flags & RTLD_LO_EARLY) {
|
} else if (lo_flags & RTLD_LO_EARLY) {
|
||||||
@ -2587,28 +2591,31 @@ dlopen_object(const char *name, int fd, Obj_Entry *refobj, int lo_flags,
|
|||||||
GDB_STATE(RT_CONSISTENT,obj ? &obj->linkmap : NULL);
|
GDB_STATE(RT_CONSISTENT,obj ? &obj->linkmap : NULL);
|
||||||
|
|
||||||
if (!(lo_flags & RTLD_LO_EARLY)) {
|
if (!(lo_flags & RTLD_LO_EARLY)) {
|
||||||
map_stacks_exec(&lockstate);
|
map_stacks_exec(lockstate);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (initlist_objects_ifunc(&initlist, (mode & RTLD_MODEMASK) == RTLD_NOW,
|
if (initlist_objects_ifunc(&initlist, (mode & RTLD_MODEMASK) == RTLD_NOW,
|
||||||
(lo_flags & RTLD_LO_EARLY) ? SYMLOOK_EARLY : 0,
|
(lo_flags & RTLD_LO_EARLY) ? SYMLOOK_EARLY : 0,
|
||||||
&lockstate) == -1) {
|
lockstate) == -1) {
|
||||||
objlist_clear(&initlist);
|
objlist_clear(&initlist);
|
||||||
dlopen_cleanup(obj);
|
dlopen_cleanup(obj);
|
||||||
lock_release(rtld_bind_lock, &lockstate);
|
if (lockstate == &mlockstate)
|
||||||
|
lock_release(rtld_bind_lock, lockstate);
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(lo_flags & RTLD_LO_EARLY)) {
|
if (!(lo_flags & RTLD_LO_EARLY)) {
|
||||||
/* Call the init functions. */
|
/* Call the init functions. */
|
||||||
objlist_call_init(&initlist, &lockstate);
|
objlist_call_init(&initlist, lockstate);
|
||||||
}
|
}
|
||||||
objlist_clear(&initlist);
|
objlist_clear(&initlist);
|
||||||
lock_release(rtld_bind_lock, &lockstate);
|
if (lockstate == &mlockstate)
|
||||||
|
lock_release(rtld_bind_lock, lockstate);
|
||||||
return obj;
|
return obj;
|
||||||
trace:
|
trace:
|
||||||
trace_loaded_objects(obj);
|
trace_loaded_objects(obj);
|
||||||
lock_release(rtld_bind_lock, &lockstate);
|
if (lockstate == &mlockstate)
|
||||||
|
lock_release(rtld_bind_lock, lockstate);
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user