summaryrefslogtreecommitdiffstats
path: root/libexec
diff options
context:
space:
mode:
authorkan <kan@FreeBSD.org>2008-09-03 01:05:32 +0000
committerkan <kan@FreeBSD.org>2008-09-03 01:05:32 +0000
commitad15dd0347be6ac89f045eb2d3796f0c1a191ea0 (patch)
tree9e07cd337fd5cf19b2caf2d1aec1f1e4b1497a94 /libexec
parentad33f05a7c8ea70d1e02d61b1d866130540245e9 (diff)
downloadFreeBSD-src-ad15dd0347be6ac89f045eb2d3796f0c1a191ea0.zip
FreeBSD-src-ad15dd0347be6ac89f045eb2d3796f0c1a191ea0.tar.gz
Make sure internal rtld malloc routines are not called from unlocked
contexts as rtld's malloc is not thread safe and is only supposed to be called with exclusive bind lock already held. The originating PR submitted a patch on top of different pre-requisite workaroud for unsafe dlopen calls, and the patch was midief slighlty to apply to stock sources for the purpose of this commit. Running rtld malloc from unlocked contexts is a bug on its own. PR: 126950 Submited by: Oleg Dolgov
Diffstat (limited to 'libexec')
-rw-r--r--libexec/rtld-elf/rtld.c31
1 files changed, 17 insertions, 14 deletions
diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c
index ec68eea..7e0f8b1 100644
--- a/libexec/rtld-elf/rtld.c
+++ b/libexec/rtld-elf/rtld.c
@@ -106,8 +106,8 @@ static int load_needed_objects(Obj_Entry *);
static int load_preload_objects(void);
static Obj_Entry *load_object(const char *, const Obj_Entry *);
static Obj_Entry *obj_from_addr(const void *);
-static void objlist_call_fini(Objlist *);
-static void objlist_call_init(Objlist *);
+static void objlist_call_fini(Objlist *, int *lockstate);
+static void objlist_call_init(Objlist *, int *lockstate);
static void objlist_clear(Objlist *);
static Objlist_Entry *objlist_find(Objlist *, const Obj_Entry *);
static void objlist_init(Objlist *);
@@ -512,8 +512,8 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
r_debug_state(NULL, &obj_main->linkmap); /* say hello to gdb! */
- objlist_call_init(&initlist);
lockstate = wlock_acquire(rtld_bind_lock);
+ objlist_call_init(&initlist, &lockstate);
objlist_clear(&initlist);
wlock_release(rtld_bind_lock, lockstate);
@@ -1464,7 +1464,7 @@ obj_from_addr(const void *addr)
* non-NULL fini functions.
*/
static void
-objlist_call_fini(Objlist *list)
+objlist_call_fini(Objlist *list, int *lockstate)
{
Objlist_Entry *elm;
char *saved_msg;
@@ -1474,6 +1474,7 @@ objlist_call_fini(Objlist *list)
* call into the dynamic linker and overwrite it.
*/
saved_msg = errmsg_save();
+ wlock_release(rtld_bind_lock, *lockstate);
STAILQ_FOREACH(elm, list, link) {
if (elm->obj->refcount == 0) {
dbg("calling fini function for %s at %p", elm->obj->path,
@@ -1483,6 +1484,7 @@ objlist_call_fini(Objlist *list)
call_initfini_pointer(elm->obj, elm->obj->fini);
}
}
+ *lockstate = wlock_acquire(rtld_bind_lock);
errmsg_restore(saved_msg);
}
@@ -1492,7 +1494,7 @@ objlist_call_fini(Objlist *list)
* functions.
*/
static void
-objlist_call_init(Objlist *list)
+objlist_call_init(Objlist *list, int *lockstate)
{
Objlist_Entry *elm;
char *saved_msg;
@@ -1502,6 +1504,7 @@ objlist_call_init(Objlist *list)
* call into the dynamic linker and overwrite it.
*/
saved_msg = errmsg_save();
+ wlock_release(rtld_bind_lock, *lockstate);
STAILQ_FOREACH(elm, list, link) {
dbg("calling init function for %s at %p", elm->obj->path,
(void *)elm->obj->init);
@@ -1509,6 +1512,7 @@ objlist_call_init(Objlist *list)
elm->obj->path);
call_initfini_pointer(elm->obj, elm->obj->init);
}
+ *lockstate = wlock_acquire(rtld_bind_lock);
errmsg_restore(saved_msg);
}
@@ -1669,15 +1673,18 @@ static void
rtld_exit(void)
{
Obj_Entry *obj;
+ int lockstate;
+ lockstate = wlock_acquire(rtld_bind_lock);
dbg("rtld_exit()");
/* Clear all the reference counts so the fini functions will be called. */
for (obj = obj_list; obj != NULL; obj = obj->next)
obj->refcount = 0;
- objlist_call_fini(&list_fini);
+ objlist_call_fini(&list_fini, &lockstate);
/* No need to remove the items from the list, since we are exiting. */
if (!libmap_disable)
lm_fini();
+ wlock_release(rtld_bind_lock, lockstate);
}
static void *
@@ -1791,11 +1798,9 @@ dlclose(void *handle)
if (root->refcount == 0) {
/*
* The object is no longer referenced, so we must unload it.
- * First, call the fini functions with no locks held.
+ * First, call the fini functions.
*/
- wlock_release(rtld_bind_lock, lockstate);
- objlist_call_fini(&list_fini);
- lockstate = wlock_acquire(rtld_bind_lock);
+ objlist_call_fini(&list_fini, &lockstate);
objlist_remove_unref(&list_fini);
/* Finish cleaning up the newly-unreferenced objects. */
@@ -1903,10 +1908,8 @@ dlopen(const char *name, int mode)
name);
GDB_STATE(RT_CONSISTENT,obj ? &obj->linkmap : NULL);
- /* Call the init functions with no locks held. */
- wlock_release(rtld_bind_lock, lockstate);
- objlist_call_init(&initlist);
- lockstate = wlock_acquire(rtld_bind_lock);
+ /* Call the init functions. */
+ objlist_call_init(&initlist, &lockstate);
objlist_clear(&initlist);
wlock_release(rtld_bind_lock, lockstate);
return obj;
OpenPOWER on IntegriCloud