diff options
author | Thomas Schwinge <thomas@codesourcery.com> | 2013-12-20 08:59:57 +0100 |
---|---|---|
committer | Thomas Schwinge <thomas@codesourcery.com> | 2013-12-20 08:59:57 +0100 |
commit | b4578bab30f72cddd2cf38abfb39f9c8dc892249 (patch) | |
tree | 60b8d9a3ae574849fe9b3768622ec513325b1255 /elf | |
parent | 3fcdabc977f7aa0a92da7030c775313eb6d17abc (diff) | |
parent | 64a17f1adde4715bb6607f64decd73b2df9e6852 (diff) |
Merge commit 'refs/top-bases/baseline' into baseline
Diffstat (limited to 'elf')
45 files changed, 705 insertions, 135 deletions
diff --git a/elf/Makefile b/elf/Makefile index 3b58649de5..c6626e14bf 100644 --- a/elf/Makefile +++ b/elf/Makefile @@ -59,7 +59,7 @@ before-compile = $(objpfx)trusted-dirs.h generated := trusted-dirs.h trusted-dirs.st for-renamed/renamed.so generated-dirs := for-renamed -ifeq ($(versioning),yes) +ifeq ($(build-shared),yes) ld-map = $(common-objpfx)ld.map endif @@ -119,9 +119,11 @@ $(inst_auditdir)/sotruss-lib.so: $(objpfx)sotruss-lib.so $(+force) endif tests = tst-tls1 tst-tls2 tst-tls9 tst-leaks1 \ - tst-array1 tst-array2 tst-array3 tst-array4 tst-array5 + tst-array1 tst-array2 tst-array3 tst-array4 tst-array5 \ + tst-auxv tests-static = tst-tls1-static tst-tls2-static tst-stackguard1-static \ - tst-leaks1-static tst-array1-static tst-array5-static + tst-leaks1-static tst-array1-static tst-array5-static \ + tst-ptrguard1-static ifeq (yes,$(build-shared)) tests-static += tst-tls9-static tst-tls9-static-ENV = \ @@ -145,7 +147,8 @@ tests += loadtest restest1 preloadtest loadfail multiload origtest resolvfail \ tst-audit1 tst-audit2 tst-audit8 \ tst-stackguard1 tst-addr1 tst-thrlock \ tst-unique1 tst-unique2 tst-unique3 tst-unique4 \ - tst-initorder tst-initorder2 tst-relsort1 tst-null-argv + tst-initorder tst-initorder2 tst-relsort1 tst-null-argv \ + tst-ptrguard1 # reldep9 test-srcs = tst-pathopt selinux-enabled := $(shell cat /selinux/enforce 2> /dev/null) @@ -1016,6 +1019,12 @@ LDFLAGS-order2mod2.so = $(no-as-needed) tst-stackguard1-ARGS = --command "$(host-test-program-cmd) --child" tst-stackguard1-static-ARGS = --command "$(objpfx)tst-stackguard1-static --child" +tst-ptrguard1-ARGS = --command "$(host-test-program-cmd) --child" +# When built statically, the pointer guard interface uses +# __pointer_chk_guard_local. +CFLAGS-tst-ptrguard1-static.c = -DPTRGUARD_LOCAL +tst-ptrguard1-static-ARGS = --command "$(objpfx)tst-ptrguard1-static --child" + $(objpfx)tst-leaks1: $(libdl) $(objpfx)tst-leaks1-mem: $(objpfx)tst-leaks1.out $(common-objpfx)malloc/mtrace $(objpfx)tst-leaks1.mtrace > $@ diff --git a/elf/Versions b/elf/Versions index 238399232d..01b7a59d5e 100644 --- a/elf/Versions +++ b/elf/Versions @@ -53,6 +53,7 @@ ld { _dl_allocate_tls; _dl_allocate_tls_init; _dl_argv; _dl_find_dso_for_object; _dl_get_tls_static_info; _dl_deallocate_tls; _dl_make_stack_executable; _dl_out_of_memory; + _dl_clear_dtv; _dl_rtld_di_serinfo; _dl_starting_up; _dl_tls_setup; _rtld_global; _rtld_global_ro; diff --git a/elf/cache.c b/elf/cache.c index 9bf261cd29..1a43dd7765 100644 --- a/elf/cache.c +++ b/elf/cache.c @@ -105,6 +105,15 @@ print_entry (const char *lib, int flag, unsigned int osversion, case FLAG_ARM_LIBSF: fputs (",soft-float", stdout); break; + case FLAG_MIPS_LIB32_NAN2008: + fputs (",nan2008", stdout); + break; + case FLAG_MIPS64_LIBN32_NAN2008: + fputs (",N32,nan2008", stdout); + break; + case FLAG_MIPS64_LIBN64_NAN2008: + fputs (",64bit,nan2008", stdout); + break; case 0: break; default: diff --git a/elf/dl-close.c b/elf/dl-close.c index fe3014cca3..407926bade 100644 --- a/elf/dl-close.c +++ b/elf/dl-close.c @@ -274,9 +274,8 @@ _dl_close_worker (struct link_map *map) /* Next try the old-style destructor. */ if (imap->l_info[DT_FINI] != NULL) - (*(void (*) (void)) DL_DT_FINI_ADDRESS - (imap, ((void *) imap->l_addr - + imap->l_info[DT_FINI]->d_un.d_ptr))) (); + DL_CALL_DT_FINI (imap, ((void *) imap->l_addr + + imap->l_info[DT_FINI]->d_un.d_ptr)); } #ifdef SHARED diff --git a/elf/dl-deps.c b/elf/dl-deps.c index 1c36f501bc..6652f6d0cd 100644 --- a/elf/dl-deps.c +++ b/elf/dl-deps.c @@ -595,7 +595,6 @@ Filters not supported with LD_TRACE_PRELINKING")); if (list[i]->l_reserved) { /* Need to allocate new array of relocation dependencies. */ - struct link_map_reldeps *l_reldeps; l_reldeps = malloc (sizeof (*l_reldeps) + map->l_reldepsmax * sizeof (struct link_map *)); diff --git a/elf/dl-error.c b/elf/dl-error.c index 8257c17030..79e3fa38f2 100644 --- a/elf/dl-error.c +++ b/elf/dl-error.c @@ -28,10 +28,11 @@ _dl_signal_error. */ struct catch { - const char *objname; /* Object/File name. */ - const char *errstring; /* Error detail filled in here. */ - bool malloced; /* Nonzero if the string is malloced + const char **objname; /* Object/File name. */ + const char **errstring; /* Error detail filled in here. */ + bool *malloced; /* Nonzero if the string is malloced by the libc malloc. */ + volatile int *errcode; /* Return value of _dl_signal_error. */ jmp_buf env; /* longjmp here on error. */ }; @@ -86,33 +87,36 @@ _dl_signal_error (int errcode, const char *objname, const char *occation, size_t len_objname = strlen (objname) + 1; size_t len_errstring = strlen (errstring) + 1; - lcatch->errstring = (char *) malloc (len_objname + len_errstring); - if (lcatch->errstring != NULL) + char *errstring_copy = malloc (len_objname + len_errstring); + if (errstring_copy != NULL) { /* Make a copy of the object file name and the error string. */ - lcatch->objname = memcpy (__mempcpy ((char *) lcatch->errstring, - errstring, len_errstring), - objname, len_objname); + *lcatch->objname = memcpy (__mempcpy (errstring_copy, + errstring, len_errstring), + objname, len_objname); + *lcatch->errstring = errstring_copy; /* If the main executable is relocated it means the libc's malloc is used. */ + bool malloced = true; #ifdef SHARED - lcatch->malloced = (GL(dl_ns)[LM_ID_BASE]._ns_loaded != NULL - && (GL(dl_ns)[LM_ID_BASE]._ns_loaded->l_relocated - != 0)); -#else - lcatch->malloced = true; + malloced = (GL(dl_ns)[LM_ID_BASE]._ns_loaded != NULL + && (GL(dl_ns)[LM_ID_BASE]._ns_loaded->l_relocated != 0)); #endif + *lcatch->malloced = malloced; } else { /* This is better than nothing. */ - lcatch->objname = ""; - lcatch->errstring = _dl_out_of_memory; - lcatch->malloced = false; + *lcatch->objname = ""; + *lcatch->errstring = _dl_out_of_memory; + *lcatch->malloced = false; } + + *lcatch->errcode = errcode; + /* We do not restore the signal mask because none was saved. */ - __longjmp (lcatch->env[0].__jmpbuf, errcode ?: -1); + __longjmp (lcatch->env[0].__jmpbuf, 1); } else { @@ -157,23 +161,29 @@ internal_function _dl_catch_error (const char **objname, const char **errstring, bool *mallocedp, void (*operate) (void *), void *args) { - int errcode; - struct catch *volatile old; - struct catch c; /* We need not handle `receiver' since setting a `catch' is handled before it. */ - /* Some systems (e.g., SPARC) handle constructors to local variables - inefficient. So we initialize `c' by hand. */ - c.errstring = NULL; + /* Only this needs to be marked volatile, because it is the only local + variable that gets changed between the setjmp invocation and the + longjmp call. All others are just set here (before setjmp) and read + in _dl_signal_error (before longjmp). */ + volatile int errcode; + + struct catch c; + /* Don't use an initializer since we don't need to clear C.env. */ + c.objname = objname; + c.errstring = errstring; + c.malloced = mallocedp; + c.errcode = &errcode; struct catch **const catchp = &CATCH_HOOK; - old = *catchp; + struct catch *const old = *catchp; + *catchp = &c; + /* Do not save the signal mask. */ - errcode = __sigsetjmp (c.env, 0); - if (__builtin_expect (errcode, 0) == 0) + if (__builtin_expect (__sigsetjmp (c.env, 0), 0) == 0) { - *catchp = &c; (*operate) (args); *catchp = old; *objname = NULL; @@ -182,12 +192,10 @@ _dl_catch_error (const char **objname, const char **errstring, return 0; } - /* We get here only if we longjmp'd out of OPERATE. */ + /* We get here only if we longjmp'd out of OPERATE. _dl_signal_error has + already stored values into *OBJNAME, *ERRSTRING, and *MALLOCEDP. */ *catchp = old; - *objname = c.objname; - *errstring = c.errstring; - *mallocedp = c.malloced; - return errcode == -1 ? 0 : errcode; + return errcode; } diff --git a/elf/dl-fini.c b/elf/dl-fini.c index 6b245f0022..db5269c82f 100644 --- a/elf/dl-fini.c +++ b/elf/dl-fini.c @@ -254,7 +254,7 @@ _dl_fini (void) /* Next try the old-style destructor. */ if (l->l_info[DT_FINI] != NULL) - ((fini_t) DL_DT_FINI_ADDRESS (l, l->l_addr + l->l_info[DT_FINI]->d_un.d_ptr)) (); + DL_CALL_DT_FINI(l, l->l_addr + l->l_info[DT_FINI]->d_un.d_ptr); } #ifdef SHARED diff --git a/elf/dl-init.c b/elf/dl-init.c index a657eb6c40..40783684f2 100644 --- a/elf/dl-init.c +++ b/elf/dl-init.c @@ -61,13 +61,7 @@ call_init (struct link_map *l, int argc, char **argv, char **env) - the others in the DT_INIT_ARRAY. */ if (l->l_info[DT_INIT] != NULL) - { - init_t init = (init_t) DL_DT_INIT_ADDRESS - (l, l->l_addr + l->l_info[DT_INIT]->d_un.d_ptr); - - /* Call the function. */ - init (argc, argv, env); - } + DL_CALL_DT_INIT(l, l->l_addr + l->l_info[DT_INIT]->d_un.d_ptr, argc, argv, env); /* Next see whether there is an array with initialization functions. */ ElfW(Dyn) *init_array = l->l_info[DT_INIT_ARRAY]; diff --git a/elf/dl-libc.c b/elf/dl-libc.c index aba0d1af19..397d898993 100644 --- a/elf/dl-libc.c +++ b/elf/dl-libc.c @@ -286,6 +286,7 @@ libc_freeres_fn (free_mem) /* Free the initfini dependency list. */ if (l->l_free_initfini) free (l->l_initfini); + l->l_initfini = NULL; } if (__builtin_expect (GL(dl_ns)[ns]._ns_global_scope_alloc, 0) != 0 diff --git a/elf/dl-load.c b/elf/dl-load.c index 6a73f27345..d3e1cf8f9c 100644 --- a/elf/dl-load.c +++ b/elf/dl-load.c @@ -481,14 +481,19 @@ static size_t max_dirnamelen; static struct r_search_path_elem ** fillin_rpath (char *rpath, struct r_search_path_elem **result, const char *sep, - int check_trusted, const char *what, const char *where) + int check_trusted, const char *what, const char *where, + struct link_map *l) { char *cp; size_t nelems = 0; + char *to_free; while ((cp = __strsep (&rpath, sep)) != NULL) { struct r_search_path_elem *dirp; + + to_free = cp = expand_dynamic_string_token (l, cp, 1); + size_t len = strlen (cp); /* `strsep' can pass an empty string. This has to be @@ -509,7 +514,10 @@ fillin_rpath (char *rpath, struct r_search_path_elem **result, const char *sep, /* Make sure we don't use untrusted directories if we run SUID. */ if (__builtin_expect (check_trusted, 0) && !is_trusted_path (cp, len)) - continue; + { + free (to_free); + continue; + } /* See if this directory is already known. */ for (dirp = GL(dl_all_dirs); dirp != NULL; dirp = dirp->next) @@ -570,6 +578,7 @@ fillin_rpath (char *rpath, struct r_search_path_elem **result, const char *sep, /* Put it in the result array. */ result[nelems++] = dirp; } + free (to_free); } /* Terminate the array. */ @@ -625,9 +634,8 @@ decompose_rpath (struct r_search_path_struct *sps, while (*inhp != '\0'); } - /* Make a writable copy. At the same time expand possible dynamic - string tokens. */ - copy = expand_dynamic_string_token (l, rpath, 1); + /* Make a writable copy. */ + copy = local_strdup (rpath); if (copy == NULL) { errstring = N_("cannot create RUNPATH/RPATH copy"); @@ -660,7 +668,7 @@ decompose_rpath (struct r_search_path_struct *sps, _dl_signal_error (ENOMEM, NULL, NULL, errstring); } - fillin_rpath (copy, result, ":", 0, what, where); + fillin_rpath (copy, result, ":", 0, what, where, l); /* Free the copied RPATH string. `fillin_rpath' make own copies if necessary. */ @@ -708,9 +716,7 @@ _dl_init_paths (const char *llp) const char *strp; struct r_search_path_elem *pelem, **aelem; size_t round_size; -#ifdef SHARED - struct link_map *l; -#endif + struct link_map __attribute__ ((unused)) *l = NULL; /* Initialize to please the compiler. */ const char *errstring = NULL; @@ -865,7 +871,7 @@ _dl_init_paths (const char *llp) (void) fillin_rpath (llp_tmp, env_path_list.dirs, ":;", INTUSE(__libc_enable_secure), "LD_LIBRARY_PATH", - NULL); + NULL, l); if (env_path_list.dirs[0] == NULL) { diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c index 39f463eae1..f869dcfa96 100644 --- a/elf/dl-lookup.c +++ b/elf/dl-lookup.c @@ -746,7 +746,7 @@ _dl_lookup_symbol_x (const char *undef_name, struct link_map *undef_map, contain the needed symbol. This code is never reached for unversioned lookups. */ assert (version != NULL); - const char *reference_name = undef_map ? undef_map->l_name : NULL; + const char *reference_name = undef_map ? undef_map->l_name : ""; /* XXX We cannot translate the message. */ _dl_signal_cerror (0, DSO_FILENAME (reference_name), diff --git a/elf/dl-misc.c b/elf/dl-misc.c index 5fc13a44a4..b529af3f4b 100644 --- a/elf/dl-misc.c +++ b/elf/dl-misc.c @@ -19,6 +19,7 @@ #include <assert.h> #include <fcntl.h> #include <ldsodefs.h> +#include <libc-symbols.h> #include <limits.h> #include <link.h> #include <stdarg.h> @@ -364,3 +365,144 @@ _dl_higher_prime_number (unsigned long int n) return *low; } + +/* To support accessing TLS variables from signal handlers, we need an + async signal safe memory allocator. These routines are never + themselves invoked reentrantly (all calls to them are surrounded by + signal masks) but may be invoked concurrently from many threads. + The current implementation is not particularly performant nor space + efficient, but it will be used rarely (and only in binaries that use + dlopen.) The API matches that of malloc() and friends. */ + +struct __signal_safe_allocator_header +{ + size_t size; + void *start; +}; + +static inline struct __signal_safe_allocator_header * +ptr_to_signal_safe_allocator_header (void *ptr) +{ + return (struct __signal_safe_allocator_header *) + ((char *) (ptr) - sizeof (struct __signal_safe_allocator_header)); +} + +void *weak_function +__signal_safe_memalign (size_t boundary, size_t size) +{ + struct __signal_safe_allocator_header *header; + + if (boundary < sizeof (*header)) + boundary = sizeof (*header); + + /* Boundary must be a power of two. */ + if (!powerof2 (boundary)) + return NULL; + + size_t pg = GLRO (dl_pagesize); + size_t padded_size; + if (boundary <= pg) + { + /* We'll get a pointer certainly aligned to boundary, so just + add one more boundary-sized chunk to hold the header. */ + padded_size = roundup (size, boundary) + boundary; + } + else + { + /* If we want K pages aligned to a J-page boundary, K+J+1 pages + contains at least one such region that isn't directly at the start + (so we can place the header.) This is wasteful, but you're the one + who wanted 64K-aligned TLS. */ + padded_size = roundup (size, pg) + boundary + pg; + } + + + size_t actual_size = roundup (padded_size, pg); + void *actual = mmap (NULL, actual_size, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + if (actual == MAP_FAILED) + return NULL; + + if (boundary <= pg) + { + header = actual + boundary - sizeof (*header); + } + else + { + intptr_t actual_pg = ((intptr_t) actual) / pg; + intptr_t boundary_pg = boundary / pg; + intptr_t start_pg = actual_pg + boundary_pg; + start_pg -= start_pg % boundary_pg; + if (start_pg > (actual_pg + 1)) + { + int ret = munmap (actual, (start_pg - actual_pg - 1) * pg); + assert (ret == 0); + actual = (void *) ((start_pg - 1) * pg); + } + char *start = (void *) (start_pg * pg); + header = ptr_to_signal_safe_allocator_header (start); + } + + header->size = actual_size; + header->start = actual; + void *ptr = header; + ptr += sizeof (*header); + if (((intptr_t) ptr) % boundary != 0) + _dl_fatal_printf ("__signal_safe_memalign produced incorrect alignment\n"); + return ptr; +} + +void * weak_function +__signal_safe_malloc (size_t size) +{ + return __signal_safe_memalign (1, size); +} + +void weak_function +__signal_safe_free (void *ptr) +{ + if (ptr == NULL) + return; + + struct __signal_safe_allocator_header *header + = ptr_to_signal_safe_allocator_header (ptr); + int ret = munmap (header->start, header->size); + + assert (ret == 0); +} + +void * weak_function +__signal_safe_realloc (void *ptr, size_t size) +{ + if (size == 0) + { + __signal_safe_free (ptr); + return NULL; + } + if (ptr == NULL) + return __signal_safe_malloc (size); + + struct __signal_safe_allocator_header *header + = ptr_to_signal_safe_allocator_header (ptr); + size_t old_size = header->size; + if (old_size - sizeof (*header) >= size) + return ptr; + + void *new_ptr = __signal_safe_malloc (size); + if (new_ptr == NULL) + return NULL; + + memcpy (new_ptr, ptr, old_size); + __signal_safe_free (ptr); + + return new_ptr; +} + +void * weak_function +__signal_safe_calloc (size_t nmemb, size_t size) +{ + void *ptr = __signal_safe_malloc (nmemb * size); + if (ptr == NULL) + return NULL; + return memset (ptr, 0, nmemb * size); +} diff --git a/elf/dl-object.c b/elf/dl-object.c index 0f594d25e6..26d4f44375 100644 --- a/elf/dl-object.c +++ b/elf/dl-object.c @@ -88,7 +88,13 @@ _dl_new_object (char *realname, const char *libname, int type, /* newname->next = NULL; We use calloc therefore not necessary. */ newname->dont_free = 1; - new->l_name = realname; + /* When we create the executable link map, or a VDSO link map, we start + with "" for the l_name. In these cases "" points to ld.so rodata + and won't get dumped during core file generation. Therefore to assist + gdb and to create more self-contained core files we adjust l_name to + point at the newly allocated copy (which will get dumped) instead of + the ld.so rodata copy. */ + new->l_name = *realname ? realname : (char *) newname->name + libname_len - 1; new->l_type = type; /* If we set the bit now since we know it is never used we avoid dirtying the cache line later. */ diff --git a/elf/dl-support.c b/elf/dl-support.c index 5a082feb7a..2023bd031c 100644 --- a/elf/dl-support.c +++ b/elf/dl-support.c @@ -167,6 +167,9 @@ size_t _dl_phnum; uint64_t _dl_hwcap __attribute__ ((nocommon)); uint64_t _dl_hwcap2 __attribute__ ((nocommon)); +/* The value of the FPU control word the kernel will preset in hardware. */ +fpu_control_t _dl_fpu_control = _FPU_DEFAULT; + /* This is not initialized to HWCAP_IMPORTANT, matching the definition of _dl_important_hwcaps, below, where no hwcap strings are ever used. This mask is still used to mediate the lookups in the cache @@ -253,6 +256,9 @@ _dl_aux_init (ElfW(auxv_t) *av) case AT_HWCAP2: GLRO(dl_hwcap2) = (unsigned long int) av->a_un.a_val; break; + case AT_FPUCW: + GLRO(dl_fpu_control) = av->a_un.a_val; + break; #ifdef NEED_DL_SYSINFO case AT_SYSINFO: GL(dl_sysinfo) = av->a_un.a_val; diff --git a/elf/dl-tls.c b/elf/dl-tls.c index 576d9a1465..12e6e8f3e0 100644 --- a/elf/dl-tls.c +++ b/elf/dl-tls.c @@ -293,7 +293,7 @@ allocate_dtv (void *result) initial set of modules. This should avoid in most cases expansions of the dtv. */ dtv_length = GL(dl_tls_max_dtv_idx) + DTV_SURPLUS; - dtv = calloc (dtv_length + 2, sizeof (dtv_t)); + dtv = __signal_safe_calloc (dtv_length + 2, sizeof (dtv_t)); if (dtv != NULL) { /* This is the initial length of the dtv. */ @@ -463,6 +463,18 @@ _dl_allocate_tls (void *mem) } rtld_hidden_def (_dl_allocate_tls) +void +internal_function +_dl_clear_dtv (dtv_t *dtv) +{ + for (size_t cnt = 0; cnt < dtv[-1].counter; ++cnt) + if (! dtv[1 + cnt].pointer.is_static + && dtv[1 + cnt].pointer.val != TLS_DTV_UNALLOCATED) + __signal_safe_free (dtv[1 + cnt].pointer.val); + memset (dtv, '\0', (dtv[-1].counter + 1) * sizeof (dtv_t)); +} + +rtld_hidden_def (_dl_clear_dtv) #ifndef SHARED extern dtv_t _dl_static_dtv[]; @@ -479,11 +491,11 @@ _dl_deallocate_tls (void *tcb, bool dealloc_tcb) for (size_t cnt = 0; cnt < dtv[-1].counter; ++cnt) if (! dtv[1 + cnt].pointer.is_static && dtv[1 + cnt].pointer.val != TLS_DTV_UNALLOCATED) - free (dtv[1 + cnt].pointer.val); + __signal_safe_free (dtv[1 + cnt].pointer.val); /* The array starts with dtv[-1]. */ if (dtv != GL(dl_initial_dtv)) - free (dtv - 1); + __signal_safe_free (dtv - 1); if (dealloc_tcb) { @@ -525,8 +537,7 @@ static void * allocate_and_init (struct link_map *map) { void *newp; - - newp = __libc_memalign (map->l_tls_align, map->l_tls_blocksize); + newp = __signal_safe_memalign (map->l_tls_align, map->l_tls_blocksize); if (newp == NULL) oom (); @@ -596,25 +607,27 @@ _dl_update_slotinfo (unsigned long int req_modid) if (gen <= dtv[0].counter) continue; + size_t modid = total + cnt; + /* If there is no map this means the entry is empty. */ 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 >= modid + && !dtv[modid].pointer.is_static + && dtv[modid].pointer.val != TLS_DTV_UNALLOCATED) { - free (dtv[total + cnt].pointer.val); - dtv[total + cnt].pointer.val = TLS_DTV_UNALLOCATED; + __signal_safe_free (dtv[modid].pointer.val); + dtv[modid].pointer.val = TLS_DTV_UNALLOCATED; } continue; } + assert (modid == map->l_tls_modid); /* Check whether the current dtv array is large enough. */ - size_t modid = map->l_tls_modid; - assert (total + cnt == modid); if (dtv[-1].counter < modid) { /* Reallocate the dtv. */ @@ -628,17 +641,18 @@ _dl_update_slotinfo (unsigned long int req_modid) { /* This is the initial dtv that was allocated during rtld startup using the dl-minimal.c - malloc instead of the real malloc. We can't + malloc instead of the real allocator. We can't free it, we have to abandon the old storage. */ - newp = malloc ((2 + newsize) * sizeof (dtv_t)); + newp = __signal_safe_malloc ( + (2 + newsize) * sizeof (dtv_t)); if (newp == NULL) oom (); memcpy (newp, &dtv[-1], (2 + oldsize) * sizeof (dtv_t)); } else { - newp = realloc (&dtv[-1], + newp = __signal_safe_realloc (&dtv[-1], (2 + newsize) * sizeof (dtv_t)); if (newp == NULL) oom (); @@ -668,7 +682,7 @@ _dl_update_slotinfo (unsigned long int req_modid) deallocate even if it is this dtv entry we are supposed to load. The reason is that we call memalign and not malloc. */ - free (dtv[modid].pointer.val); + __signal_safe_free (dtv[modid].pointer.val); /* This module is loaded dynamically- We defer memory allocation. */ @@ -1383,6 +1383,7 @@ typedef struct #define EF_MIPS_64BIT_WHIRL 16 #define EF_MIPS_ABI2 32 #define EF_MIPS_ABI_ON32 64 +#define EF_MIPS_NAN2008 1024 /* Uses IEEE 754-2008 NaN encoding. */ #define EF_MIPS_ARCH 0xf0000000 /* MIPS architecture level. */ /* Legal values for MIPS architecture level. */ @@ -2251,6 +2252,17 @@ typedef Elf32_Addr Elf32_Conflict; #define R_PPC64_DTPREL16_HIGHERA 104 /* half16 (sym+add)@dtprel@highera */ #define R_PPC64_DTPREL16_HIGHEST 105 /* half16 (sym+add)@dtprel@highest */ #define R_PPC64_DTPREL16_HIGHESTA 106 /* half16 (sym+add)@dtprel@highesta */ +#define R_PPC64_TLSGD 107 /* none (sym+add)@tlsgd */ +#define R_PPC64_TLSLD 108 /* none (sym+add)@tlsld */ +#define R_PPC64_TOCSAVE 109 /* none */ + +/* Added when HA and HI relocs were changed to report overflows. */ +#define R_PPC64_ADDR16_HIGH 110 +#define R_PPC64_ADDR16_HIGHA 111 +#define R_PPC64_TPREL16_HIGH 112 +#define R_PPC64_TPREL16_HIGHA 113 +#define R_PPC64_DTPREL16_HIGH 114 +#define R_PPC64_DTPREL16_HIGHA 115 /* GNU extension to support local ifunc. */ #define R_PPC64_JMP_IREL 247 @@ -2260,12 +2272,29 @@ typedef Elf32_Addr Elf32_Conflict; #define R_PPC64_REL16_HI 251 /* half16 (sym+add-.)@h */ #define R_PPC64_REL16_HA 252 /* half16 (sym+add-.)@ha */ +/* e_flags bits specifying ABI. + 1 for original function descriptor using ABI, + 2 for revised ABI without function descriptors, + 0 for unspecified or not using any features affected by the differences. */ +#define EF_PPC64_ABI 3 + /* PowerPC64 specific values for the Dyn d_tag field. */ #define DT_PPC64_GLINK (DT_LOPROC + 0) #define DT_PPC64_OPD (DT_LOPROC + 1) #define DT_PPC64_OPDSZ (DT_LOPROC + 2) +#define DT_PPC64_OPT (DT_LOPROC + 3) #define DT_PPC64_NUM 3 +/* PowerPC64 specific values for the DT_PPC64_OPT Dyn entry. */ +#define PPC64_OPT_TLS 1 +#define PPC64_OPT_MULTI_TOC 2 + +/* PowerPC64 specific values for the Elf64_Sym st_other field. */ +#define STO_PPC64_LOCAL_BIT 5 +#define STO_PPC64_LOCAL_MASK (7 << STO_PPC64_LOCAL_BIT) +#define PPC64_LOCAL_ENTRY_OFFSET(other) \ + (((1 << (((other) & STO_PPC64_LOCAL_MASK) >> STO_PPC64_LOCAL_BIT)) >> 2) << 2) + /* ARM specific declarations */ @@ -2335,6 +2364,117 @@ typedef Elf32_Addr Elf32_Conflict; #define R_AARCH64_NONE 0 /* No relocation. */ #define R_AARCH64_ABS64 257 /* Direct 64 bit. */ #define R_AARCH64_ABS32 258 /* Direct 32 bit. */ +#define R_AARCH64_ABS16 259 /* Direct 16-bit. */ +#define R_AARCH64_PREL64 260 /* PC-relative 64-bit. */ +#define R_AARCH64_PREL32 261 /* PC-relative 32-bit. */ +#define R_AARCH64_PREL16 262 /* PC-relative 16-bit. */ +#define R_AARCH64_MOVW_UABS_G0 263 /* Dir. MOVZ imm. from bits 15:0. */ +#define R_AARCH64_MOVW_UABS_G0_NC 264 /* Likewise for MOVK; no check. */ +#define R_AARCH64_MOVW_UABS_G1 265 /* Dir. MOVZ imm. from bits 31:16. */ +#define R_AARCH64_MOVW_UABS_G1_NC 266 /* Likewise for MOVK; no check. */ +#define R_AARCH64_MOVW_UABS_G2 267 /* Dir. MOVZ imm. from bits 47:32. */ +#define R_AARCH64_MOVW_UABS_G2_NC 268 /* Likewise for MOVK; no check. */ +#define R_AARCH64_MOVW_UABS_G3 269 /* Dir. MOV{K,Z} imm. from 63:48. */ +#define R_AARCH64_MOVW_SABS_G0 270 /* Dir. MOV{N,Z} imm. from 15:0. */ +#define R_AARCH64_MOVW_SABS_G1 271 /* Dir. MOV{N,Z} imm. from 31:16. */ +#define R_AARCH64_MOVW_SABS_G2 272 /* Dir. MOV{N,Z} imm. from 47:32. */ +#define R_AARCH64_LD_PREL_LO19 273 /* PC-rel. LD imm. from bits 20:2. */ +#define R_AARCH64_ADR_PREL_LO21 274 /* PC-rel. ADR imm. from bits 20:0. */ +#define R_AARCH64_ADR_PREL_PG_HI21 275 /* Page-rel. ADRP imm. from 32:12. */ +#define R_AARCH64_ADR_PREL_PG_HI21_NC 276 /* Likewise; no overflow check. */ +#define R_AARCH64_ADD_ABS_LO12_NC 277 /* Dir. ADD imm. from bits 11:0. */ +#define R_AARCH64_LDST8_ABS_LO12_NC 278 /* Likewise for LD/ST; no check. */ +#define R_AARCH64_TSTBR14 279 /* PC-rel. TBZ/TBNZ imm. from 15:2. */ +#define R_AARCH64_CONDBR19 280 /* PC-rel. cond. br. imm. from 20:2. */ +#define R_AARCH64_JUMP26 282 /* PC-rel. B imm. from bits 27:2. */ +#define R_AARCH64_CALL26 283 /* Likewise for CALL. */ +#define R_AARCH64_LDST16_ABS_LO12_NC 284 /* Dir. ADD imm. from bits 11:1. */ +#define R_AARCH64_LDST32_ABS_LO12_NC 285 /* Likewise for bits 11:2. */ +#define R_AARCH64_LDST64_ABS_LO12_NC 286 /* Likewise for bits 11:3. */ +#define R_AARCH64_MOVW_PREL_G0 287 /* PC-rel. MOV{N,Z} imm. from 15:0. */ +#define R_AARCH64_MOVW_PREL_G0_NC 288 /* Likewise for MOVK; no check. */ +#define R_AARCH64_MOVW_PREL_G1 289 /* PC-rel. MOV{N,Z} imm. from 31:16. */ +#define R_AARCH64_MOVW_PREL_G1_NC 290 /* Likewise for MOVK; no check. */ +#define R_AARCH64_MOVW_PREL_G2 291 /* PC-rel. MOV{N,Z} imm. from 47:32. */ +#define R_AARCH64_MOVW_PREL_G2_NC 292 /* Likewise for MOVK; no check. */ +#define R_AARCH64_MOVW_PREL_G3 293 /* PC-rel. MOV{N,Z} imm. from 63:48. */ +#define R_AARCH64_LDST128_ABS_LO12_NC 299 /* Dir. ADD imm. from bits 11:4. */ +#define R_AARCH64_MOVW_GOTOFF_G0 300 /* GOT-rel. off. MOV{N,Z} imm. 15:0. */ +#define R_AARCH64_MOVW_GOTOFF_G0_NC 301 /* Likewise for MOVK; no check. */ +#define R_AARCH64_MOVW_GOTOFF_G1 302 /* GOT-rel. o. MOV{N,Z} imm. 31:16. */ +#define R_AARCH64_MOVW_GOTOFF_G1_NC 303 /* Likewise for MOVK; no check. */ +#define R_AARCH64_MOVW_GOTOFF_G2 304 /* GOT-rel. o. MOV{N,Z} imm. 47:32. */ +#define R_AARCH64_MOVW_GOTOFF_G2_NC 305 /* Likewise for MOVK; no check. */ +#define R_AARCH64_MOVW_GOTOFF_G3 306 /* GOT-rel. o. MOV{N,Z} imm. 63:48. */ +#define R_AARCH64_GOTREL64 307 /* GOT-relative 64-bit. */ +#define R_AARCH64_GOTREL32 308 /* GOT-relative 32-bit. */ +#define R_AARCH64_GOT_LD_PREL19 309 /* PC-rel. GOT off. load imm. 20:2. */ +#define R_AARCH64_LD64_GOTOFF_LO15 310 /* GOT-rel. off. LD/ST imm. 14:3. */ +#define R_AARCH64_ADR_GOT_PAGE 311 /* P-page-rel. GOT off. ADRP 32:12. */ +#define R_AARCH64_LD64_GOT_LO12_NC 312 /* Dir. GOT off. LD/ST imm. 11:3. */ +#define R_AARCH64_LD64_GOTPAGE_LO15 313 /* GOT-page-rel. GOT off. LD/ST 14:3 */ +#define R_AARCH64_TLSGD_ADR_PREL21 512 /* PC-relative ADR imm. 20:0. */ +#define R_AARCH64_TLSGD_ADR_PAGE21 513 /* page-rel. ADRP imm. 32:12. */ +#define R_AARCH64_TLSGD_ADD_LO12_NC 514 /* direct ADD imm. from 11:0. */ +#define R_AARCH64_TLSGD_MOVW_G1 515 /* GOT-rel. MOV{N,Z} 31:16. */ +#define R_AARCH64_TLSGD_MOVW_G0_NC 516 /* GOT-rel. MOVK imm. 15:0. */ +#define R_AARCH64_TLSLD_ADR_PREL21 517 /* Like 512; local dynamic model. */ +#define R_AARCH64_TLSLD_ADR_PAGE21 518 /* Like 513; local dynamic model. */ +#define R_AARCH64_TLSLD_ADD_LO12_NC 519 /* Like 514; local dynamic model. */ +#define R_AARCH64_TLSLD_MOVW_G1 520 /* Like 515; local dynamic model. */ +#define R_AARCH64_TLSLD_MOVW_G0_NC 521 /* Like 516; local dynamic model. */ +#define R_AARCH64_TLSLD_LD_PREL19 522 /* TLS PC-rel. load imm. 20:2. */ +#define R_AARCH64_TLSLD_MOVW_DTPREL_G2 523 /* TLS DTP-rel. MOV{N,Z} 47:32. */ +#define R_AARCH64_TLSLD_MOVW_DTPREL_G1 524 /* TLS DTP-rel. MOV{N,Z} 31:16. */ +#define R_AARCH64_TLSLD_MOVW_DTPREL_G1_NC 525 /* Likewise; MOVK; no check. */ +#define R_AARCH64_TLSLD_MOVW_DTPREL_G0 526 /* TLS DTP-rel. MOV{N,Z} 15:0. */ +#define R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC 527 /* Likewise; MOVK; no check. */ +#define R_AARCH64_TLSLD_ADD_DTPREL_HI12 528 /* DTP-rel. ADD imm. from 23:12. */ +#define R_AARCH64_TLSLD_ADD_DTPREL_LO12 529 /* DTP-rel. ADD imm. from 11:0. */ +#define R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC 530 /* Likewise; no ovfl. check. */ +#define R_AARCH64_TLSLD_LDST8_DTPREL_LO12 531 /* DTP-rel. LD/ST imm. 11:0. */ +#define R_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC 532 /* Likewise; no check. */ +#define R_AARCH64_TLSLD_LDST16_DTPREL_LO12 533 /* DTP-rel. LD/ST imm. 11:1. */ +#define R_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC 534 /* Likewise; no check. */ +#define R_AARCH64_TLSLD_LDST32_DTPREL_LO12 535 /* DTP-rel. LD/ST imm. 11:2. */ +#define R_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC 536 /* Likewise; no check. */ +#define R_AARCH64_TLSLD_LDST64_DTPREL_LO12 537 /* DTP-rel. LD/ST imm. 11:3. */ +#define R_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC 538 /* Likewise; no check. */ +#define R_AARCH64_TLSIE_MOVW_GOTTPREL_G1 539 /* GOT-rel. MOV{N,Z} 31:16. */ +#define R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC 540 /* GOT-rel. MOVK 15:0. */ +#define R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 541 /* Page-rel. ADRP 32:12. */ +#define R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC 542 /* Direct LD off. 11:3. */ +#define R_AARCH64_TLSIE_LD_GOTTPREL_PREL19 543 /* PC-rel. load imm. 20:2. */ +#define R_AARCH64_TLSLE_MOVW_TPREL_G2 544 /* TLS TP-rel. MOV{N,Z} 47:32. */ +#define R_AARCH64_TLSLE_MOVW_TPREL_G1 545 /* TLS TP-rel. MOV{N,Z} 31:16. */ +#define R_AARCH64_TLSLE_MOVW_TPREL_G1_NC 546 /* Likewise; MOVK; no check. */ +#define R_AARCH64_TLSLE_MOVW_TPREL_G0 547 /* TLS TP-rel. MOV{N,Z} 15:0. */ +#define R_AARCH64_TLSLE_MOVW_TPREL_G0_NC 548 /* Likewise; MOVK; no check. */ +#define R_AARCH64_TLSLE_ADD_TPREL_HI12 549 /* TP-rel. ADD imm. 23:12. */ +#define R_AARCH64_TLSLE_ADD_TPREL_LO12 550 /* TP-rel. ADD imm. 11:0. */ +#define R_AARCH64_TLSLE_ADD_TPREL_LO12_NC 551 /* Likewise; no ovfl. check. */ +#define R_AARCH64_TLSLE_LDST8_TPREL_LO12 552 /* TP-rel. LD/ST off. 11:0. */ +#define R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC 553 /* Likewise; no ovfl. check. */ +#define R_AARCH64_TLSLE_LDST16_TPREL_LO12 554 /* TP-rel. LD/ST off. 11:1. */ +#define R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC 555 /* Likewise; no check. */ +#define R_AARCH64_TLSLE_LDST32_TPREL_LO12 556 /* TP-rel. LD/ST off. 11:2. */ +#define R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC 557 /* Likewise; no check. */ +#define R_AARCH64_TLSLE_LDST64_TPREL_LO12 558 /* TP-rel. LD/ST off. 11:3. */ +#define R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC 559 /* Likewise; no check. */ +#define R_AARCH64_TLSDESC_LD_PREL19 560 /* PC-rel. load immediate 20:2. */ +#define R_AARCH64_TLSDESC_ADR_PREL21 561 /* PC-rel. ADR immediate 20:0. */ +#define R_AARCH64_TLSDESC_ADR_PAGE21 562 /* Page-rel. ADRP imm. 32:12. */ +#define R_AARCH64_TLSDESC_LD64_LO12 563 /* Direct LD off. from 11:3. */ +#define R_AARCH64_TLSDESC_ADD_LO12 564 /* Direct ADD imm. from 11:0. */ +#define R_AARCH64_TLSDESC_OFF_G1 565 /* GOT-rel. MOV{N,Z} imm. 31:16. */ +#define R_AARCH64_TLSDESC_OFF_G0_NC 566 /* GOT-rel. MOVK imm. 15:0; no ck. */ +#define R_AARCH64_TLSDESC_LDR 567 /* Relax LDR. */ +#define R_AARCH64_TLSDESC_ADD 568 /* Relax ADD. */ +#define R_AARCH64_TLSDESC_CALL 569 /* Relax BLR. */ +#define R_AARCH64_TLSLE_LDST128_TPREL_LO12 570 /* TP-rel. LD/ST off. 11:4. */ +#define R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC 571 /* Likewise; no check. */ +#define R_AARCH64_TLSLD_LDST128_DTPREL_LO12 572 /* DTP-rel. LD/ST imm. 11:4. */ +#define R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC 573 /* Likewise; no check. */ #define R_AARCH64_COPY 1024 /* Copy symbol at runtime. */ #define R_AARCH64_GLOB_DAT 1025 /* Create GOT entry. */ #define R_AARCH64_JUMP_SLOT 1026 /* Create PLT entry. */ @@ -2343,6 +2483,7 @@ typedef Elf32_Addr Elf32_Conflict; #define R_AARCH64_TLS_DTPREL64 1029 /* Module-relative offset, 64 bit. */ #define R_AARCH64_TLS_TPREL64 1030 /* TP-relative offset, 64 bit. */ #define R_AARCH64_TLSDESC 1031 /* TLS Descriptor. */ +#define R_AARCH64_IRELATIVE 1032 /* STT_GNU_IFUNC relocation. */ /* ARM relocs. */ diff --git a/elf/ldd.bash.in b/elf/ldd.bash.in index 39aeca249d..c4a1a15139 100644 --- a/elf/ldd.bash.in +++ b/elf/ldd.bash.in @@ -106,19 +106,18 @@ if test "$unused" = yes; then add_env="$add_env LD_DEBUG=\"$LD_DEBUG${LD_DEBUG:+,}unused\"" fi -# The following use of cat is needed to make ldd work in SELinux -# environments where the executed program might not have permissions -# to write to the console/tty. But only bash 3.x supports the pipefail -# option, and we don't bother to handle the case for older bash versions. -if set -o pipefail 2> /dev/null; then - try_trace() { - eval $add_env '"$@"' | cat - } -else - try_trace() { - eval $add_env '"$@"' - } -fi +# The following command substitution is needed to make ldd work in SELinux +# environments where the RTLD might not have permission to write to the +# terminal. The extra "x" character prevents the shell from trimming trailing +# newlines from command substitution results. This function is defined as a +# subshell compound list (using "(...)") to prevent parameter assignments from +# affecting the calling shell execution environment. +try_trace() ( + output=$(eval $add_env '"$@"' 2>&1; rc=$?; printf 'x'; exit $rc) + rc=$? + printf '%s' "${output%x}" + return $rc +) case $# in 0) diff --git a/elf/rtld.c b/elf/rtld.c index 91da88cdd1..3d207a3fa0 100644 --- a/elf/rtld.c +++ b/elf/rtld.c @@ -816,8 +816,8 @@ do_preload (char *fname, struct link_map *main_map, const char *where) if (__builtin_expect (err_str != NULL, 0)) { _dl_error_printf ("\ -ERROR: ld.so: object '%s' from %s cannot be preloaded: ignored.\n", - fname, where); +ERROR: ld.so: object '%s' from %s cannot be preloaded (%s): ignored.\n", + fname, where, err_str); /* No need to call free, this is still before the libc's malloc is used. */ } @@ -1118,6 +1118,9 @@ of this helper program; chances are you did not intend to run this program.\n\ case AT_ENTRY: av->a_un.a_val = *user_entry; break; + case AT_EXECFN: + av->a_un.a_val = (uintptr_t) _dl_argv[0]; + break; } #endif } @@ -2217,10 +2220,6 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n", _dl_start_profile (); } -#ifndef NONTLS_INIT_TP -# define NONTLS_INIT_TP do { } while (0) -#endif - if (!was_tls_init_tp_called && GL(dl_tls_max_dtv_idx) > 0) ++GL(dl_tls_generation); diff --git a/elf/tlsdeschtab.h b/elf/tlsdeschtab.h index 155f4fdd9b..8ce8249b92 100644 --- a/elf/tlsdeschtab.h +++ b/elf/tlsdeschtab.h @@ -102,6 +102,12 @@ _dl_make_tlsdesc_dynamic (struct link_map *map, size_t ti_offset) test.tlsinfo.ti_module = map->l_tls_modid; test.tlsinfo.ti_offset = ti_offset; entry = htab_find_slot (ht, &test, 1, hash_tlsdesc, eq_tlsdesc); + if (! entry) + { + __rtld_lock_unlock_recursive (GL(dl_load_lock)); + return 0; + } + if (*entry) { td = *entry; diff --git a/elf/tst-auxv.c b/elf/tst-auxv.c new file mode 100644 index 0000000000..0fb3ad5345 --- /dev/null +++ b/elf/tst-auxv.c @@ -0,0 +1,69 @@ +/* Copyright (C) 2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <elf.h> +#include <errno.h> +#include <link.h> +#include <string.h> +#include <stdio.h> +#include <unistd.h> +#include <misc/sys/auxv.h> + +static int +do_test (int argc, char *argv[]) +{ + errno = 0; + const char *execfn = (const char *) getauxval (AT_NULL); + + if (errno != ENOENT) + { + printf ("errno is %d rather than %d (ENOENT) on failure\n", errno, + ENOENT); + return 1; + } + + if (execfn != NULL) + { + printf ("getauxval return value is nonzero on failure\n"); + return 1; + } + + errno = 0; + execfn = (const char *) getauxval (AT_EXECFN); + + if (execfn == NULL) + { + printf ("No AT_EXECFN found, AT_EXECFN test skipped\n"); + return 0; + } + + if (errno != 0) + { + printf ("errno erroneously set to %d on success\n", errno); + return 1; + } + + if (strcmp (argv[0], execfn) != 0) + { + printf ("Mismatch: argv[0]: %s vs. AT_EXECFN: %s\n", argv[0], execfn); + return 1; + } + + return 0; +} + +#include "../test-skeleton.c" diff --git a/elf/tst-ptrguard1-static.c b/elf/tst-ptrguard1-static.c new file mode 100644 index 0000000000..7aff3b7b5d --- /dev/null +++ b/elf/tst-ptrguard1-static.c @@ -0,0 +1 @@ +#include "tst-ptrguard1.c" diff --git a/elf/tst-ptrguard1.c b/elf/tst-ptrguard1.c new file mode 100644 index 0000000000..c344a04db1 --- /dev/null +++ b/elf/tst-ptrguard1.c @@ -0,0 +1,202 @@ +/* Copyright (C) 2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/wait.h> +#include <stackguard-macros.h> +#include <tls.h> +#include <unistd.h> + +#ifndef POINTER_CHK_GUARD +extern uintptr_t __pointer_chk_guard; +# define POINTER_CHK_GUARD __pointer_chk_guard +#endif + +static const char *command; +static bool child; +static uintptr_t ptr_chk_guard_copy; +static bool ptr_chk_guard_copy_set; +static int fds[2]; + +static void __attribute__ ((constructor)) +con (void) +{ + ptr_chk_guard_copy = POINTER_CHK_GUARD; + ptr_chk_guard_copy_set = true; +} + +static int +uintptr_t_cmp (const void *a, const void *b) +{ + if (*(uintptr_t *) a < *(uintptr_t *) b) + return 1; + if (*(uintptr_t *) a > *(uintptr_t *) b) + return -1; + return 0; +} + +static int +do_test (void) +{ + if (!ptr_chk_guard_copy_set) + { + puts ("constructor has not been run"); + return 1; + } + + if (ptr_chk_guard_copy != POINTER_CHK_GUARD) + { + puts ("POINTER_CHK_GUARD changed between constructor and do_test"); + return 1; + } + + if (child) + { + write (2, &ptr_chk_guard_copy, sizeof (ptr_chk_guard_copy)); + return 0; + } + + if (command == NULL) + { + puts ("missing --command or --child argument"); + return 1; + } + +#define N 16 + uintptr_t child_ptr_chk_guards[N + 1]; + child_ptr_chk_guards[N] = ptr_chk_guard_copy; + int i; + for (i = 0; i < N; ++i) + { + if (pipe (fds) < 0) + { + printf ("couldn't create pipe: %m\n"); + return 1; + } + + pid_t pid = fork (); + if (pid < 0) + { + printf ("fork failed: %m\n"); + return 1; + } + + if (!pid) + { + if (ptr_chk_guard_copy != POINTER_CHK_GUARD) + { + puts ("POINTER_CHK_GUARD changed after fork"); + exit (1); + } + + close (fds[0]); + close (2); + dup2 (fds[1], 2); + close (fds[1]); + + system (command); + exit (0); + } + + close (fds[1]); + + if (TEMP_FAILURE_RETRY (read (fds[0], &child_ptr_chk_guards[i], + sizeof (uintptr_t))) != sizeof (uintptr_t)) + { + puts ("could not read ptr_chk_guard value from child"); + return 1; + } + + close (fds[0]); + + pid_t termpid; + int status; + termpid = TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)); + if (termpid == -1) + { + printf ("waitpid failed: %m\n"); + return 1; + } + else if (termpid != pid) + { + printf ("waitpid returned %ld != %ld\n", + (long int) termpid, (long int) pid); + return 1; + } + else if (!WIFEXITED (status) || WEXITSTATUS (status)) + { + puts ("child hasn't exited with exit status 0"); + return 1; + } + } + + qsort (child_ptr_chk_guards, N + 1, sizeof (uintptr_t), uintptr_t_cmp); + + /* The default pointer guard is the same as the default stack guard. + They are only set to default if dl_random is NULL. */ + uintptr_t default_guard = 0; + unsigned char *p = (unsigned char *) &default_guard; + p[sizeof (uintptr_t) - 1] = 255; + p[sizeof (uintptr_t) - 2] = '\n'; + p[0] = 0; + + /* Test if the pointer guard canaries are either randomized, + or equal to the default pointer guard value. + Even with randomized pointer guards it might happen + that the random number generator generates the same + values, but if that happens in more than half from + the 16 runs, something is very wrong. */ + int ndifferences = 0; + int ndefaults = 0; + for (i = 0; i < N; ++i) + { + if (child_ptr_chk_guards[i] != child_ptr_chk_guards[i+1]) + ndifferences++; + else if (child_ptr_chk_guards[i] == default_guard) + ndefaults++; + } + + printf ("differences %d defaults %d\n", ndifferences, ndefaults); + + if (ndifferences < N / 2 && ndefaults < N / 2) + { + puts ("pointer guard values are not randomized enough"); + puts ("nor equal to the default value"); + return 1; + } + + return 0; +} + +#define OPT_COMMAND 10000 +#define OPT_CHILD 10001 +#define CMDLINE_OPTIONS \ + { "command", required_argument, NULL, OPT_COMMAND }, \ + { "child", no_argument, NULL, OPT_CHILD }, +#define CMDLINE_PROCESS \ + case OPT_COMMAND: \ + command = optarg; \ + break; \ + case OPT_CHILD: \ + child = true; \ + break; +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/elf/tst-tls-dlinfo.c b/elf/tst-tls-dlinfo.c index 26c2811178..28661b19c2 100644 --- a/elf/tst-tls-dlinfo.c +++ b/elf/tst-tls-dlinfo.c @@ -2,8 +2,6 @@ #include <stdio.h> #include <stdlib.h> -#include <tls.h> - #define TEST_FUNCTION do_test () static int diff --git a/elf/tst-tls1.c b/elf/tst-tls1.c index 3b9b10f9aa..bec0a2ff26 100644 --- a/elf/tst-tls1.c +++ b/elf/tst-tls1.c @@ -1,8 +1,6 @@ /* glibc test for TLS in ld.so. */ #include <stdio.h> -#include <tls.h> - #include "tls-macros.h" diff --git a/elf/tst-tls10.h b/elf/tst-tls10.h index 2b5709af72..7c8c6a6391 100644 --- a/elf/tst-tls10.h +++ b/elf/tst-tls10.h @@ -1,4 +1,3 @@ -#include <tls.h> #include <stdlib.h> struct A diff --git a/elf/tst-tls14.c b/elf/tst-tls14.c index ffd31e97be..6bacb599dd 100644 --- a/elf/tst-tls14.c +++ b/elf/tst-tls14.c @@ -4,8 +4,6 @@ #include <stdio.h> #include <stdlib.h> -#include <tls.h> - #define AL 4096 struct foo { diff --git a/elf/tst-tls2.c b/elf/tst-tls2.c index 3d13272c08..d0b6d51402 100644 --- a/elf/tst-tls2.c +++ b/elf/tst-tls2.c @@ -1,8 +1,6 @@ /* glibc test for TLS in ld.so. */ #include <stdio.h> -#include <tls.h> - #include "tls-macros.h" diff --git a/elf/tst-tls3.c b/elf/tst-tls3.c index c5e501eb4e..ca96c6a073 100644 --- a/elf/tst-tls3.c +++ b/elf/tst-tls3.c @@ -1,8 +1,6 @@ /* glibc test for TLS in ld.so. */ #include <stdio.h> -#include <tls.h> - #include "tls-macros.h" diff --git a/elf/tst-tls4.c b/elf/tst-tls4.c index 4ae33db24d..63170c3478 100644 --- a/elf/tst-tls4.c +++ b/elf/tst-tls4.c @@ -2,8 +2,6 @@ #include <stdio.h> #include <stdlib.h> -#include <tls.h> - #define TEST_FUNCTION do_test () static int diff --git a/elf/tst-tls5.c b/elf/tst-tls5.c index 27b18294fb..76905c56db 100644 --- a/elf/tst-tls5.c +++ b/elf/tst-tls5.c @@ -2,8 +2,6 @@ #include <stdio.h> #include <stdlib.h> -#include <tls.h> - #define TEST_FUNCTION do_test () static int diff --git a/elf/tst-tls6.c b/elf/tst-tls6.c index 021622d9c7..9e6235f1d3 100644 --- a/elf/tst-tls6.c +++ b/elf/tst-tls6.c @@ -3,7 +3,6 @@ #include <stdlib.h> #include <link.h> -#include <tls.h> #define TEST_FUNCTION do_test () diff --git a/elf/tst-tls7.c b/elf/tst-tls7.c index 1edc2b6356..23a16e4489 100644 --- a/elf/tst-tls7.c +++ b/elf/tst-tls7.c @@ -3,7 +3,6 @@ #include <stdlib.h> #include <link.h> -#include <tls.h> #define TEST_FUNCTION do_test () diff --git a/elf/tst-tls8.c b/elf/tst-tls8.c index 36b1baca63..4bf3e3ffb5 100644 --- a/elf/tst-tls8.c +++ b/elf/tst-tls8.c @@ -3,7 +3,6 @@ #include <stdlib.h> #include <link.h> -#include <tls.h> #define TEST_FUNCTION do_test () diff --git a/elf/tst-tls9.c b/elf/tst-tls9.c index 12078518fa..6306fb5658 100644 --- a/elf/tst-tls9.c +++ b/elf/tst-tls9.c @@ -3,7 +3,6 @@ #include <stdlib.h> #include <link.h> -#include <tls.h> #define TEST_FUNCTION do_test () static int diff --git a/elf/tst-tlsmod1.c b/elf/tst-tlsmod1.c index 4d966c9472..8d9156791b 100644 --- a/elf/tst-tlsmod1.c +++ b/elf/tst-tlsmod1.c @@ -1,7 +1,5 @@ #include <stdio.h> -#include <tls.h> - #include "tls-macros.h" diff --git a/elf/tst-tlsmod13.c b/elf/tst-tlsmod13.c index 76da630a05..7712d8b8c8 100644 --- a/elf/tst-tlsmod13.c +++ b/elf/tst-tlsmod13.c @@ -1,5 +1,3 @@ -#include <tls.h> - __thread int a[2] __attribute__ ((tls_model ("initial-exec"))); int diff --git a/elf/tst-tlsmod13a.c b/elf/tst-tlsmod13a.c index d5515d4a15..ca4eaccbff 100644 --- a/elf/tst-tlsmod13a.c +++ b/elf/tst-tlsmod13a.c @@ -1,5 +1,3 @@ -#include <tls.h> - __thread int b[2] __attribute__ ((tls_model ("initial-exec"))); extern int foo (void); diff --git a/elf/tst-tlsmod14a.c b/elf/tst-tlsmod14a.c index 6806d3403c..824c06d1f9 100644 --- a/elf/tst-tlsmod14a.c +++ b/elf/tst-tlsmod14a.c @@ -1,8 +1,6 @@ #include <stdint.h> #include <stdio.h> -#include <tls.h> - #define AL 4096 struct foo { diff --git a/elf/tst-tlsmod16a.c b/elf/tst-tlsmod16a.c index c16e603c8b..4ec6a6c37d 100644 --- a/elf/tst-tlsmod16a.c +++ b/elf/tst-tlsmod16a.c @@ -1,3 +1 @@ -#include <tls.h> - int __thread tlsvar; diff --git a/elf/tst-tlsmod16b.c b/elf/tst-tlsmod16b.c index 7268c56bcb..1ecba26dbe 100644 --- a/elf/tst-tlsmod16b.c +++ b/elf/tst-tlsmod16b.c @@ -1,5 +1,3 @@ -#include <tls.h> - extern __thread int tlsvar __attribute__((tls_model("initial-exec"))); void * diff --git a/elf/tst-tlsmod2.c b/elf/tst-tlsmod2.c index 981923313c..40eb1407f8 100644 --- a/elf/tst-tlsmod2.c +++ b/elf/tst-tlsmod2.c @@ -1,7 +1,5 @@ #include <stdio.h> -#include <tls.h> - #include "tls-macros.h" diff --git a/elf/tst-tlsmod3.c b/elf/tst-tlsmod3.c index 5c456ee2da..6d186c47ee 100644 --- a/elf/tst-tlsmod3.c +++ b/elf/tst-tlsmod3.c @@ -1,7 +1,5 @@ #include <stdio.h> -#include <tls.h> - #include "tls-macros.h" extern int in_dso (int n, int *caller_foop); diff --git a/elf/tst-tlsmod4.c b/elf/tst-tlsmod4.c index dd95486618..86889aac7e 100644 --- a/elf/tst-tlsmod4.c +++ b/elf/tst-tlsmod4.c @@ -1,7 +1,5 @@ #include <stdio.h> -#include <tls.h> - #include "tls-macros.h" diff --git a/elf/tst-tlsmod5.c b/elf/tst-tlsmod5.c index 00d3a9d920..a97c7e5e0c 100644 --- a/elf/tst-tlsmod5.c +++ b/elf/tst-tlsmod5.c @@ -1,5 +1,3 @@ -#include <tls.h> - #include "tls-macros.h" COMMON_INT_DEF(foo); diff --git a/elf/tst-tlsmod6.c b/elf/tst-tlsmod6.c index 244d9ae485..e968596dd4 100644 --- a/elf/tst-tlsmod6.c +++ b/elf/tst-tlsmod6.c @@ -1,5 +1,3 @@ -#include <tls.h> - #include "tls-macros.h" COMMON_INT_DEF(bar); |