1
0
mirror of https://sourceware.org/git/glibc.git synced 2025-08-08 17:42:12 +03:00

Add forced deletion support to _dl_close_worker

https://sourceware.org/bugzilla/show_bug.cgi?id=17833

I've a shared library that contains both undefined and unique symbols.
Then I try to call the following sequence of dlopen:

1. dlopen("./libfoo.so", RTLD_NOW)
2. dlopen("./libfoo.so", RTLD_LAZY | RTLD_GLOBAL)

First dlopen call terminates with error because of undefined symbols,
but STB_GNU_UNIQUE ones set DF_1_NODELETE flag and hence block library
in the memory.

The library goes into inconsistent state as several structures remain
uninitialized. For instance, relocations for GOT table were not performed.

By the time of second dlopen call this library looks like as it would be
fully initialized but this is not true: any call through incorrect GOT
table leads to segmentation fault.  On some systems this inconsistency
triggers assertions in the dynamic linker.

This patch adds a parameter to _dl_close_worker to implement forced object
deletion in case of dlopen() failure:

1. Clears DF_1_NODELETE bit if forced, to allow library to be removed from
memory.
2. For each unique symbol that is defined in this object clears
appropriate entry in _ns_unique_sym_table.

	[BZ #17833]
	* elf/Makefile (tests): Add tst-nodelete.
	(modules-names): Add tst-nodelete-uniquemod.
	(tst-nodelete-uniquemod.so-no-z-defs): New.
	(tst-nodelete-rtldmod.so-no-z-defs): Likewise.
	(tst-nodelete-zmod.so-no-z-defs): Likewise.
	($(objpfx)tst-nodelete): Likewise.
	($(objpfx)tst-nodelete.out): Likewise.
	(LDFLAGS-tst-nodelete): Likewise.
	(LDFLAGS-tst-nodelete-zmod.so): Likewise.
	* elf/dl-close.c (_dl_close_worker): Add a parameter to
	implement forced object deletion.
	(_dl_close): Pass false to _dl_close_worker.
	* elf/dl-open.c (_dl_open): Pass true to _dl_close_worker.
	* elf/tst-nodelete.cc: New file.
	* elf/tst-nodeletelib.cc: Likewise.
	* elf/tst-znodeletelib.cc: Likewise.
	* include/dlfcn.h (_dl_close_worker): Add a new parameter.
This commit is contained in:
Pavel Kopyl
2015-07-07 18:45:46 +03:00
committed by H.J. Lu
parent 890b7a4b33
commit 02d5e5d94a
11 changed files with 167 additions and 19 deletions

View File

@@ -108,7 +108,7 @@ remove_slotinfo (size_t idx, struct dtv_slotinfo_list *listp, size_t disp,
void
_dl_close_worker (struct link_map *map)
_dl_close_worker (struct link_map *map, bool force)
{
/* One less direct use. */
--map->l_direct_opencount;
@@ -152,6 +152,10 @@ _dl_close_worker (struct link_map *map)
l->l_idx = idx;
maps[idx] = l;
++idx;
/* Clear DF_1_NODELETE to force object deletion. */
if (force)
l->l_flags_1 &= ~DF_1_NODELETE;
}
assert (idx == nloaded);
@@ -635,6 +639,31 @@ _dl_close_worker (struct link_map *map)
}
}
/* Reset unique symbols if forced. */
if (force)
{
struct unique_sym_table *tab = &ns->_ns_unique_sym_table;
__rtld_lock_lock_recursive (tab->lock);
struct unique_sym *entries = tab->entries;
if (entries != NULL)
{
size_t idx, size = tab->size;
for (idx = 0; idx < size; ++idx)
{
/* Clear unique symbol entries that belong to this
object. */
if (entries[idx].name != NULL
&& entries[idx].map == imap)
{
entries[idx].name = NULL;
entries[idx].hashval = 0;
tab->n_elements--;
}
}
}
__rtld_lock_unlock_recursive (tab->lock);
}
/* We can unmap all the maps at once. We determined the
start address and length when we loaded the object and
the `munmap' call does the rest. */
@@ -782,7 +811,7 @@ _dl_close (void *_map)
/* Acquire the lock. */
__rtld_lock_lock_recursive (GL(dl_load_lock));
_dl_close_worker (map);
_dl_close_worker (map, false);
__rtld_lock_unlock_recursive (GL(dl_load_lock));
}