[PATCH][BZ #19329] Fix race between tls allocation at thread creation and dlopen
Szabolcs Nagy
szabolcs.nagy@arm.com
Wed Jan 6 18:34:00 GMT 2016
I've seen the following failure:
Inconsistency detected by ld.so: dl-tls.c: 493: _dl_allocate_tls_init: Assertion `listp->slotinfo[cnt].gen <=
_rtld_local._dl_tls_generation' failed!
It seems dlopen modifies tls related dynamic linker data structures in
dl_open_worker if a shared library is loaded with tls, while holding
the GL(dl_load_lock).
Meanwhile at thread creation the same globals are accessed when the dtv
and tls is set up for the new thread in _dl_allocate_tls_init without
holding any locks.
At least the following objects may have conflicting access:
GL(dl_tls_max_dtv_idx)
GL(dl_tls_generation)
listp->slotinfo[i].map
listp->slotinfo[i].gen
listp->next
The race window that triggers the assert failure above is short compared
to dlopen and thread creation, so it rarely happens, but the probability
can be increased by loading a long chain of dependent shared objects
with tls. Then all the loaded dsos get the same generation number,
GL(dl_tls_generation)+1, in the slotinfo list and GL(dl_tls_generation)
gets incremented only after that, so the assertion can fail in a
concurrently created thread reading the new slotinfos.
My fix loads the current number of dtv slots, GL(dl_tls_max_dtv_idx),
and the current generation counter, GL(dl_tls_generation), at the
beginning of _dl_allocate_tls_init and then ignores any slotinfo
entry that got concurrently added. So instead of taking the
GL(dl_load_lock), used atomics to avoid the races.
I think various other accesses to the objects in the list above should
be atomic as well, but that rabbit hole is deeper than what a quick
fix could patch up.
I can trigger the bug on x86_64 by loading a chain of 50 dsos and
concurrently creating >1000 threads, but i cannot easily turn that
into a glibc test case. (On aarch64 the failure happens to be more
common.)
A related issue is that glibc does not try to do worst-case allocation
of tls for existing threads whenever a library is loaded so there might
be further allocation needed at first tls access making it non-as-safe
and possibly oom crash. This lazy allocation allows me to ignore the
slotinfo of concurrently loaded dsos in _dl_allocate_tls_init, those
will be lazy initialized.
Changelog:
2016-01-06 Szabolcs Nagy <szabolcs.nagy@arm.com>
[BZ #19329]
* elf/dl-open.c (dl_open_worker): Write GL(dl_tls_generation) atomically.
* elf/dl-tls.c (_dl_allocate_tls_init): Read GL(dl_tls_generation),
GL(dl_tls_max_dtv_idx) and slotinfo entries atomically.
(_dl_add_to_slotinfo): Write the slotinfo entry atomically.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: dtv.diff
Type: text/x-patch
Size: 3230 bytes
Desc: not available
URL: <http://sourceware.org/pipermail/libc-alpha/attachments/20160106/8b3b2749/attachment.bin>
More information about the Libc-alpha
mailing list