Skip to content

Commit

Permalink
Fix DTV race, assert, DTV_SURPLUS Static TLS limit, and nptl_db garbage
Browse files Browse the repository at this point in the history
for  ChangeLog

	[BZ #17090]
	[BZ #17620]
	[BZ #17621]
	[BZ #17628]
	* NEWS: Update.
	* elf/dl-tls.c (_dl_update_slotinfo): Clean up outdated DTV
	entries with Static TLS too.  Skip entries past the end of the
	allocated DTV, from Alan Modra.
	(tls_get_addr_tail): Update to glibc_likely/unlikely.  Move
	Static TLS DTV entry set up from...
	 (_dl_allocate_tls_init): ... here (fix modid assertion), ...
	* elf/dl-reloc.c (_dl_nothread_init_static_tls): ... here...
	* nptl/allocatestack.c (init_one_static_tls): ... and here...
	* elf/dlopen.c (dl_open_worker): Drop l_tls_modid upper bound
	for Static TLS.
	* elf/tlsdeschtab.h (map_generation): Return size_t.  Check
	that the slot we find is associated with the given map before
	using its generation count.
	* nptl_db/db_info.c: Include ldsodefs.h.
	(rtld_global, dtv_slotinfo_list, dtv_slotinfo): New typedefs.
	* nptl_db/structs.def (DB_RTLD_VARIABLE): New macro.
	(DB_MAIN_VARIABLE, DB_RTLD_GLOBAL_FIELD): Likewise.
	(link_map::l_tls_offset): New struct field.
	(dtv_t::counter): Likewise.
	(rtld_global): New struct.
	(_rtld_global): New rtld variable.
	(dl_tls_dtv_slotinfo_list): New rtld global field.
	(dtv_slotinfo_list): New struct.
	(dtv_slotinfo): Likewise.
	* nptl_db/td_symbol_list.c: Drop gnu/lib-names.h include.
	(td_lookup): Rename to...
	(td_mod_lookup): ... this.  Use new mod parameter instead of
	LIBPTHREAD_SO.
	* nptl_db/td_thr_tlsbase.c: Include link.h.
	(dtv_slotinfo_list, dtv_slotinfo): New functions.
	(td_thr_tlsbase): Check DTV generation.  Compute Static TLS
	addresses even if the DTV is out of date or missing them.
	* nptl_db/fetch-value.c (_td_locate_field): Do not refuse to
	index zero-length arrays.
	* nptl_db/thread_dbP.h: Include gnu/lib-names.h.
	(td_lookup): Make it a macro implemented in terms of...
	(td_mod_lookup): ... this declaration.
	* nptl_db/db-symbols.awk (DB_RTLD_VARIABLE): Override.
	(DB_MAIN_VARIABLE): Likewise.
  • Loading branch information
Alexandre Oliva committed Mar 17, 2015
1 parent b97eb2b commit f8aeae3
Show file tree
Hide file tree
Showing 14 changed files with 317 additions and 73 deletions.
47 changes: 47 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,50 @@
2015-03-17 Alexandre Oliva <aoliva@redhat.com>

[BZ #17090]
[BZ #17620]
[BZ #17621]
[BZ #17628]
* NEWS: Update.
* elf/dl-tls.c (_dl_update_slotinfo): Clean up outdated DTV
entries with Static TLS too. Skip entries past the end of the
allocated DTV, from Alan Modra.
(tls_get_addr_tail): Update to glibc_likely/unlikely. Move
Static TLS DTV entry set up from...
(_dl_allocate_tls_init): ... here (fix modid assertion), ...
* elf/dl-reloc.c (_dl_nothread_init_static_tls): ... here...
* nptl/allocatestack.c (init_one_static_tls): ... and here...
* elf/dlopen.c (dl_open_worker): Drop l_tls_modid upper bound
for Static TLS.
* elf/tlsdeschtab.h (map_generation): Return size_t. Check
that the slot we find is associated with the given map before
using its generation count.
* nptl_db/db_info.c: Include ldsodefs.h.
(rtld_global, dtv_slotinfo_list, dtv_slotinfo): New typedefs.
* nptl_db/structs.def (DB_RTLD_VARIABLE): New macro.
(DB_MAIN_VARIABLE, DB_RTLD_GLOBAL_FIELD): Likewise.
(link_map::l_tls_offset): New struct field.
(dtv_t::counter): Likewise.
(rtld_global): New struct.
(_rtld_global): New rtld variable.
(dl_tls_dtv_slotinfo_list): New rtld global field.
(dtv_slotinfo_list): New struct.
(dtv_slotinfo): Likewise.
* nptl_db/td_symbol_list.c: Drop gnu/lib-names.h include.
(td_lookup): Rename to...
(td_mod_lookup): ... this. Use new mod parameter instead of
LIBPTHREAD_SO.
* nptl_db/td_thr_tlsbase.c: Include link.h.
(dtv_slotinfo_list, dtv_slotinfo): New functions.
(td_thr_tlsbase): Check DTV generation. Compute Static TLS
addresses even if the DTV is out of date or missing them.
* nptl_db/fetch-value.c (_td_locate_field): Do not refuse to
index zero-length arrays.
* nptl_db/thread_dbP.h: Include gnu/lib-names.h.
(td_lookup): Make it a macro implemented in terms of...
(td_mod_lookup): ... this declaration.
* nptl_db/db-symbols.awk (DB_RTLD_VARIABLE): Override.
(DB_MAIN_VARIABLE): Likewise.

2015-03-16 H.J. Lu <hongjiu.lu@intel.com>

[BZ #18134]
Expand Down
11 changes: 6 additions & 5 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@ Version 2.22
* The following bugs are resolved with this release:

4719, 13064, 14094, 14841, 14906, 15319, 15467, 15790, 15969, 16351,
16512, 16560, 16783, 17269, 17523, 17569, 17588, 17631, 17711, 17776,
17779, 17792, 17836, 17912, 17916, 17932, 17944, 17949, 17964, 17965,
17967, 17969, 17978, 17987, 17991, 17996, 17998, 17999, 18019, 18020,
18029, 18030, 18032, 18036, 18038, 18039, 18042, 18043, 18046, 18047,
18068, 18080, 18093, 18104, 18110, 18111, 18128.
16512, 16560, 16783, 17090, 17269, 17523, 17569, 17588, 17620, 17621,
17628, 17631, 17711, 17776, 17779, 17792, 17836, 17912, 17916, 17932,
17944, 17949, 17964, 17965, 17967, 17969, 17978, 17987, 17991, 17996,
17998, 17999, 18019, 18020, 18029, 18030, 18032, 18036, 18038, 18039,
18042, 18043, 18046, 18047, 18068, 18080, 18093, 18104, 18110, 18111,
18128.

* Character encoding and ctype tables were updated to Unicode 7.0.0, using
new generator scripts contributed by Pravin Satpute and Mike FABIAN (Red
Expand Down
12 changes: 1 addition & 11 deletions elf/dl-open.c
Original file line number Diff line number Diff line change
Expand Up @@ -533,17 +533,7 @@ TLS generation counter wrapped! Please report this."));
&& imap->l_tls_blocksize > 0)
{
/* For static TLS we have to allocate the memory here and
now. This includes allocating memory in the DTV. But we
cannot change any DTV other than our own. So, if we
cannot guarantee that there is room in the DTV we don't
even try it and fail the load.
XXX We could track the minimum DTV slots allocated in
all threads. */
if (! RTLD_SINGLE_THREAD_P && imap->l_tls_modid > DTV_SURPLUS)
_dl_signal_error (0, "dlopen", NULL, N_("\
cannot load any more object with static TLS"));

now, but we can delay updating the DTV. */
imap->l_need_tls_init = 0;
#ifdef SHARED
/* Update the slot information data for at least the
Expand Down
6 changes: 0 additions & 6 deletions elf/dl-reloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -137,12 +137,6 @@ _dl_nothread_init_static_tls (struct link_map *map)
# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
#endif

/* Fill in the DTV slot so that a later LD/GD access will find it. */
dtv_t *dtv = THREAD_DTV ();
assert (map->l_tls_modid <= dtv[-1].counter);
dtv[map->l_tls_modid].pointer.val = dest;
dtv[map->l_tls_modid].pointer.is_static = true;

/* Initialize the memory. */
memset (__mempcpy (dest, map->l_tls_initimage, map->l_tls_initimage_size),
'\0', map->l_tls_blocksize - map->l_tls_initimage_size);
Expand Down
63 changes: 32 additions & 31 deletions elf/dl-tls.c
Original file line number Diff line number Diff line change
Expand Up @@ -493,17 +493,14 @@ _dl_allocate_tls_init (void *result)
assert (listp->slotinfo[cnt].gen <= GL(dl_tls_generation));
maxgen = MAX (maxgen, listp->slotinfo[cnt].gen);

dtv[map->l_tls_modid].pointer.val = TLS_DTV_UNALLOCATED;
dtv[map->l_tls_modid].pointer.is_static = false;

if (map->l_tls_offset == NO_TLS_OFFSET
|| map->l_tls_offset == FORCED_DYNAMIC_TLS_OFFSET)
{
/* For dynamically loaded modules we simply store
the value indicating deferred allocation. */
dtv[map->l_tls_modid].pointer.val = TLS_DTV_UNALLOCATED;
dtv[map->l_tls_modid].pointer.is_static = false;
continue;
}
continue;

assert (map->l_tls_modid == cnt);
assert (map->l_tls_modid == total + cnt);
assert (map->l_tls_blocksize >= map->l_tls_initimage_size);
#if TLS_TCB_AT_TP
assert ((size_t) map->l_tls_offset >= map->l_tls_blocksize);
Expand All @@ -515,8 +512,6 @@ _dl_allocate_tls_init (void *result)
#endif

/* Copy the initialization image and clear the BSS part. */
dtv[map->l_tls_modid].pointer.val = dest;
dtv[map->l_tls_modid].pointer.is_static = true;
memset (__mempcpy (dest, map->l_tls_initimage,
map->l_tls_initimage_size), '\0',
map->l_tls_blocksize - map->l_tls_initimage_size);
Expand Down Expand Up @@ -679,13 +674,16 @@ _dl_update_slotinfo (unsigned long int req_modid)
struct link_map *map = listp->slotinfo[cnt].map;
if (map == NULL)
{
/* If this modid was used at some point the memory
might still be allocated. */
if (! dtv[total + cnt].pointer.is_static
&& dtv[total + cnt].pointer.val != TLS_DTV_UNALLOCATED)
if (dtv[-1].counter >= total + cnt)
{
free (dtv[total + cnt].pointer.val);
/* If this modid was used at some point the memory
might still be allocated. */
if (! dtv[total + cnt].pointer.is_static
&& (dtv[total + cnt].pointer.val
!= TLS_DTV_UNALLOCATED))
free (dtv[total + cnt].pointer.val);
dtv[total + cnt].pointer.val = TLS_DTV_UNALLOCATED;
dtv[total + cnt].pointer.is_static = false;
}

continue;
Expand Down Expand Up @@ -718,10 +716,8 @@ _dl_update_slotinfo (unsigned long int req_modid)
memalign and not malloc. */
free (dtv[modid].pointer.val);

/* This module is loaded dynamically- We defer memory
allocation. */
dtv[modid].pointer.is_static = false;
dtv[modid].pointer.val = TLS_DTV_UNALLOCATED;
dtv[modid].pointer.is_static = false;

if (modid == req_modid)
the_map = map;
Expand Down Expand Up @@ -759,36 +755,41 @@ tls_get_addr_tail (GET_ADDR_ARGS, dtv_t *dtv, struct link_map *the_map)
the_map = listp->slotinfo[idx].map;
}

again:
/* Make sure that, if a dlopen running in parallel forces the
variable into static storage, we'll wait until the address in the
static TLS block is set up, and use that. If we're undecided
yet, make sure we make the decision holding the lock as well. */
if (__builtin_expect (the_map->l_tls_offset
!= FORCED_DYNAMIC_TLS_OFFSET, 0))
if (__glibc_unlikely (the_map->l_tls_offset
!= FORCED_DYNAMIC_TLS_OFFSET))
{
__rtld_lock_lock_recursive (GL(dl_load_lock));
if (__glibc_likely (the_map->l_tls_offset == NO_TLS_OFFSET))
{
the_map->l_tls_offset = FORCED_DYNAMIC_TLS_OFFSET;
__rtld_lock_unlock_recursive (GL(dl_load_lock));
}
else
else if (__glibc_likely (the_map->l_tls_offset
!= FORCED_DYNAMIC_TLS_OFFSET))
{
#if TLS_TCB_AT_TP
void *p = (char *) THREAD_SELF - the_map->l_tls_offset;
#elif TLS_DTV_AT_TP
void *p = (char *) THREAD_SELF + the_map->l_tls_offset + TLS_PRE_TCB_SIZE;
#else
# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
#endif
__rtld_lock_unlock_recursive (GL(dl_load_lock));
if (__builtin_expect (the_map->l_tls_offset
!= FORCED_DYNAMIC_TLS_OFFSET, 1))
{
void *p = dtv[GET_ADDR_MODULE].pointer.val;
if (__glibc_unlikely (p == TLS_DTV_UNALLOCATED))
goto again;

return (char *) p + GET_ADDR_OFFSET;
}
dtv[GET_ADDR_MODULE].pointer.is_static = true;
dtv[GET_ADDR_MODULE].pointer.val = p;

return (char *) p + GET_ADDR_OFFSET;
}
else
__rtld_lock_unlock_recursive (GL(dl_load_lock));
}
void *p = dtv[GET_ADDR_MODULE].pointer.val = allocate_and_init (the_map);
dtv[GET_ADDR_MODULE].pointer.is_static = false;
assert (!dtv[GET_ADDR_MODULE].pointer.is_static);

return (char *) p + GET_ADDR_OFFSET;
}
Expand Down
4 changes: 2 additions & 2 deletions elf/tlsdeschtab.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ eq_tlsdesc (void *p, void *q)
return tdp->tlsinfo.ti_offset == tdq->tlsinfo.ti_offset;
}

inline static int
inline static size_t
map_generation (struct link_map *map)
{
size_t idx = map->l_tls_modid;
Expand All @@ -58,7 +58,7 @@ map_generation (struct link_map *map)
we can assume that, if the generation count is zero, we
still haven't determined the generation count for this
module. */
if (listp->slotinfo[idx].gen)
if (listp->slotinfo[idx].map == map && listp->slotinfo[idx].gen)
return listp->slotinfo[idx].gen;
else
break;
Expand Down
9 changes: 3 additions & 6 deletions nptl/allocatestack.c
Original file line number Diff line number Diff line change
Expand Up @@ -1190,7 +1190,6 @@ __nptl_setxid (struct xid_command *cmdp)
static inline void __attribute__((always_inline))
init_one_static_tls (struct pthread *curp, struct link_map *map)
{
dtv_t *dtv = GET_DTV (TLS_TPADJ (curp));
# if TLS_TCB_AT_TP
void *dest = (char *) curp - map->l_tls_offset;
# elif TLS_DTV_AT_TP
Expand All @@ -1199,11 +1198,9 @@ init_one_static_tls (struct pthread *curp, struct link_map *map)
# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
# endif

/* Fill in the DTV slot so that a later LD/GD access will find it. */
dtv[map->l_tls_modid].pointer.val = dest;
dtv[map->l_tls_modid].pointer.is_static = true;

/* Initialize the memory. */
/* We cannot delay the initialization of the Static TLS area, since
it can be accessed with LE or IE, but since the DTV is only used
by GD and LD, we can delay its update to avoid a race. */
memset (__mempcpy (dest, map->l_tls_initimage, map->l_tls_initimage_size),
'\0', map->l_tls_blocksize - map->l_tls_initimage_size);
}
Expand Down
2 changes: 2 additions & 0 deletions nptl_db/db-symbols.awk
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
# we've just built. It checks for all the symbols used in td_symbol_list.

BEGIN {
%define DB_RTLD_VARIABLE(name) /* Nothing. */
%define DB_MAIN_VARIABLE(name) /* Nothing. */
%define DB_LOOKUP_NAME(idx, name) required[STRINGIFY (name)] = 1;
%define DB_LOOKUP_NAME_TH_UNIQUE(idx, name) th_unique[STRINGIFY (name)] = 1;
%include "db-symbols.h"
Expand Down
4 changes: 4 additions & 0 deletions nptl_db/db_info.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <stdint.h>
#include "thread_dbP.h"
#include <tls.h>
#include <ldsodefs.h>

typedef struct pthread pthread;
typedef struct pthread_key_struct pthread_key_struct;
Expand All @@ -37,6 +38,9 @@ typedef struct
} dtv;

typedef struct link_map link_map;
typedef struct rtld_global rtld_global;
typedef struct dtv_slotinfo_list dtv_slotinfo_list;
typedef struct dtv_slotinfo dtv_slotinfo;

/* Actually static in nptl/init.c, but we only need it for typeof. */
extern bool __nptl_initial_report_events;
Expand Down
3 changes: 2 additions & 1 deletion nptl_db/fetch-value.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ _td_locate_field (td_thragent_t *ta,
}
}

if (idx != 0 && idx - (psaddr_t) 0 > DB_DESC_NELEM (desc))
if (idx != 0 && DB_DESC_NELEM (desc) != 0
&& idx - (psaddr_t) 0 > DB_DESC_NELEM (desc))
/* This is an internal indicator to callers with nonzero IDX
that the IDX value is too big. */
return TD_NOAPLIC;
Expand Down
39 changes: 39 additions & 0 deletions nptl_db/structs.def
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,28 @@
# define STRUCTS_DEF_DEFAULTS 1
#endif

#ifndef DB_RTLD_VARIABLE
# define DB_RTLD_VARIABLE(name) DB_VARIABLE (name)
#endif

#ifndef DB_MAIN_VARIABLE
# define DB_MAIN_VARIABLE(name) DB_VARIABLE (name)
#endif

#ifndef DB_RTLD_GLOBAL_FIELD
# if !IS_IN (libpthread)
# define DB_RTLD_GLOBAL_FIELD(field) \
DB_STRUCT_FIELD (rtld_global, _##field) \
DB_MAIN_VARIABLE (_##field)
# elif defined SHARED
# define DB_RTLD_GLOBAL_FIELD(field) \
DB_STRUCT_FIELD (rtld_global, _##field)
# else
# define DB_RTLD_GLOBAL_FIELD(field) \
DB_MAIN_VARIABLE (_##field)
# endif
#endif /* DB_RTLD_GLOBAL_FIELD */

DB_STRUCT (pthread)
DB_STRUCT_FIELD (pthread, list)
DB_STRUCT_FIELD (pthread, report_events)
Expand Down Expand Up @@ -70,14 +92,31 @@ DB_STRUCT (pthread_key_data_level2)
DB_STRUCT_ARRAY_FIELD (pthread_key_data_level2, data)

DB_STRUCT_FIELD (link_map, l_tls_modid)
DB_STRUCT_FIELD (link_map, l_tls_offset)

DB_STRUCT_ARRAY_FIELD (dtv, dtv)
#define pointer_val pointer.val /* Field of anonymous struct in dtv_t. */
DB_STRUCT_FIELD (dtv_t, pointer_val)
DB_STRUCT_FIELD (dtv_t, counter)
#if !IS_IN (libpthread) || TLS_TCB_AT_TP
DB_STRUCT_FIELD (pthread, dtvp)
#endif

#if !(IS_IN (libpthread) && !defined SHARED)
DB_STRUCT (rtld_global)
DB_RTLD_VARIABLE (_rtld_global)
#endif
DB_RTLD_GLOBAL_FIELD (dl_tls_dtv_slotinfo_list)

DB_STRUCT (dtv_slotinfo_list)
DB_STRUCT_FIELD (dtv_slotinfo_list, len)
DB_STRUCT_FIELD (dtv_slotinfo_list, next)
DB_STRUCT_ARRAY_FIELD (dtv_slotinfo_list, slotinfo)

DB_STRUCT (dtv_slotinfo)
DB_STRUCT_FIELD (dtv_slotinfo, gen)
DB_STRUCT_FIELD (dtv_slotinfo, map)

#ifdef STRUCTS_DEF_DEFAULTS
# undef DB_STRUCT_ARRAY_FIELD
# undef DB_ARRAY_VARIABLE
Expand Down
7 changes: 3 additions & 4 deletions nptl_db/td_symbol_list.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
<http://www.gnu.org/licenses/>. */

#include <assert.h>
#include <gnu/lib-names.h>
#include "thread_dbP.h"

static const char *symbol_list_arr[] =
Expand All @@ -41,12 +40,12 @@ td_symbol_list (void)


ps_err_e
td_lookup (struct ps_prochandle *ps, int idx, psaddr_t *sym_addr)
td_mod_lookup (struct ps_prochandle *ps, const char *mod,
int idx, psaddr_t *sym_addr)
{
ps_err_e result;
assert (idx >= 0 && idx < SYM_NUM_MESSAGES);
result = ps_pglobal_lookup (ps, LIBPTHREAD_SO, symbol_list_arr[idx],
sym_addr);
result = ps_pglobal_lookup (ps, mod, symbol_list_arr[idx], sym_addr);

return result;
}
Loading

0 comments on commit f8aeae3

Please sign in to comment.