rtld: Ensure that dlopen() cannot obtain a reference on a doomed object.

rtld drops the bind lock to call fini functions in an object prior to
unmapping it. The new "doomed" state flag prevents the acquisition of new
references for an object while the lock is dropped.

Reviewed by:	kib
MFC after:	2 weeks
Sponsored by:	Dell EMC Isilon
This commit is contained in:
Mark Johnston 2016-12-22 17:41:32 +00:00
parent c02741759f
commit 510fe58c82
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=310421
2 changed files with 9 additions and 10 deletions

View File

@ -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.

View File

@ -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 (%) */