diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c index cde79be9b6bd..10711da25bb1 100644 --- a/libexec/rtld-elf/rtld.c +++ b/libexec/rtld-elf/rtld.c @@ -2229,7 +2229,7 @@ load_object(const char *name, int fd_u, const Obj_Entry *refobj, int flags) fd = -1; if (name != NULL) { TAILQ_FOREACH(obj, &obj_list, next) { - if (obj->marker) + if (obj->marker || obj->doomed) continue; if (object_match_name(obj, name)) return (obj); @@ -2276,7 +2276,7 @@ load_object(const char *name, int fd_u, const Obj_Entry *refobj, int flags) return NULL; } TAILQ_FOREACH(obj, &obj_list, next) { - if (obj->marker) + if (obj->marker || obj->doomed) continue; if (obj->ino == sb.st_ino && obj->dev == sb.st_dev) break; @@ -2418,6 +2418,9 @@ objlist_call_fini(Objlist *list, Obj_Entry *root, RtldLockState *lockstate) assert(root == NULL || root->refcount == 1); + if (root != NULL) + root->doomed = true; + /* * Preserve the current error message since a fini function might * call into the dynamic linker and overwrite it. @@ -2430,16 +2433,11 @@ objlist_call_fini(Objlist *list, Obj_Entry *root, RtldLockState *lockstate) continue; /* Remove object from fini list to prevent recursive invocation. */ STAILQ_REMOVE(list, elm, Struct_Objlist_Entry, link); - /* - * XXX: If a dlopen() call references an object while the - * fini function is in progress, we might end up trying to - * unload the referenced object in dlclose() or the object - * won't be unloaded although its fini function has been - * called. - */ + /* Ensure that new references cannot be acquired. */ + elm->obj->doomed = true; + hold_object(elm->obj); lock_release(rtld_bind_lock, lockstate); - /* * It is legal to have both DT_FINI and DT_FINI_ARRAY defined. * When this happens, DT_FINI_ARRAY is processed first. diff --git a/libexec/rtld-elf/rtld.h b/libexec/rtld-elf/rtld.h index cb99651a1d3a..4e48026e8409 100644 --- a/libexec/rtld-elf/rtld.h +++ b/libexec/rtld-elf/rtld.h @@ -267,6 +267,7 @@ typedef struct Struct_Obj_Entry { bool dlopened : 1; /* dlopen()-ed (vs. load statically) */ bool marker : 1; /* marker on the global obj list */ bool unholdfree : 1; /* unmap upon last unhold */ + bool doomed : 1; /* Object cannot be referenced */ struct link_map linkmap; /* For GDB and dlinfo() */ Objlist dldags; /* Object belongs to these dlopened DAGs (%) */