diff --git a/NEWS b/NEWS index 3c610744c9..698964bb9e 100644 --- a/NEWS +++ b/NEWS @@ -4,6 +4,25 @@ See the end for copying conditions. Please send GNU C library bug reports via using `glibc' in the "product" field. + +Version 2.34.1 + +The following bugs are resolved with this release: + + [12889] nptl: Fix race between pthread_kill and thread exit + [19193] nptl: pthread_kill, pthread_cancel should not fail after exit + [28036] Incorrect types for pthread_mutexattr_set/getrobust_np + [28182] _TIME_BITS=64 in C++ has issues with fcntl, ioctl, prctl + [28310] Do not use affinity mask for sysconf (_SC_NPROCESSORS_CONF) + [28340] ld.so crashes while loading a DSO with a read-only dynamic section + [28357] deadlock between pthread_create and ELF constructors + [28361] nptl: Avoid setxid deadlock with blocked signals in thread exit + [28407] pthread_kill assumes that kill and tgkill are equivalent + [28524] Conversion from ISO-2022-JP-3 with iconv may emit spurious NULs + [28607] Masked signals are delivered on thread exit + [28532] powerpc64[le]: CFI for assembly templated syscalls is incorrect + [28678] nptl/tst-create1 hangs sporadically + Version 2.34 diff --git a/bits/stdlib-bsearch.h b/bits/stdlib-bsearch.h index 4132dc6af0..e2fcea6e17 100644 --- a/bits/stdlib-bsearch.h +++ b/bits/stdlib-bsearch.h @@ -29,14 +29,23 @@ bsearch (const void *__key, const void *__base, size_t __nmemb, size_t __size, while (__l < __u) { __idx = (__l + __u) / 2; - __p = (void *) (((const char *) __base) + (__idx * __size)); + __p = (const void *) (((const char *) __base) + (__idx * __size)); __comparison = (*__compar) (__key, __p); if (__comparison < 0) __u = __idx; else if (__comparison > 0) __l = __idx + 1; else - return (void *) __p; + { +#if __GNUC_PREREQ(4, 6) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wcast-qual" +#endif + return (void *) __p; +#if __GNUC_PREREQ(4, 6) +# pragma GCC diagnostic pop +#endif + } } return NULL; diff --git a/elf/Makefile b/elf/Makefile index d05f410592..118d579c42 100644 --- a/elf/Makefile +++ b/elf/Makefile @@ -224,7 +224,7 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \ tst-tls-ie tst-tls-ie-dlmopen argv0test \ tst-glibc-hwcaps tst-glibc-hwcaps-prepend tst-glibc-hwcaps-mask \ tst-tls20 tst-tls21 tst-dlmopen-dlerror tst-dlmopen-gethostbyname \ - tst-dl-is_dso + tst-dl-is_dso tst-ro-dynamic # reldep9 tests-internal += loadtest unload unload2 circleload1 \ neededtest neededtest2 neededtest3 neededtest4 \ @@ -357,7 +357,7 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \ libmarkermod4-1 libmarkermod4-2 libmarkermod4-3 libmarkermod4-4 \ tst-tls20mod-bad tst-tls21mod tst-dlmopen-dlerror-mod \ tst-auxvalmod \ - tst-dlmopen-gethostbyname-mod \ + tst-dlmopen-gethostbyname-mod tst-ro-dynamic-mod \ # Most modules build with _ISOMAC defined, but those filtered out # depend on internal headers. @@ -399,8 +399,9 @@ endif modules-execstack-yes = tst-execstack-mod extra-test-objs += $(addsuffix .os,$(strip $(modules-names))) -# filtmod1.so, tst-big-note-lib.so have special rules. -modules-names-nobuild := filtmod1 tst-big-note-lib +# filtmod1.so, tst-big-note-lib.so, tst-ro-dynamic-mod.so have special +# rules. +modules-names-nobuild := filtmod1 tst-big-note-lib tst-ro-dynamic-mod tests += $(tests-static) @@ -1906,3 +1907,10 @@ $(objpfx)tst-getauxval-static.out: $(objpfx)tst-auxvalmod.so tst-getauxval-static-ENV = LD_LIBRARY_PATH=$(objpfx):$(common-objpfx) $(objpfx)tst-dlmopen-gethostbyname.out: $(objpfx)tst-dlmopen-gethostbyname-mod.so + +$(objpfx)tst-ro-dynamic: $(objpfx)tst-ro-dynamic-mod.so +$(objpfx)tst-ro-dynamic-mod.so: $(objpfx)tst-ro-dynamic-mod.os \ + tst-ro-dynamic-mod.map + $(LINK.o) -nostdlib -nostartfiles -shared -o $@ \ + -Wl,--script=tst-ro-dynamic-mod.map \ + $(objpfx)tst-ro-dynamic-mod.os diff --git a/elf/dl-close.c b/elf/dl-close.c index f39001cab9..cd7b9c9fe8 100644 --- a/elf/dl-close.c +++ b/elf/dl-close.c @@ -549,6 +549,9 @@ _dl_close_worker (struct link_map *map, bool force) size_t tls_free_end; tls_free_start = tls_free_end = NO_TLS_OFFSET; + /* Protects global and module specitic TLS state. */ + __rtld_lock_lock_recursive (GL(dl_load_tls_lock)); + /* We modify the list of loaded objects. */ __rtld_lock_lock_recursive (GL(dl_load_write_lock)); @@ -784,6 +787,9 @@ _dl_close_worker (struct link_map *map, bool force) GL(dl_tls_static_used) = tls_free_start; } + /* TLS is cleaned up for the unloaded modules. */ + __rtld_lock_unlock_recursive (GL(dl_load_tls_lock)); + #ifdef SHARED /* Auditing checkpoint: we have deleted all objects. */ if (__glibc_unlikely (do_audit)) diff --git a/elf/dl-load.c b/elf/dl-load.c index 650e4edc35..0976977fbd 100644 --- a/elf/dl-load.c +++ b/elf/dl-load.c @@ -1130,6 +1130,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, struct loadcmd loadcmds[l->l_phnum]; size_t nloadcmds = 0; bool has_holes = false; + bool empty_dynamic = false; /* The struct is initialized to zero so this is not necessary: l->l_ld = 0; @@ -1142,13 +1143,16 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, segments are mapped in. We record the addresses it says verbatim, and later correct for the run-time load address. */ case PT_DYNAMIC: - if (ph->p_filesz) + if (ph->p_filesz == 0) + empty_dynamic = true; /* Usually separate debuginfo. */ + else { /* Debuginfo only files from "objcopy --only-keep-debug" contain a PT_DYNAMIC segment with p_filesz == 0. Skip such a segment to avoid a crash later. */ l->l_ld = (void *) ph->p_vaddr; l->l_ldnum = ph->p_memsz / sizeof (ElfW(Dyn)); + l->l_ld_readonly = (ph->p_flags & PF_W) == 0; } break; @@ -1264,6 +1268,13 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, goto lose; } + /* This check recognizes most separate debuginfo files. */ + if (__glibc_unlikely ((l->l_ld == 0 && type == ET_DYN) || empty_dynamic)) + { + errstring = N_("object file has no dynamic section"); + goto lose; + } + /* Length of the sections to be loaded. */ maplength = loadcmds[nloadcmds - 1].allocend - loadcmds[0].mapstart; @@ -1281,18 +1292,10 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, } } - if (l->l_ld == 0) - { - if (__glibc_unlikely (type == ET_DYN)) - { - errstring = N_("object file has no dynamic section"); - goto lose; - } - } - else + if (l->l_ld != 0) l->l_ld = (ElfW(Dyn) *) ((ElfW(Addr)) l->l_ld + l->l_addr); - elf_get_dynamic_info (l, NULL); + elf_get_dynamic_info (l); /* Make sure we are not dlopen'ing an object that has the DF_1_NOOPEN flag set, or a PIE object. */ diff --git a/elf/dl-open.c b/elf/dl-open.c index ec386626f9..bc68e2c376 100644 --- a/elf/dl-open.c +++ b/elf/dl-open.c @@ -66,6 +66,9 @@ struct dl_open_args libc_map value in the namespace in case of a dlopen failure. */ bool libc_already_loaded; + /* Set to true if the end of dl_open_worker_begin was reached. */ + bool worker_continue; + /* Original parameters to the program and the current environment. */ int argc; char **argv; @@ -482,7 +485,7 @@ call_dl_init (void *closure) } static void -dl_open_worker (void *a) +dl_open_worker_begin (void *a) { struct dl_open_args *args = a; const char *file = args->file; @@ -774,6 +777,36 @@ dl_open_worker (void *a) _dl_call_libc_early_init (libc_map, false); } + args->worker_continue = true; +} + +static void +dl_open_worker (void *a) +{ + struct dl_open_args *args = a; + + args->worker_continue = false; + + { + /* Protects global and module specific TLS state. */ + __rtld_lock_lock_recursive (GL(dl_load_tls_lock)); + + struct dl_exception ex; + int err = _dl_catch_exception (&ex, dl_open_worker_begin, args); + + __rtld_lock_unlock_recursive (GL(dl_load_tls_lock)); + + if (__glibc_unlikely (ex.errstring != NULL)) + /* Reraise the error. */ + _dl_signal_exception (err, &ex, NULL); + } + + if (!args->worker_continue) + return; + + int mode = args->mode; + struct link_map *new = args->map; + /* Run the initializer functions of new objects. Temporarily disable the exception handler, so that lazy binding failures are fatal. */ @@ -886,7 +919,7 @@ no more namespaces available for dlmopen()")); /* Avoid keeping around a dangling reference to the libc.so link map in case it has been cached in libc_map. */ if (!args.libc_already_loaded) - GL(dl_ns)[nsid].libc_map = NULL; + GL(dl_ns)[args.nsid].libc_map = NULL; /* Remove the object from memory. It may be in an inconsistent state if relocation failed, for example. */ diff --git a/elf/dl-reloc-static-pie.c b/elf/dl-reloc-static-pie.c index d5bd2f31e9..2fb02d7276 100644 --- a/elf/dl-reloc-static-pie.c +++ b/elf/dl-reloc-static-pie.c @@ -40,7 +40,17 @@ _dl_relocate_static_pie (void) /* Read our own dynamic section and fill in the info array. */ main_map->l_ld = ((void *) main_map->l_addr + elf_machine_dynamic ()); - elf_get_dynamic_info (main_map, NULL); + + const ElfW(Phdr) *ph, *phdr = GL(dl_phdr); + size_t phnum = GL(dl_phnum); + for (ph = phdr; ph < &phdr[phnum]; ++ph) + if (ph->p_type == PT_DYNAMIC) + { + main_map->l_ld_readonly = (ph->p_flags & PF_W) == 0; + break; + } + + elf_get_dynamic_info (main_map); # ifdef ELF_MACHINE_BEFORE_RTLD_RELOC ELF_MACHINE_BEFORE_RTLD_RELOC (main_map->l_info); diff --git a/elf/dl-support.c b/elf/dl-support.c index 0155718175..d8c06ba7eb 100644 --- a/elf/dl-support.c +++ b/elf/dl-support.c @@ -229,6 +229,13 @@ __rtld_lock_define_initialized_recursive (, _dl_load_lock) list of loaded objects while an object is added to or removed from that list. */ __rtld_lock_define_initialized_recursive (, _dl_load_write_lock) + /* This lock protects global and module specific TLS related data. + E.g. it is held in dlopen and dlclose when GL(dl_tls_generation), + GL(dl_tls_max_dtv_idx) or GL(dl_tls_dtv_slotinfo_list) are + accessed and when TLS related relocations are processed for a + module. It was introduced to keep pthread_create accessing TLS + state that is being set up. */ +__rtld_lock_define_initialized_recursive (, _dl_load_tls_lock) #ifdef HAVE_AUX_VECTOR diff --git a/elf/dl-sysdep.c b/elf/dl-sysdep.c index d47bef1340..2c684c2db2 100644 --- a/elf/dl-sysdep.c +++ b/elf/dl-sysdep.c @@ -317,7 +317,7 @@ _dl_show_auxv (void) [AT_SYSINFO_EHDR - 2] = { "SYSINFO_EHDR: 0x", hex }, [AT_RANDOM - 2] = { "RANDOM: 0x", hex }, [AT_HWCAP2 - 2] = { "HWCAP2: 0x", hex }, - [AT_MINSIGSTKSZ - 2] = { "MINSIGSTKSZ ", dec }, + [AT_MINSIGSTKSZ - 2] = { "MINSIGSTKSZ: ", dec }, [AT_L1I_CACHESIZE - 2] = { "L1I_CACHESIZE: ", dec }, [AT_L1I_CACHEGEOMETRY - 2] = { "L1I_CACHEGEOMETRY: 0x", hex }, [AT_L1D_CACHESIZE - 2] = { "L1D_CACHESIZE: ", dec }, diff --git a/elf/dl-tls.c b/elf/dl-tls.c index 423e380f7c..40263cf586 100644 --- a/elf/dl-tls.c +++ b/elf/dl-tls.c @@ -532,7 +532,7 @@ _dl_allocate_tls_init (void *result) size_t maxgen = 0; /* Protects global dynamic TLS related state. */ - __rtld_lock_lock_recursive (GL(dl_load_lock)); + __rtld_lock_lock_recursive (GL(dl_load_tls_lock)); /* Check if the current dtv is big enough. */ if (dtv[-1].counter < GL(dl_tls_max_dtv_idx)) @@ -606,7 +606,7 @@ _dl_allocate_tls_init (void *result) listp = listp->next; assert (listp != NULL); } - __rtld_lock_unlock_recursive (GL(dl_load_lock)); + __rtld_lock_unlock_recursive (GL(dl_load_tls_lock)); /* The DTV version is up-to-date now. */ dtv[0].counter = maxgen; @@ -745,7 +745,7 @@ _dl_update_slotinfo (unsigned long int req_modid) Here the dtv needs to be updated to new_gen generation count. - This code may be called during TLS access when GL(dl_load_lock) + This code may be called during TLS access when GL(dl_load_tls_lock) is not held. In that case the user code has to synchronize with dlopen and dlclose calls of relevant modules. A module m is relevant if the generation of m <= new_gen and dlclose of m is @@ -867,11 +867,11 @@ tls_get_addr_tail (GET_ADDR_ARGS, dtv_t *dtv, struct link_map *the_map) if (__glibc_unlikely (the_map->l_tls_offset != FORCED_DYNAMIC_TLS_OFFSET)) { - __rtld_lock_lock_recursive (GL(dl_load_lock)); + __rtld_lock_lock_recursive (GL(dl_load_tls_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)); + __rtld_lock_unlock_recursive (GL(dl_load_tls_lock)); } else if (__glibc_likely (the_map->l_tls_offset != FORCED_DYNAMIC_TLS_OFFSET)) @@ -883,7 +883,7 @@ tls_get_addr_tail (GET_ADDR_ARGS, dtv_t *dtv, struct link_map *the_map) #else # error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined" #endif - __rtld_lock_unlock_recursive (GL(dl_load_lock)); + __rtld_lock_unlock_recursive (GL(dl_load_tls_lock)); dtv[GET_ADDR_MODULE].pointer.to_free = NULL; dtv[GET_ADDR_MODULE].pointer.val = p; @@ -891,7 +891,7 @@ tls_get_addr_tail (GET_ADDR_ARGS, dtv_t *dtv, struct link_map *the_map) return (char *) p + GET_ADDR_OFFSET; } else - __rtld_lock_unlock_recursive (GL(dl_load_lock)); + __rtld_lock_unlock_recursive (GL(dl_load_tls_lock)); } struct dtv_pointer result = allocate_and_init (the_map); dtv[GET_ADDR_MODULE].pointer = result; @@ -962,7 +962,7 @@ _dl_tls_get_addr_soft (struct link_map *l) return NULL; dtv_t *dtv = THREAD_DTV (); - /* This may be called without holding the GL(dl_load_lock). Reading + /* This may be called without holding the GL(dl_load_tls_lock). Reading arbitrary gen value is fine since this is best effort code. */ size_t gen = atomic_load_relaxed (&GL(dl_tls_generation)); if (__glibc_unlikely (dtv[0].counter != gen)) diff --git a/elf/get-dynamic-info.h b/elf/get-dynamic-info.h index d8ec32377d..4aa2058abf 100644 --- a/elf/get-dynamic-info.h +++ b/elf/get-dynamic-info.h @@ -28,7 +28,7 @@ static auto #endif inline void __attribute__ ((unused, always_inline)) -elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp) +elf_get_dynamic_info (struct link_map *l) { #if __ELF_NATIVE_CLASS == 32 typedef Elf32_Word d_tag_utype; @@ -69,28 +69,15 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp) info[i] = dyn; } -#define DL_RO_DYN_TEMP_CNT 8 - -#ifndef DL_RO_DYN_SECTION /* Don't adjust .dynamic unnecessarily. */ - if (l->l_addr != 0) + if (l->l_addr != 0 && dl_relocate_ld (l)) { ElfW(Addr) l_addr = l->l_addr; - int cnt = 0; # define ADJUST_DYN_INFO(tag) \ do \ if (info[tag] != NULL) \ - { \ - if (temp) \ - { \ - temp[cnt].d_tag = info[tag]->d_tag; \ - temp[cnt].d_un.d_ptr = info[tag]->d_un.d_ptr + l_addr; \ - info[tag] = temp + cnt++; \ - } \ - else \ - info[tag]->d_un.d_ptr += l_addr; \ - } \ + info[tag]->d_un.d_ptr += l_addr; \ while (0) ADJUST_DYN_INFO (DT_HASH); @@ -107,9 +94,7 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp) ADJUST_DYN_INFO (VERSYMIDX (DT_VERSYM)); ADJUST_DYN_INFO (ADDRIDX (DT_GNU_HASH)); # undef ADJUST_DYN_INFO - assert (cnt <= DL_RO_DYN_TEMP_CNT); } -#endif if (info[DT_PLTREL] != NULL) { #if ELF_MACHINE_NO_RELA diff --git a/elf/ldconfig.c b/elf/ldconfig.c index 1037e8d0cf..b8893637f8 100644 --- a/elf/ldconfig.c +++ b/elf/ldconfig.c @@ -503,7 +503,11 @@ add_dir_1 (const char *line, const char *from_file, int from_line) entry->path[--i] = '\0'; if (i == 0) - return; + { + free (entry->path); + free (entry); + return; + } char *path = entry->path; if (opt_chroot != NULL) diff --git a/elf/rtld.c b/elf/rtld.c index d733359eaf..d83ac1bdc4 100644 --- a/elf/rtld.c +++ b/elf/rtld.c @@ -322,6 +322,7 @@ struct rtld_global _rtld_global = #ifdef _LIBC_REENTRANT ._dl_load_lock = _RTLD_LOCK_RECURSIVE_INITIALIZER, ._dl_load_write_lock = _RTLD_LOCK_RECURSIVE_INITIALIZER, + ._dl_load_tls_lock = _RTLD_LOCK_RECURSIVE_INITIALIZER, #endif ._dl_nns = 1, ._dl_ns = @@ -463,6 +464,7 @@ _dl_start_final (void *arg, struct dl_start_final_info *info) #ifndef DONT_USE_BOOTSTRAP_MAP GL(dl_rtld_map).l_addr = info->l.l_addr; GL(dl_rtld_map).l_ld = info->l.l_ld; + GL(dl_rtld_map).l_ld_readonly = info->l.l_ld_readonly; memcpy (GL(dl_rtld_map).l_info, info->l.l_info, sizeof GL(dl_rtld_map).l_info); GL(dl_rtld_map).l_mach = info->l.l_mach; @@ -546,7 +548,8 @@ _dl_start (void *arg) /* Read our own dynamic section and fill in the info array. */ bootstrap_map.l_ld = (void *) bootstrap_map.l_addr + elf_machine_dynamic (); - elf_get_dynamic_info (&bootstrap_map, NULL); + bootstrap_map.l_ld_readonly = DL_RO_DYN_SECTION; + elf_get_dynamic_info (&bootstrap_map); #if NO_TLS_OFFSET != 0 bootstrap_map.l_tls_offset = NO_TLS_OFFSET; @@ -1468,6 +1471,7 @@ dl_main (const ElfW(Phdr) *phdr, /* This tells us where to find the dynamic section, which tells us everything we need to do. */ main_map->l_ld = (void *) main_map->l_addr + ph->p_vaddr; + main_map->l_ld_readonly = (ph->p_flags & PF_W) == 0; break; case PT_INTERP: /* This "interpreter segment" was used by the program loader to @@ -1613,7 +1617,7 @@ dl_main (const ElfW(Phdr) *phdr, if (! rtld_is_main) { /* Extract the contents of the dynamic section for easy access. */ - elf_get_dynamic_info (main_map, NULL); + elf_get_dynamic_info (main_map); /* If the main map is libc.so, update the base namespace to refer to this map. If libc.so is loaded later, this happens diff --git a/elf/setup-vdso.h b/elf/setup-vdso.h index 86c491e49c..f44748bc98 100644 --- a/elf/setup-vdso.h +++ b/elf/setup-vdso.h @@ -33,8 +33,6 @@ setup_vdso (struct link_map *main_map __attribute__ ((unused)), 0, LM_ID_BASE); if (__glibc_likely (l != NULL)) { - static ElfW(Dyn) dyn_temp[DL_RO_DYN_TEMP_CNT] attribute_relro; - l->l_phdr = ((const void *) GLRO(dl_sysinfo_dso) + GLRO(dl_sysinfo_dso)->e_phoff); l->l_phnum = GLRO(dl_sysinfo_dso)->e_phnum; @@ -45,6 +43,7 @@ setup_vdso (struct link_map *main_map __attribute__ ((unused)), { l->l_ld = (void *) ph->p_vaddr; l->l_ldnum = ph->p_memsz / sizeof (ElfW(Dyn)); + l->l_ld_readonly = (ph->p_flags & PF_W) == 0; } else if (ph->p_type == PT_LOAD) { @@ -65,7 +64,7 @@ setup_vdso (struct link_map *main_map __attribute__ ((unused)), l->l_map_end += l->l_addr; l->l_text_end += l->l_addr; l->l_ld = (void *) ((ElfW(Addr)) l->l_ld + l->l_addr); - elf_get_dynamic_info (l, dyn_temp); + elf_get_dynamic_info (l); _dl_setup_hash (l); l->l_relocated = 1; diff --git a/elf/tst-ro-dynamic-mod.c b/elf/tst-ro-dynamic-mod.c new file mode 100644 index 0000000000..6d99925964 --- /dev/null +++ b/elf/tst-ro-dynamic-mod.c @@ -0,0 +1,19 @@ +/* Test case for DSO with readonly dynamic section. + Copyright (C) 2021 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 + . */ + +int foo = -1; diff --git a/elf/tst-ro-dynamic-mod.map b/elf/tst-ro-dynamic-mod.map new file mode 100644 index 0000000000..2fe4a2998c --- /dev/null +++ b/elf/tst-ro-dynamic-mod.map @@ -0,0 +1,16 @@ +SECTIONS +{ + . = SIZEOF_HEADERS; + .dynamic : { *(.dynamic) } :text :dynamic + .rodata : { *(.data*) *(.bss*) } :text + /DISCARD/ : { + *(.note.gnu.property) + } + .note : { *(.note.*) } :text :note +} +PHDRS +{ + text PT_LOAD FLAGS(5) FILEHDR PHDRS; + dynamic PT_DYNAMIC FLAGS(4); + note PT_NOTE FLAGS(4); +} diff --git a/elf/tst-ro-dynamic.c b/elf/tst-ro-dynamic.c new file mode 100644 index 0000000000..3a18f8789a --- /dev/null +++ b/elf/tst-ro-dynamic.c @@ -0,0 +1,31 @@ +/* Test case for DSO with readonly dynamic section. + Copyright (C) 2021 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 + . */ + +#include +#include + +extern int foo; + +static int +do_test (void) +{ + TEST_COMPARE (foo, -1); + return 0; +} + +#include diff --git a/iconv/gconv_conf.c b/iconv/gconv_conf.c index 62bee28769..cc391d8f93 100644 --- a/iconv/gconv_conf.c +++ b/iconv/gconv_conf.c @@ -478,7 +478,7 @@ __gconv_read_conf (void) __gconv_get_path (); for (cnt = 0; __gconv_path_elem[cnt].name != NULL; ++cnt) - gconv_parseconfdir (__gconv_path_elem[cnt].name, + gconv_parseconfdir (NULL, __gconv_path_elem[cnt].name, __gconv_path_elem[cnt].len); #endif diff --git a/iconv/gconv_parseconfdir.h b/iconv/gconv_parseconfdir.h index a4153e54c6..a586268abc 100644 --- a/iconv/gconv_parseconfdir.h +++ b/iconv/gconv_parseconfdir.h @@ -39,7 +39,6 @@ /* Name of the file containing the module information in the directories along the path. */ static const char gconv_conf_filename[] = "gconv-modules"; -static const char gconv_conf_dirname[] = "gconv-modules.d"; static void add_alias (char *); static void add_module (char *, const char *, size_t, int); @@ -110,19 +109,28 @@ read_conf_file (const char *filename, const char *directory, size_t dir_len) return true; } +/* Prefix DIR (with length DIR_LEN) with PREFIX if the latter is non-NULL and + parse configuration in it. */ + static __always_inline bool -gconv_parseconfdir (const char *dir, size_t dir_len) +gconv_parseconfdir (const char *prefix, const char *dir, size_t dir_len) { - /* No slash needs to be inserted between dir and gconv_conf_filename; - dir already ends in a slash. */ - char *buf = malloc (dir_len + sizeof (gconv_conf_dirname)); + /* No slash needs to be inserted between dir and gconv_conf_filename; dir + already ends in a slash. The additional 2 is to accommodate the ".d" + when looking for configuration files in gconv-modules.d. */ + size_t buflen = dir_len + sizeof (gconv_conf_filename) + 2; + char *buf = malloc (buflen + (prefix != NULL ? strlen (prefix) : 0)); + char *cp = buf; bool found = false; if (buf == NULL) return false; - char *cp = mempcpy (mempcpy (buf, dir, dir_len), gconv_conf_filename, - sizeof (gconv_conf_filename)); + if (prefix != NULL) + cp = stpcpy (cp, prefix); + + cp = mempcpy (mempcpy (cp, dir, dir_len), gconv_conf_filename, + sizeof (gconv_conf_filename)); /* Read the gconv-modules configuration file first. */ found = read_conf_file (buf, dir, dir_len); @@ -153,12 +161,11 @@ gconv_parseconfdir (const char *dir, size_t dir_len) struct stat64 st; if (asprintf (&conf, "%s/%s", buf, ent->d_name) < 0) continue; - if (ent->d_type == DT_UNKNOWN - && (lstat64 (conf, &st) == -1 - || !S_ISREG (st.st_mode))) - continue; - found |= read_conf_file (conf, dir, dir_len); + if (ent->d_type != DT_UNKNOWN + || (lstat64 (conf, &st) != -1 && S_ISREG (st.st_mode))) + found |= read_conf_file (conf, dir, dir_len); + free (conf); } } diff --git a/iconv/iconv_charmap.c b/iconv/iconv_charmap.c index e2d53fee3c..a8b6b56124 100644 --- a/iconv/iconv_charmap.c +++ b/iconv/iconv_charmap.c @@ -234,6 +234,8 @@ charmap_conversion (const char *from_code, struct charmap_t *from_charmap, while (++remaining < argc); /* All done. */ + if (output != stdout) + fclose (output); free_table (cvtbl); return status; } diff --git a/iconv/iconvconfig.c b/iconv/iconvconfig.c index 783b2bbdbb..273a71f673 100644 --- a/iconv/iconvconfig.c +++ b/iconv/iconvconfig.c @@ -653,13 +653,21 @@ add_module (char *rp, const char *directory, static int handle_dir (const char *dir) { + char *newp = NULL; size_t dirlen = strlen (dir); bool found = false; - char *fulldir = xasprintf ("%s%s%s", dir[0] == '/' ? prefix : "", - dir, dir[dirlen - 1] != '/' ? "/" : ""); + /* End directory path with a '/' if it doesn't already. */ + if (dir[dirlen - 1] != '/') + { + newp = xmalloc (dirlen + 2); + memcpy (newp, dir, dirlen); + newp[dirlen++] = '/'; + newp[dirlen] = '\0'; + dir = newp; + } - found = gconv_parseconfdir (fulldir, strlen (fulldir)); + found = gconv_parseconfdir (dir[0] == '/' ? prefix : NULL, dir, dirlen); if (!found) { @@ -671,7 +679,7 @@ handle_dir (const char *dir) "configuration files with names ending in .conf."); } - free (fulldir); + free (newp); return found ? 0 : 1; } diff --git a/iconvdata/Makefile b/iconvdata/Makefile index c216f959df..d5507a048c 100644 --- a/iconvdata/Makefile +++ b/iconvdata/Makefile @@ -1,4 +1,5 @@ # Copyright (C) 1997-2021 Free Software Foundation, Inc. +# Copyright (C) The GNU Toolchain Authors. # This file is part of the GNU C Library. # The GNU C Library is free software; you can redistribute it and/or @@ -74,7 +75,7 @@ ifeq (yes,$(build-shared)) tests = bug-iconv1 bug-iconv2 tst-loading tst-e2big tst-iconv4 bug-iconv4 \ tst-iconv6 bug-iconv5 bug-iconv6 tst-iconv7 bug-iconv8 bug-iconv9 \ bug-iconv10 bug-iconv11 bug-iconv12 tst-iconv-big5-hkscs-to-2ucs4 \ - bug-iconv13 bug-iconv14 + bug-iconv13 bug-iconv14 bug-iconv15 ifeq ($(have-thread-library),yes) tests += bug-iconv3 endif @@ -327,6 +328,8 @@ $(objpfx)bug-iconv12.out: $(addprefix $(objpfx), $(gconv-modules)) \ $(addprefix $(objpfx),$(modules.so)) $(objpfx)bug-iconv14.out: $(addprefix $(objpfx), $(gconv-modules)) \ $(addprefix $(objpfx),$(modules.so)) +$(objpfx)bug-iconv15.out: $(addprefix $(objpfx), $(gconv-modules)) \ + $(addprefix $(objpfx),$(modules.so)) $(objpfx)iconv-test.out: run-iconv-test.sh \ $(addprefix $(objpfx), $(gconv-modules)) \ diff --git a/iconvdata/bug-iconv15.c b/iconvdata/bug-iconv15.c new file mode 100644 index 0000000000..cc04bd0313 --- /dev/null +++ b/iconvdata/bug-iconv15.c @@ -0,0 +1,60 @@ +/* Bug 28524: Conversion from ISO-2022-JP-3 with iconv + may emit spurious NUL character on state reset. + Copyright (C) The GNU Toolchain Authors. + 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 + . */ + +#include +#include +#include + +static int +do_test (void) +{ + char in[] = "\x1b(I"; + char *inbuf = in; + size_t inleft = sizeof (in) - 1; + char out[1]; + char *outbuf = out; + size_t outleft = sizeof (out); + iconv_t cd; + + cd = iconv_open ("UTF8", "ISO-2022-JP-3"); + TEST_VERIFY_EXIT (cd != (iconv_t) -1); + + /* First call to iconv should alter internal state. + Now, JISX0201_Kana_set is selected and + state value != ASCII_set. */ + TEST_VERIFY (iconv (cd, &inbuf, &inleft, &outbuf, &outleft) != (size_t) -1); + + /* No bytes should have been added to + the output buffer at this point. */ + TEST_VERIFY (outbuf == out); + TEST_VERIFY (outleft == sizeof (out)); + + /* Second call shall emit spurious NUL character in unpatched glibc. */ + TEST_VERIFY (iconv (cd, NULL, NULL, &outbuf, &outleft) != (size_t) -1); + + /* No characters are expected to be produced. */ + TEST_VERIFY (outbuf == out); + TEST_VERIFY (outleft == sizeof (out)); + + TEST_VERIFY_EXIT (iconv_close (cd) != -1); + + return 0; +} + +#include diff --git a/iconvdata/iso-2022-jp-3.c b/iconvdata/iso-2022-jp-3.c index c8ba88cdc9..5fc0c0f739 100644 --- a/iconvdata/iso-2022-jp-3.c +++ b/iconvdata/iso-2022-jp-3.c @@ -1,5 +1,6 @@ /* Conversion module for ISO-2022-JP-3. Copyright (C) 1998-2021 Free Software Foundation, Inc. + Copyright (C) The GNU Toolchain Authors. This file is part of the GNU C Library. Contributed by Ulrich Drepper , 1998, and Bruno Haible , 2002. @@ -81,20 +82,31 @@ enum the output state to the initial state. This has to be done during the flushing. */ #define EMIT_SHIFT_TO_INIT \ - if (data->__statep->__count != ASCII_set) \ + if ((data->__statep->__count & ~7) != ASCII_set) \ { \ if (FROM_DIRECTION) \ { \ - if (__glibc_likely (outbuf + 4 <= outend)) \ + uint32_t ch = data->__statep->__count >> 6; \ + \ + if (__glibc_unlikely (ch != 0)) \ { \ - /* Write out the last character. */ \ - *((uint32_t *) outbuf) = data->__statep->__count >> 6; \ - outbuf += sizeof (uint32_t); \ - data->__statep->__count = ASCII_set; \ + if (__glibc_likely (outbuf + 4 <= outend)) \ + { \ + /* Write out the last character. */ \ + put32u (outbuf, ch); \ + outbuf += 4; \ + data->__statep->__count &= 7; \ + data->__statep->__count |= ASCII_set; \ + } \ + else \ + /* We don't have enough room in the output buffer. */ \ + status = __GCONV_FULL_OUTPUT; \ } \ else \ - /* We don't have enough room in the output buffer. */ \ - status = __GCONV_FULL_OUTPUT; \ + { \ + data->__statep->__count &= 7; \ + data->__statep->__count |= ASCII_set; \ + } \ } \ else \ { \ diff --git a/include/link.h b/include/link.h index 4af16cb596..c46aced9f7 100644 --- a/include/link.h +++ b/include/link.h @@ -205,6 +205,7 @@ struct link_map unsigned int l_free_initfini:1; /* Nonzero if l_initfini can be freed, ie. not allocated with the dummy malloc in ld.so. */ + unsigned int l_ld_readonly:1; /* Nonzero if dynamic section is readonly. */ /* NODELETE status of the map. Only valid for maps of type lt_loaded. Lazy binding sets l_nodelete_active directly, @@ -342,6 +343,8 @@ struct link_map unsigned long long int l_serial; }; +#include + /* Information used by audit modules. For most link maps, this data immediate follows the link map in memory. For the dynamic linker, it is allocated separately. See link_map_audit_state in diff --git a/include/sys/sysinfo.h b/include/sys/sysinfo.h index 7388356a19..c490561581 100644 --- a/include/sys/sysinfo.h +++ b/include/sys/sysinfo.h @@ -9,10 +9,15 @@ extern int __get_nprocs_conf (void); libc_hidden_proto (__get_nprocs_conf) -/* Return number of available processors. */ +/* Return number of available processors (not all of them will be + available to the caller process). */ extern int __get_nprocs (void); libc_hidden_proto (__get_nprocs) +/* Return the number of available processors which the process can + be scheduled. */ +extern int __get_nprocs_sched (void) attribute_hidden; + /* Return number of physical pages of memory in the system. */ extern long int __get_phys_pages (void); libc_hidden_proto (__get_phys_pages) diff --git a/io/fcntl.h b/io/fcntl.h index 8917a73b42..1c96f98f4d 100644 --- a/io/fcntl.h +++ b/io/fcntl.h @@ -187,10 +187,10 @@ extern int fcntl64 (int __fd, int __cmd, ...); # endif #else /* __USE_TIME_BITS64 */ # ifdef __REDIRECT -extern int __REDIRECT (fcntl, (int __fd, int __request, ...), - __fcntl_time64) __THROW; -extern int __REDIRECT (fcntl64, (int __fd, int __request, ...), - __fcntl_time64) __THROW; +extern int __REDIRECT_NTH (fcntl, (int __fd, int __request, ...), + __fcntl_time64); +extern int __REDIRECT_NTH (fcntl64, (int __fd, int __request, ...), + __fcntl_time64); # else extern int __fcntl_time64 (int __fd, int __request, ...) __THROW; # define fcntl64 __fcntl_time64 diff --git a/io/tst-closefrom.c b/io/tst-closefrom.c index d4c187073c..395ec0d894 100644 --- a/io/tst-closefrom.c +++ b/io/tst-closefrom.c @@ -24,31 +24,22 @@ #include #include #include +#include #include #define NFDS 100 -static int -open_multiple_temp_files (void) -{ - /* Check if the temporary file descriptor has no no gaps. */ - int lowfd = xopen ("/dev/null", O_RDONLY, 0600); - for (int i = 1; i <= NFDS; i++) - TEST_COMPARE (xopen ("/dev/null", O_RDONLY, 0600), lowfd + i); - return lowfd; -} - static int closefrom_test (void) { struct support_descriptors *descrs = support_descriptors_list (); - int lowfd = open_multiple_temp_files (); + int lowfd = support_open_dev_null_range (NFDS, O_RDONLY, 0600); - const int maximum_fd = lowfd + NFDS; + const int maximum_fd = lowfd + NFDS - 1; const int half_fd = lowfd + NFDS / 2; - const int gap = maximum_fd / 4; + const int gap = lowfd + NFDS / 4; /* Close half of the descriptors and check result. */ closefrom (half_fd); @@ -58,7 +49,7 @@ closefrom_test (void) TEST_COMPARE (fcntl (i, F_GETFL), -1); TEST_COMPARE (errno, EBADF); } - for (int i = 0; i < half_fd; i++) + for (int i = lowfd; i < half_fd; i++) TEST_VERIFY (fcntl (i, F_GETFL) > -1); /* Create some gaps, close up to a threshold, and check result. */ @@ -74,7 +65,7 @@ closefrom_test (void) TEST_COMPARE (fcntl (i, F_GETFL), -1); TEST_COMPARE (errno, EBADF); } - for (int i = 0; i < gap; i++) + for (int i = lowfd; i < gap; i++) TEST_VERIFY (fcntl (i, F_GETFL) > -1); /* Close the remmaining but the last one. */ diff --git a/malloc/arena.c b/malloc/arena.c index 667484630e..f1f0af8648 100644 --- a/malloc/arena.c +++ b/malloc/arena.c @@ -879,7 +879,7 @@ arena_get2 (size_t size, mstate avoid_arena) narenas_limit = mp_.arena_max; else if (narenas > mp_.arena_test) { - int n = __get_nprocs (); + int n = __get_nprocs_sched (); if (n >= 1) narenas_limit = NARENAS_FROM_NCORES (n); diff --git a/malloc/malloc-debug.c b/malloc/malloc-debug.c index 9922ef5f25..3d7e6d44fd 100644 --- a/malloc/malloc-debug.c +++ b/malloc/malloc-debug.c @@ -1,5 +1,6 @@ /* Malloc debug DSO. Copyright (C) 2021 Free Software Foundation, Inc. + Copyright The GNU Toolchain Authors. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -399,17 +400,17 @@ strong_alias (__debug_calloc, calloc) size_t malloc_usable_size (void *mem) { + if (mem == NULL) + return 0; + if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK)) return mcheck_usable_size (mem); if (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK)) return malloc_check_get_size (mem); - if (mem != NULL) - { - mchunkptr p = mem2chunk (mem); - if (DUMPED_MAIN_ARENA_CHUNK (p)) - return chunksize (p) - SIZE_SZ; - } + mchunkptr p = mem2chunk (mem); + if (DUMPED_MAIN_ARENA_CHUNK (p)) + return chunksize (p) - SIZE_SZ; return musable (mem); } diff --git a/malloc/malloc.c b/malloc/malloc.c index e065785af7..7882c70f0a 100644 --- a/malloc/malloc.c +++ b/malloc/malloc.c @@ -1,5 +1,6 @@ /* Malloc implementation for multiple threads without lock contention. Copyright (C) 1996-2021 Free Software Foundation, Inc. + Copyright The GNU Toolchain Authors. This file is part of the GNU C Library. Contributed by Wolfram Gloger and Doug Lea , 2001. @@ -5009,20 +5010,13 @@ __malloc_trim (size_t s) static size_t musable (void *mem) { - mchunkptr p; - if (mem != 0) - { - size_t result = 0; - - p = mem2chunk (mem); + mchunkptr p = mem2chunk (mem); - if (chunk_is_mmapped (p)) - result = chunksize (p) - CHUNK_HDR_SZ; - else if (inuse (p)) - result = memsize (p); + if (chunk_is_mmapped (p)) + return chunksize (p) - CHUNK_HDR_SZ; + else if (inuse (p)) + return memsize (p); - return result; - } return 0; } @@ -5030,10 +5024,9 @@ musable (void *mem) size_t __malloc_usable_size (void *m) { - size_t result; - - result = musable (m); - return result; + if (m == NULL) + return 0; + return musable (m); } #endif diff --git a/malloc/tst-malloc-usable.c b/malloc/tst-malloc-usable.c index a1074b782a..b0d702be10 100644 --- a/malloc/tst-malloc-usable.c +++ b/malloc/tst-malloc-usable.c @@ -2,6 +2,7 @@ MALLOC_CHECK_ exported to a positive value. Copyright (C) 2012-2021 Free Software Foundation, Inc. + Copyright The GNU Toolchain Authors. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -21,29 +22,24 @@ #include #include #include +#include +#include static int do_test (void) { size_t usable_size; void *p = malloc (7); - if (!p) - { - printf ("memory allocation failed\n"); - return 1; - } + TEST_VERIFY_EXIT (p != NULL); usable_size = malloc_usable_size (p); - if (usable_size != 7) - { - printf ("malloc_usable_size: expected 7 but got %zu\n", usable_size); - return 1; - } - + TEST_COMPARE (usable_size, 7); memset (p, 0, usable_size); free (p); + + TEST_COMPARE (malloc_usable_size (NULL), 0); + return 0; } -#define TEST_FUNCTION do_test () -#include "../test-skeleton.c" +#include "support/test-driver.c" diff --git a/misc/getsysstats.c b/misc/getsysstats.c index 0eedface6d..57d93601e2 100644 --- a/misc/getsysstats.c +++ b/misc/getsysstats.c @@ -45,6 +45,12 @@ weak_alias (__get_nprocs, get_nprocs) link_warning (get_nprocs, "warning: get_nprocs will always return 1") +int +__get_nprocs_sched (void) +{ + return 1; +} + long int __get_phys_pages (void) { diff --git a/misc/sys/ioctl.h b/misc/sys/ioctl.h index 6884d9925f..9945c1e918 100644 --- a/misc/sys/ioctl.h +++ b/misc/sys/ioctl.h @@ -42,8 +42,8 @@ __BEGIN_DECLS extern int ioctl (int __fd, unsigned long int __request, ...) __THROW; #else # ifdef __REDIRECT -extern int __REDIRECT (ioctl, (int __fd, unsigned long int __request, ...), - __ioctl_time64) __THROW; +extern int __REDIRECT_NTH (ioctl, (int __fd, unsigned long int __request, ...), + __ioctl_time64); # else extern int __ioctl_time64 (int __fd, unsigned long int __request, ...) __THROW; # define ioctl __ioctl_time64 diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c index cfe37a3443..50065bc9bd 100644 --- a/nptl/allocatestack.c +++ b/nptl/allocatestack.c @@ -32,6 +32,7 @@ #include #include #include +#include /* Default alignment of stack. */ #ifndef STACK_ALIGN @@ -127,6 +128,8 @@ get_cached_stack (size_t *sizep, void **memp) /* No pending event. */ result->nextevent = NULL; + result->exiting = false; + __libc_lock_init (result->exit_lock); result->tls_state = (struct tls_internal_t) { 0 }; /* Clear the DTV. */ diff --git a/nptl/descr.h b/nptl/descr.h index c85778d449..4de84138fb 100644 --- a/nptl/descr.h +++ b/nptl/descr.h @@ -396,6 +396,12 @@ struct pthread PTHREAD_CANCEL_ASYNCHRONOUS). */ unsigned char canceltype; + /* Used in __pthread_kill_internal to detected a thread that has + exited or is about to exit. exit_lock must only be acquired + after blocking signals. */ + bool exiting; + int exit_lock; /* A low-level lock (for use with __libc_lock_init etc). */ + /* Used on strsignal. */ struct tls_internal_t tls_state; diff --git a/nptl/pthread_cancel.c b/nptl/pthread_cancel.c index cc25ff21f3..9bac6e3b76 100644 --- a/nptl/pthread_cancel.c +++ b/nptl/pthread_cancel.c @@ -62,10 +62,11 @@ __pthread_cancel (pthread_t th) { volatile struct pthread *pd = (volatile struct pthread *) th; - /* Make sure the descriptor is valid. */ - if (INVALID_TD_P (pd)) - /* Not a valid thread handle. */ - return ESRCH; + if (pd->tid == 0) + /* The thread has already exited on the kernel side. Its outcome + (regular exit, other cancelation) has already been + determined. */ + return 0; static int init_sigcancel = 0; if (atomic_load_relaxed (&init_sigcancel) == 0) diff --git a/nptl/pthread_create.c b/nptl/pthread_create.c index d8ec299cb1..3db0c9fdf4 100644 --- a/nptl/pthread_create.c +++ b/nptl/pthread_create.c @@ -37,6 +37,7 @@ #include #include #include +#include #include @@ -406,8 +407,6 @@ start_thread (void *arg) unwind_buf.priv.data.prev = NULL; unwind_buf.priv.data.cleanup = NULL; - __libc_signal_restore_set (&pd->sigmask); - /* Allow setxid from now onwards. */ if (__glibc_unlikely (atomic_exchange_acq (&pd->setxid_futex, 0) == -2)) futex_wake (&pd->setxid_futex, 1, FUTEX_PRIVATE); @@ -417,6 +416,8 @@ start_thread (void *arg) /* Store the new cleanup handler info. */ THREAD_SETMEM (pd, cleanup_jmp_buf, &unwind_buf); + __libc_signal_restore_set (&pd->sigmask); + LIBC_PROBE (pthread_start, 3, (pthread_t) pd, pd->start_routine, pd->arg); /* Run the code the user provided. */ @@ -485,6 +486,27 @@ start_thread (void *arg) /* This was the last thread. */ exit (0); + /* This prevents sending a signal from this thread to itself during + its final stages. This must come after the exit call above + because atexit handlers must not run with signals blocked. + + Do not block SIGSETXID. The setxid handshake below expects the + signal to be delivered. (SIGSETXID cannot run application code, + nor does it use pthread_kill.) Reuse the pd->sigmask space for + computing the signal mask, to save stack space. */ + __sigfillset (&pd->sigmask); + __sigdelset (&pd->sigmask, SIGSETXID); + INTERNAL_SYSCALL_CALL (rt_sigprocmask, SIG_BLOCK, &pd->sigmask, NULL, + __NSIG_BYTES); + + /* Tell __pthread_kill_internal that this thread is about to exit. + If there is a __pthread_kill_internal in progress, this delays + the thread exit until the signal has been queued by the kernel + (so that the TID used to send it remains valid). */ + __libc_lock_lock (pd->exit_lock); + pd->exiting = true; + __libc_lock_unlock (pd->exit_lock); + #ifndef __ASSUME_SET_ROBUST_LIST /* If this thread has any robust mutexes locked, handle them now. */ # if __PTHREAD_MUTEX_HAVE_PREV diff --git a/nptl/pthread_kill.c b/nptl/pthread_kill.c index f79a2b26fc..35bf1f973e 100644 --- a/nptl/pthread_kill.c +++ b/nptl/pthread_kill.c @@ -16,39 +16,66 @@ License along with the GNU C Library; if not, see . */ +#include #include #include #include -int -__pthread_kill_internal (pthread_t threadid, int signo) +/* Sends SIGNO to THREADID. If the thread is about to exit or has + already exited on the kernel side, return NO_TID. Otherwise return + 0 or an error code. */ +static int +__pthread_kill_implementation (pthread_t threadid, int signo, int no_tid) { - pid_t tid; struct pthread *pd = (struct pthread *) threadid; - if (pd == THREAD_SELF) - /* It is a special case to handle raise() implementation after a vfork - call (which does not update the PD tid field). */ - tid = INLINE_SYSCALL_CALL (gettid); - else - /* Force load of pd->tid into local variable or register. Otherwise - if a thread exits between ESRCH test and tgkill, we might return - EINVAL, because pd->tid would be cleared by the kernel. */ - tid = atomic_forced_read (pd->tid); - - int val; - if (__glibc_likely (tid > 0)) { - pid_t pid = __getpid (); - - val = INTERNAL_SYSCALL_CALL (tgkill, pid, tid, signo); - val = (INTERNAL_SYSCALL_ERROR_P (val) - ? INTERNAL_SYSCALL_ERRNO (val) : 0); + /* Use the actual TID from the kernel, so that it refers to the + current thread even if called after vfork. There is no + signal blocking in this case, so that the signal is delivered + immediately, before __pthread_kill_internal returns: a signal + sent to the thread itself needs to be delivered + synchronously. (It is unclear if Linux guarantees the + delivery of all pending signals after unblocking in the code + below. POSIX only guarantees delivery of a single signal, + which may not be the right one.) */ + pid_t tid = INTERNAL_SYSCALL_CALL (gettid); + int ret = INTERNAL_SYSCALL_CALL (tgkill, __getpid (), tid, signo); + return INTERNAL_SYSCALL_ERROR_P (ret) ? INTERNAL_SYSCALL_ERRNO (ret) : 0; } + + /* Block all signals, as required by pd->exit_lock. */ + sigset_t old_mask; + __libc_signal_block_all (&old_mask); + __libc_lock_lock (pd->exit_lock); + + int ret; + if (pd->exiting) + /* The thread is about to exit (or has exited). Sending the + signal is either not observable (the target thread has already + blocked signals at this point), or it will fail, or it might be + delivered to a new, unrelated thread that has reused the TID. + So do not actually send the signal. */ + ret = no_tid; else - val = ESRCH; + { + ret = INTERNAL_SYSCALL_CALL (tgkill, __getpid (), pd->tid, signo); + ret = INTERNAL_SYSCALL_ERROR_P (ret) ? INTERNAL_SYSCALL_ERRNO (ret) : 0; + } + + __libc_lock_unlock (pd->exit_lock); + __libc_signal_restore_set (&old_mask); - return val; + return ret; +} + +int +__pthread_kill_internal (pthread_t threadid, int signo) +{ + /* Do not report an error in the no-tid case because the threadid + argument is still valid (the thread ID lifetime has not ended), + and ESRCH (for example) would be misleading. */ + return __pthread_kill_implementation (threadid, signo, 0); } int @@ -61,6 +88,7 @@ __pthread_kill (pthread_t threadid, int signo) return __pthread_kill_internal (threadid, signo); } + /* Some architectures (for instance arm) might pull raise through libgcc, so avoid the symbol version if it ends up being used on ld.so. */ #if !IS_IN(rtld) @@ -68,6 +96,17 @@ libc_hidden_def (__pthread_kill) versioned_symbol (libc, __pthread_kill, pthread_kill, GLIBC_2_34); # if OTHER_SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_34) -compat_symbol (libc, __pthread_kill, pthread_kill, GLIBC_2_0); +/* Variant which returns ESRCH in the no-TID case, for backwards + compatibility. */ +int +attribute_compat_text_section +__pthread_kill_esrch (pthread_t threadid, int signo) +{ + if (__is_internal_signal (signo)) + return EINVAL; + + return __pthread_kill_implementation (threadid, signo, ESRCH); +} +compat_symbol (libc, __pthread_kill_esrch, pthread_kill, GLIBC_2_0); # endif #endif diff --git a/nss/tst-nss-files-hosts-long.root/etc/nsswitch.conf b/nss/tst-nss-files-hosts-long.root/etc/nsswitch.conf new file mode 100644 index 0000000000..5b0c6a4199 --- /dev/null +++ b/nss/tst-nss-files-hosts-long.root/etc/nsswitch.conf @@ -0,0 +1 @@ +hosts: files diff --git a/posix/Makefile b/posix/Makefile index 059efb3cd2..09460a28e8 100644 --- a/posix/Makefile +++ b/posix/Makefile @@ -107,7 +107,8 @@ tests := test-errno tstgetopt testfnm runtests runptests \ tst-sysconf-empty-chroot tst-glob_symlinks tst-fexecve \ tst-glob-tilde test-ssize-max tst-spawn4 bug-regex37 \ bug-regex38 tst-regcomp-truncated tst-spawn-chdir \ - tst-wordexp-nocmd tst-execveat tst-spawn5 + tst-wordexp-nocmd tst-execveat tst-spawn5 \ + tst-sched_getaffinity # Test for the glob symbol version that was replaced in glibc 2.27. ifeq ($(have-GLIBC_2.26)$(build-shared),yesyes) diff --git a/posix/bits/unistd.h b/posix/bits/unistd.h index f0831386c7..622adeb2b2 100644 --- a/posix/bits/unistd.h +++ b/posix/bits/unistd.h @@ -199,10 +199,9 @@ __NTH (readlinkat (int __fd, const char *__restrict __path, #endif extern char *__getcwd_chk (char *__buf, size_t __size, size_t __buflen) - __THROW __wur __attr_access ((__write_only__, 1, 2)); + __THROW __wur; extern char *__REDIRECT_NTH (__getcwd_alias, - (char *__buf, size_t __size), getcwd) - __wur __attr_access ((__write_only__, 1, 2)); + (char *__buf, size_t __size), getcwd) __wur; extern char *__REDIRECT_NTH (__getcwd_chk_warn, (char *__buf, size_t __size, size_t __buflen), __getcwd_chk) diff --git a/posix/fork.c b/posix/fork.c index c471f7b15f..021691b9b7 100644 --- a/posix/fork.c +++ b/posix/fork.c @@ -99,6 +99,9 @@ __libc_fork (void) /* Reset the lock the dynamic loader uses to protect its data. */ __rtld_lock_initialize (GL(dl_load_lock)); + /* Reset the lock protecting dynamic TLS related data. */ + __rtld_lock_initialize (GL(dl_load_tls_lock)); + reclaim_stacks (); /* Run the handlers registered for the child. */ diff --git a/posix/tst-sched_getaffinity.c b/posix/tst-sched_getaffinity.c new file mode 100644 index 0000000000..db9d517a96 --- /dev/null +++ b/posix/tst-sched_getaffinity.c @@ -0,0 +1,48 @@ +/* Tests for sched_getaffinity with large buffers. + Copyright (C) 2021 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 + . */ + +#include +#include +#include + +/* NB: this test may fail on system with more than 32k cpus. */ + +static int +do_test (void) +{ + /* The values are larger than the default cpu_set_t. */ + const int bufsize[] = { 1<<11, 1<<12, 1<<13, 1<<14, 1<<15, 1<<16, 1<<17 }; + int cpucount[array_length (bufsize)]; + + for (int i = 0; i < array_length (bufsize); i++) + { + cpu_set_t *cpuset = CPU_ALLOC (bufsize[i]); + TEST_VERIFY (cpuset != NULL); + size_t size = CPU_ALLOC_SIZE (bufsize[i]); + TEST_COMPARE (sched_getaffinity (0, size, cpuset), 0); + cpucount[i] = CPU_COUNT_S (size, cpuset); + CPU_FREE (cpuset); + } + + for (int i = 0; i < array_length (cpucount) - 1; i++) + TEST_COMPARE (cpucount[i], cpucount[i + 1]); + + return 0; +} + +#include diff --git a/posix/tst-spawn5.c b/posix/tst-spawn5.c index ac66738004..a95199af6b 100644 --- a/posix/tst-spawn5.c +++ b/posix/tst-spawn5.c @@ -47,17 +47,6 @@ static int initial_argv_count; #define NFDS 100 -static int -open_multiple_temp_files (void) -{ - /* Check if the temporary file descriptor has no no gaps. */ - int lowfd = xopen ("/dev/null", O_RDONLY, 0600); - for (int i = 1; i <= NFDS; i++) - TEST_COMPARE (xopen ("/dev/null", O_RDONLY, 0600), - lowfd + i); - return lowfd; -} - static int parse_fd (const char *str) { @@ -185,7 +174,7 @@ spawn_closefrom_test (posix_spawn_file_actions_t *fa, int lowfd, int highfd, static void do_test_closefrom (void) { - int lowfd = open_multiple_temp_files (); + int lowfd = support_open_dev_null_range (NFDS, O_RDONLY, 0600); const int half_fd = lowfd + NFDS / 2; /* Close half of the descriptors and check result. */ diff --git a/posix/unistd.h b/posix/unistd.h index 3dca65732f..8224c5fbc9 100644 --- a/posix/unistd.h +++ b/posix/unistd.h @@ -528,8 +528,7 @@ extern int fchdir (int __fd) __THROW __wur; an array is allocated with `malloc'; the array is SIZE bytes long, unless SIZE == 0, in which case it is as big as necessary. */ -extern char *getcwd (char *__buf, size_t __size) __THROW __wur - __attr_access ((__write_only__, 1, 2)); +extern char *getcwd (char *__buf, size_t __size) __THROW __wur; #ifdef __USE_GNU /* Return a malloc'd string containing the current directory name. diff --git a/rt/Makefile b/rt/Makefile index 113cea03a5..910e775995 100644 --- a/rt/Makefile +++ b/rt/Makefile @@ -74,6 +74,7 @@ tests := tst-shm tst-timer tst-timer2 \ tst-aio7 tst-aio8 tst-aio9 tst-aio10 \ tst-mqueue1 tst-mqueue2 tst-mqueue3 tst-mqueue4 \ tst-mqueue5 tst-mqueue6 tst-mqueue7 tst-mqueue8 tst-mqueue9 \ + tst-bz28213 \ tst-timer3 tst-timer4 tst-timer5 \ tst-cpuclock2 tst-cputimer1 tst-cputimer2 tst-cputimer3 \ tst-shm-cancel \ diff --git a/rt/tst-bz28213.c b/rt/tst-bz28213.c new file mode 100644 index 0000000000..0c096b5a0a --- /dev/null +++ b/rt/tst-bz28213.c @@ -0,0 +1,101 @@ +/* Bug 28213: test for NULL pointer dereference in mq_notify. + Copyright (C) The GNU Toolchain Authors. + 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 + . */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static mqd_t m = -1; +static const char msg[] = "hello"; + +static void +check_bz28213_cb (union sigval sv) +{ + char buf[sizeof (msg)]; + + (void) sv; + + TEST_VERIFY_EXIT ((size_t) mq_receive (m, buf, sizeof (buf), NULL) + == sizeof (buf)); + TEST_VERIFY_EXIT (memcmp (buf, msg, sizeof (buf)) == 0); + + exit (0); +} + +static void +check_bz28213 (void) +{ + struct sigevent sev; + + memset (&sev, '\0', sizeof (sev)); + sev.sigev_notify = SIGEV_THREAD; + sev.sigev_notify_function = check_bz28213_cb; + + /* Step 1: Register & unregister notifier. + Helper thread should receive NOTIFY_REMOVED notification. + In a vulnerable version of glibc, NULL pointer dereference follows. */ + TEST_VERIFY_EXIT (mq_notify (m, &sev) == 0); + TEST_VERIFY_EXIT (mq_notify (m, NULL) == 0); + + /* Step 2: Once again, register notification. + Try to send one message. + Test is considered successful, if the callback does exit (0). */ + TEST_VERIFY_EXIT (mq_notify (m, &sev) == 0); + TEST_VERIFY_EXIT (mq_send (m, msg, sizeof (msg), 1) == 0); + + /* Wait... */ + pause (); +} + +static int +do_test (void) +{ + static const char m_name[] = "/bz28213_queue"; + struct mq_attr m_attr; + + memset (&m_attr, '\0', sizeof (m_attr)); + m_attr.mq_maxmsg = 1; + m_attr.mq_msgsize = sizeof (msg); + + m = mq_open (m_name, + O_RDWR | O_CREAT | O_EXCL, + 0600, + &m_attr); + + if (m < 0) + { + if (errno == ENOSYS) + FAIL_UNSUPPORTED ("POSIX message queues are not implemented\n"); + FAIL_EXIT1 ("Failed to create POSIX message queue: %m\n"); + } + + TEST_VERIFY_EXIT (mq_unlink (m_name) == 0); + + check_bz28213 (); + + return 0; +} + +#include diff --git a/scripts/build-many-glibcs.py b/scripts/build-many-glibcs.py index 5a77af90a6..86537fa800 100755 --- a/scripts/build-many-glibcs.py +++ b/scripts/build-many-glibcs.py @@ -782,7 +782,7 @@ class Context(object): 'gcc': 'vcs-11', 'glibc': 'vcs-mainline', 'gmp': '6.2.1', - 'linux': '5.13', + 'linux': '5.14', 'mpc': '1.2.1', 'mpfr': '4.1.0', 'mig': 'vcs-mainline', diff --git a/support/Makefile b/support/Makefile index a462781718..2a0731796f 100644 --- a/support/Makefile +++ b/support/Makefile @@ -66,6 +66,7 @@ libsupport-routines = \ support_path_support_time64 \ support_process_state \ support_ptrace \ + support-open-dev-null-range \ support_openpty \ support_paths \ support_quote_blob \ @@ -82,9 +83,10 @@ libsupport-routines = \ support_test_compare_blob \ support_test_compare_failure \ support_test_compare_string \ - support_write_file_string \ support_test_main \ support_test_verify_impl \ + support_wait_for_thread_exit \ + support_write_file_string \ temp_file \ timespec \ timespec-time64 \ @@ -264,6 +266,7 @@ tests = \ tst-support_capture_subprocess \ tst-support_descriptors \ tst-support_format_dns_packet \ + tst-support-open-dev-null-range \ tst-support-process_state \ tst-support_quote_blob \ tst-support_quote_string \ diff --git a/support/support-open-dev-null-range.c b/support/support-open-dev-null-range.c new file mode 100644 index 0000000000..66a8504105 --- /dev/null +++ b/support/support-open-dev-null-range.c @@ -0,0 +1,134 @@ +/* Return a range of open file descriptors. + Copyright (C) 2021 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 + . */ + +#include +#include +#include +#include +#include +#include +#include + +static void +increase_nofile (void) +{ + struct rlimit rl; + if (getrlimit (RLIMIT_NOFILE, &rl) == -1) + FAIL_EXIT1 ("getrlimit (RLIMIT_NOFILE): %m"); + + rl.rlim_cur += 128; + + if (setrlimit (RLIMIT_NOFILE, &rl) == 1) + FAIL_EXIT1 ("setrlimit (RLIMIT_NOFILE): %m"); +} + +static int +open_dev_null (int flags, mode_t mode) +{ + int fd = open64 ("/dev/null", flags, mode); + if (fd >= 0) + return fd; + + if (fd < 0 && errno != EMFILE) + FAIL_EXIT1 ("open64 (\"/dev/null\", 0x%x, 0%o): %m", flags, mode); + + increase_nofile (); + + return xopen ("/dev/null", flags, mode); +} + +struct range +{ + int lowfd; + size_t len; +}; + +struct range_list +{ + size_t total; + size_t used; + struct range *ranges; +}; + +static void +range_init (struct range_list *r) +{ + r->total = 8; + r->used = 0; + r->ranges = xmalloc (r->total * sizeof (struct range)); +} + +static void +range_add (struct range_list *r, int lowfd, size_t len) +{ + if (r->used == r->total) + { + r->total *= 2; + r->ranges = xrealloc (r->ranges, r->total * sizeof (struct range)); + } + r->ranges[r->used].lowfd = lowfd; + r->ranges[r->used].len = len; + r->used++; +} + +static void +range_close (struct range_list *r) +{ + for (size_t i = 0; i < r->used; i++) + { + int minfd = r->ranges[i].lowfd; + int maxfd = r->ranges[i].lowfd + r->ranges[i].len; + for (int fd = minfd; fd < maxfd; fd++) + xclose (fd); + } + free (r->ranges); +} + +int +support_open_dev_null_range (int num, int flags, mode_t mode) +{ + /* We keep track of the ranges that hit an already opened descriptor, so + we close them after we get a working range. */ + struct range_list rl; + range_init (&rl); + + int lowfd = open_dev_null (flags, mode); + int prevfd = lowfd; + while (true) + { + int i = 1; + for (; i < num; i++) + { + int fd = open_dev_null (flags, mode); + if (fd != lowfd + i) + { + range_add (&rl, lowfd, prevfd - lowfd + 1); + + prevfd = lowfd = fd; + break; + } + prevfd = fd; + } + if (i == num) + break; + } + + range_close (&rl); + + return lowfd; +} diff --git a/support/support.h b/support/support.h index 834dba9097..c219e0d9d1 100644 --- a/support/support.h +++ b/support/support.h @@ -174,6 +174,10 @@ timer_t support_create_timer (uint64_t sec, long int nsec, bool repeat, /* Disable the timer TIMER. */ void support_delete_timer (timer_t timer); +/* Wait until all threads except the current thread have exited (as + far as the kernel is concerned). */ +void support_wait_for_thread_exit (void); + struct support_stack { void *stack; @@ -193,6 +197,14 @@ struct support_stack support_stack_alloc (size_t size); /* Deallocate the STACK. */ void support_stack_free (struct support_stack *stack); + +/* Create a range of NUM opened '/dev/null' file descriptors using FLAGS and + MODE. The function takes care of restarting the open range if a file + descriptor is found within the specified range and also increases + RLIMIT_NOFILE if required. + The returned value is the lowest file descriptor number. */ +int support_open_dev_null_range (int num, int flags, mode_t mode); + __END_DECLS #endif /* SUPPORT_H */ diff --git a/support/support_capture_subprocess.c b/support/support_capture_subprocess.c index 27bfd19c93..0bacf6dbc2 100644 --- a/support/support_capture_subprocess.c +++ b/support/support_capture_subprocess.c @@ -170,6 +170,7 @@ copy_and_spawn_sgid (char *child_id, gid_t gid) support_subprogram because we only want the program exit status, not the contents. */ ret = 0; + infd = outfd = -1; char * const args[] = {execname, child_id, NULL}; diff --git a/support/support_wait_for_thread_exit.c b/support/support_wait_for_thread_exit.c new file mode 100644 index 0000000000..5e3be421a7 --- /dev/null +++ b/support/support_wait_for_thread_exit.c @@ -0,0 +1,75 @@ +/* Wait until all threads except the current thread has exited. + Copyright (C) 2021 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 + . */ + +#include +#include +#include +#include +#include +#include + +void +support_wait_for_thread_exit (void) +{ +#ifdef __linux__ + DIR *proc_self_task = opendir ("/proc/self/task"); + TEST_VERIFY_EXIT (proc_self_task != NULL); + + while (true) + { + errno = 0; + struct dirent *e = readdir (proc_self_task); + if (e == NULL && errno != 0) + FAIL_EXIT1 ("readdir: %m"); + if (e == NULL) + { + /* Only the main thread remains. Testing may continue. */ + closedir (proc_self_task); + return; + } + + /* In some kernels, "0" entries denote a thread that has just + exited. */ + if (strcmp (e->d_name, ".") == 0 || strcmp (e->d_name, "..") == 0 + || strcmp (e->d_name, "0") == 0) + continue; + + int task_tid = atoi (e->d_name); + if (task_tid <= 0) + FAIL_EXIT1 ("Invalid /proc/self/task entry: %s", e->d_name); + + if (task_tid == gettid ()) + /* The current thread. Keep scanning for other + threads. */ + continue; + + /* task_tid does not refer to this thread here, i.e., there is + another running thread. */ + + /* Small timeout to give the thread a chance to exit. */ + usleep (50 * 1000); + + /* Start scanning the directory from the start. */ + rewinddir (proc_self_task); + } +#else + /* Use a large timeout because we cannot verify that the thread has + exited. */ + usleep (5 * 1000 * 1000); +#endif +} diff --git a/support/tst-support-open-dev-null-range.c b/support/tst-support-open-dev-null-range.c new file mode 100644 index 0000000000..8e29def1ce --- /dev/null +++ b/support/tst-support-open-dev-null-range.c @@ -0,0 +1,155 @@ +/* Tests for support_open_dev_null_range. + Copyright (C) 2021 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 + . */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef PATH_MAX +# define PATH_MAX 1024 +#endif + +#include + +static void +check_path (int fd) +{ + char *proc_fd_path = xasprintf ("/proc/self/fd/%d", fd); + char file_path[PATH_MAX]; + ssize_t file_path_length + = readlink (proc_fd_path, file_path, sizeof (file_path)); + free (proc_fd_path); + if (file_path_length < 0) + FAIL_EXIT1 ("readlink (%s, %p, %zu)", proc_fd_path, file_path, + sizeof (file_path)); + file_path[file_path_length] = '\0'; + TEST_COMPARE_STRING (file_path, "/dev/null"); +} + +static int +number_of_opened_files (void) +{ + DIR *fds = opendir ("/proc/self/fd"); + if (fds == NULL) + FAIL_EXIT1 ("opendir (\"/proc/self/fd\"): %m"); + + int r = 0; + while (true) + { + errno = 0; + struct dirent64 *e = readdir64 (fds); + if (e == NULL) + { + if (errno != 0) + FAIL_EXIT1 ("readdir: %m"); + break; + } + + if (e->d_name[0] == '.') + continue; + + char *endptr; + long int fd = strtol (e->d_name, &endptr, 10); + if (*endptr != '\0' || fd < 0 || fd > INT_MAX) + FAIL_EXIT1 ("readdir: invalid file descriptor name: /proc/self/fd/%s", + e->d_name); + + /* Skip the descriptor which is used to enumerate the + descriptors. */ + if (fd == dirfd (fds)) + continue; + + r = r + 1; + } + + closedir (fds); + + return r; +} + +static int +do_test (void) +{ + const int nfds1 = 8; + int lowfd = support_open_dev_null_range (nfds1, O_RDONLY, 0600); + for (int i = 0; i < nfds1; i++) + { + TEST_VERIFY (fcntl (lowfd + i, F_GETFL) > -1); + check_path (lowfd + i); + } + + /* create some gaps. */ + xclose (lowfd + 1); + xclose (lowfd + 5); + xclose (lowfd + 6); + + const int nfds2 = 16; + int lowfd2 = support_open_dev_null_range (nfds2, O_RDONLY, 0600); + for (int i = 0; i < nfds2; i++) + { + TEST_VERIFY (fcntl (lowfd2 + i, F_GETFL) > -1); + check_path (lowfd2 + i); + } + + /* Decrease the maximum number of files. */ + { + struct rlimit rl; + if (getrlimit (RLIMIT_NOFILE, &rl) == -1) + FAIL_EXIT1 ("getrlimit (RLIMIT_NOFILE): %m"); + + rl.rlim_cur = number_of_opened_files (); + + if (setrlimit (RLIMIT_NOFILE, &rl) == 1) + FAIL_EXIT1 ("setrlimit (RLIMIT_NOFILE): %m"); + } + + const int nfds3 = 16; + int lowfd3 = support_open_dev_null_range (nfds3, O_RDONLY, 0600); + for (int i = 0; i < nfds3; i++) + { + TEST_VERIFY (fcntl (lowfd3 + i, F_GETFL) > -1); + check_path (lowfd3 + i); + } + + /* create a lot of gaps to trigger the range extension. */ + xclose (lowfd3 + 1); + xclose (lowfd3 + 3); + xclose (lowfd3 + 5); + xclose (lowfd3 + 7); + xclose (lowfd3 + 9); + xclose (lowfd3 + 11); + xclose (lowfd3 + 13); + + const int nfds4 = 16; + int lowfd4 = support_open_dev_null_range (nfds4, O_RDONLY, 0600); + for (int i = 0; i < nfds4; i++) + { + TEST_VERIFY (fcntl (lowfd4 + i, F_GETFL) > -1); + check_path (lowfd4 + i); + } + + return 0; +} + +#include diff --git a/sysdeps/generic/dl-relocate-ld.h b/sysdeps/generic/dl-relocate-ld.h new file mode 100644 index 0000000000..cfb86c2d6a --- /dev/null +++ b/sysdeps/generic/dl-relocate-ld.h @@ -0,0 +1,25 @@ +/* Check if dynamic section should be relocated. Generic version. + Copyright (C) 2021 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 + . */ + +#ifndef _DL_RELOCATE_LD_H +#define _DL_RELOCATE_LD_H + +/* The dynamic section is writable. */ +#define DL_RO_DYN_SECTION 0 + +#endif /* _DL_RELOCATE_LD_H */ diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h index 9c15259236..fcbbf69748 100644 --- a/sysdeps/generic/ldsodefs.h +++ b/sysdeps/generic/ldsodefs.h @@ -69,17 +69,24 @@ __BEGIN_DECLS `ElfW(TYPE)' is used in place of `Elf32_TYPE' or `Elf64_TYPE'. */ #define ELFW(type) _ElfW (ELF, __ELF_NATIVE_CLASS, type) +/* Return true if dynamic section in the shared library L should be + relocated. */ + +static inline bool +dl_relocate_ld (const struct link_map *l) +{ + /* Don't relocate dynamic section if it is readonly */ + return !(l->l_ld_readonly || DL_RO_DYN_SECTION); +} + /* All references to the value of l_info[DT_PLTGOT], l_info[DT_STRTAB], l_info[DT_SYMTAB], l_info[DT_RELA], l_info[DT_REL], l_info[DT_JMPREL], and l_info[VERSYMIDX (DT_VERSYM)] have to be accessed via the D_PTR macro. The macro is needed since for most architectures the entry is already relocated - but for some not and we need to relocate at access time. */ -#ifdef DL_RO_DYN_SECTION -# define D_PTR(map, i) ((map)->i->d_un.d_ptr + (map)->l_addr) -#else -# define D_PTR(map, i) (map)->i->d_un.d_ptr -#endif +#define D_PTR(map, i) \ + ((map)->i->d_un.d_ptr + (dl_relocate_ld (map) ? 0 : (map)->l_addr)) /* Result of the lookup functions and how to retrieve the base address. */ typedef struct link_map *lookup_t; @@ -372,6 +379,13 @@ struct rtld_global list of loaded objects while an object is added to or removed from that list. */ __rtld_lock_define_recursive (EXTERN, _dl_load_write_lock) + /* This lock protects global and module specific TLS related data. + E.g. it is held in dlopen and dlclose when GL(dl_tls_generation), + GL(dl_tls_max_dtv_idx) or GL(dl_tls_dtv_slotinfo_list) are + accessed and when TLS related relocations are processed for a + module. It was introduced to keep pthread_create accessing TLS + state that is being set up. */ + __rtld_lock_define_recursive (EXTERN, _dl_load_tls_lock) /* Incremented whenever something may have been added to dl_loaded. */ EXTERN unsigned long long _dl_load_adds; @@ -1261,7 +1275,7 @@ extern int _dl_scope_free (void *) attribute_hidden; /* Add module to slot information data. If DO_ADD is false, only the required memory is allocated. Must be called with GL - (dl_load_lock) acquired. If the function has already been called + (dl_load_tls_lock) acquired. If the function has already been called for the link map L with !do_add, then this function will not raise an exception, otherwise it is possible that it encounters a memory allocation failure. */ diff --git a/sysdeps/mach/getsysstats.c b/sysdeps/mach/getsysstats.c index 1267f39da2..cc8023f979 100644 --- a/sysdeps/mach/getsysstats.c +++ b/sysdeps/mach/getsysstats.c @@ -62,6 +62,12 @@ __get_nprocs (void) libc_hidden_def (__get_nprocs) weak_alias (__get_nprocs, get_nprocs) +int +__get_nprocs_sched (void) +{ + return __get_nprocs (); +} + /* Return the number of physical pages on the system. */ long int __get_phys_pages (void) diff --git a/sysdeps/mips/dl-relocate-ld.h b/sysdeps/mips/dl-relocate-ld.h new file mode 100644 index 0000000000..376ad75dd1 --- /dev/null +++ b/sysdeps/mips/dl-relocate-ld.h @@ -0,0 +1,25 @@ +/* Check if dynamic section should be relocated. MIPS version. + Copyright (C) 2021 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 + . */ + +#ifndef _DL_RELOCATE_LD_H +#define _DL_RELOCATE_LD_H + +/* The dynamic section is readonly. */ +#define DL_RO_DYN_SECTION 1 + +#endif /* _DL_RELOCATE_LD_H */ diff --git a/sysdeps/mips/ldsodefs.h b/sysdeps/mips/ldsodefs.h index 4db7c60e38..36fd09a8bd 100644 --- a/sysdeps/mips/ldsodefs.h +++ b/sysdeps/mips/ldsodefs.h @@ -75,10 +75,6 @@ struct La_mips_64_retval; struct La_mips_64_retval *, \ const char *); -/* The MIPS ABI specifies that the dynamic section has to be read-only. */ - -#define DL_RO_DYN_SECTION 1 - #include_next /* The 64-bit MIPS ELF ABI uses an unusual reloc format. Each diff --git a/sysdeps/nptl/pthread.h b/sysdeps/nptl/pthread.h index f1b7f2bdc6..43146e91c9 100644 --- a/sysdeps/nptl/pthread.h +++ b/sysdeps/nptl/pthread.h @@ -933,7 +933,7 @@ extern int pthread_mutexattr_getrobust (const pthread_mutexattr_t *__attr, # ifdef __USE_GNU # ifdef __REDIRECT_NTH extern int __REDIRECT_NTH (pthread_mutexattr_getrobust_np, - (pthread_mutex_t *, int *), + (pthread_mutexattr_t *, int *), pthread_mutexattr_getrobust) __nonnull ((1)) __attribute_deprecated_msg__ ("\ pthread_mutexattr_getrobust_np is deprecated, use pthread_mutexattr_getrobust"); @@ -949,7 +949,7 @@ extern int pthread_mutexattr_setrobust (pthread_mutexattr_t *__attr, # ifdef __USE_GNU # ifdef __REDIRECT_NTH extern int __REDIRECT_NTH (pthread_mutexattr_setrobust_np, - (pthread_mutex_t *, int), + (pthread_mutexattr_t *, int), pthread_mutexattr_setrobust) __nonnull ((1)) __attribute_deprecated_msg__ ("\ pthread_mutexattr_setrobust_np is deprecated, use pthread_mutexattr_setrobust"); diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c index 838a68f022..43dfc6739e 100644 --- a/sysdeps/posix/getaddrinfo.c +++ b/sysdeps/posix/getaddrinfo.c @@ -2008,6 +2008,7 @@ gaiconf_init (void) l = l->next; } free_prefixlist (labellist); + labellist = NULL; /* Sort the entries so that the most specific ones are at the beginning. */ @@ -2046,6 +2047,7 @@ gaiconf_init (void) l = l->next; } free_prefixlist (precedencelist); + precedencelist = NULL; /* Sort the entries so that the most specific ones are at the beginning. */ diff --git a/sysdeps/powerpc/powerpc64/sysdep.h b/sysdeps/powerpc/powerpc64/sysdep.h index 589f7c8d18..cfcfa69f91 100644 --- a/sysdeps/powerpc/powerpc64/sysdep.h +++ b/sysdeps/powerpc/powerpc64/sysdep.h @@ -275,12 +275,14 @@ LT_LABELSUFFIX(name,_name_end): ; \ /* Allocate frame and save register */ #define NVOLREG_SAVE \ stdu r1,-SCV_FRAME_SIZE(r1); \ + cfi_adjust_cfa_offset(SCV_FRAME_SIZE); \ std r31,SCV_FRAME_NVOLREG_SAVE(r1); \ - cfi_adjust_cfa_offset(SCV_FRAME_SIZE); + cfi_rel_offset(r31,SCV_FRAME_NVOLREG_SAVE); /* Restore register and destroy frame */ #define NVOLREG_RESTORE \ ld r31,SCV_FRAME_NVOLREG_SAVE(r1); \ + cfi_restore(r31); \ addi r1,r1,SCV_FRAME_SIZE; \ cfi_adjust_cfa_offset(-SCV_FRAME_SIZE); @@ -331,13 +333,13 @@ LT_LABELSUFFIX(name,_name_end): ; \ #define DO_CALL_SCV \ mflr r9; \ - std r9,FRAME_LR_SAVE(r1); \ - cfi_offset(lr,FRAME_LR_SAVE); \ + std r9,SCV_FRAME_SIZE+FRAME_LR_SAVE(r1); \ + cfi_rel_offset(lr,SCV_FRAME_SIZE+FRAME_LR_SAVE); \ .machine "push"; \ .machine "power9"; \ scv 0; \ .machine "pop"; \ - ld r9,FRAME_LR_SAVE(r1); \ + ld r9,SCV_FRAME_SIZE+FRAME_LR_SAVE(r1); \ mtlr r9; \ cfi_restore(lr); diff --git a/sysdeps/pthread/Makefile b/sysdeps/pthread/Makefile index 42f9fc5072..c657101696 100644 --- a/sysdeps/pthread/Makefile +++ b/sysdeps/pthread/Makefile @@ -89,7 +89,7 @@ tests += tst-cnd-basic tst-mtx-trylock tst-cnd-broadcast \ tst-join8 tst-join9 tst-join10 tst-join11 tst-join12 tst-join13 \ tst-join14 tst-join15 \ tst-key1 tst-key2 tst-key3 tst-key4 \ - tst-kill1 tst-kill2 tst-kill3 tst-kill4 tst-kill5 tst-kill6 \ + tst-kill1 tst-kill2 tst-kill3 tst-kill5 tst-kill6 \ tst-locale1 tst-locale2 \ tst-memstream \ tst-mutex-errorcheck tst-mutex1 tst-mutex2 tst-mutex3 tst-mutex4 \ @@ -118,6 +118,14 @@ tests += tst-cnd-basic tst-mtx-trylock tst-cnd-broadcast \ tst-unload \ tst-unwind-thread \ tst-pt-vfork1 tst-pt-vfork2 tst-vfork1x tst-vfork2x \ + tst-pthread-exit-signal \ + tst-pthread-setuid-loop \ + tst-pthread_cancel-exited \ + tst-pthread_cancel-select-loop \ + tst-pthread-raise-blocked-self \ + tst-pthread_kill-exited \ + tst-pthread_kill-exiting \ + # tests tests-time64 := \ tst-abstime-time64 \ @@ -145,15 +153,17 @@ tests += tst-cancelx2 tst-cancelx3 tst-cancelx6 tst-cancelx8 tst-cancelx9 \ tst-cleanupx0 tst-cleanupx1 tst-cleanupx2 tst-cleanupx3 ifeq ($(build-shared),yes) -tests += tst-atfork2 tst-pt-tls4 tst-_res1 tst-fini1 +tests += tst-atfork2 tst-pt-tls4 tst-_res1 tst-fini1 tst-create1 tests-nolibpthread += tst-fini1 endif modules-names += tst-atfork2mod tst-tls4moda tst-tls4modb \ - tst-_res1mod1 tst-_res1mod2 tst-fini1mod + tst-_res1mod1 tst-_res1mod2 tst-fini1mod \ + tst-create1mod test-modules = $(addprefix $(objpfx),$(addsuffix .so,$(modules-names))) tst-atfork2mod.so-no-z-defs = yes +tst-create1mod.so-no-z-defs = yes ifeq ($(build-shared),yes) # Build all the modules even when not actually running test programs. @@ -272,4 +282,8 @@ LDFLAGS-tst-join7mod.so = -Wl,-soname,tst-join7mod.so CFLAGS-tst-unwind-thread.c += -funwind-tables +LDFLAGS-tst-create1 = -Wl,-export-dynamic +$(objpfx)tst-create1: $(shared-thread-library) +$(objpfx)tst-create1.out: $(objpfx)tst-create1mod.so + endif diff --git a/sysdeps/pthread/tst-create1.c b/sysdeps/pthread/tst-create1.c new file mode 100644 index 0000000000..763ded8d79 --- /dev/null +++ b/sysdeps/pthread/tst-create1.c @@ -0,0 +1,123 @@ +/* Verify that pthread_create does not deadlock when ctors take locks. + Copyright (C) 2021 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 + . */ + +#include +#include +#include + +/* +Check if ctor and pthread_create deadlocks in + +thread 1: dlopen -> ctor -> lock(user_lock) +thread 2: lock(user_lock) -> pthread_create + +or in + +thread 1: dlclose -> dtor -> lock(user_lock) +thread 2: lock(user_lock) -> pthread_create +*/ + +static pthread_barrier_t bar_ctor; +static pthread_barrier_t bar_ctor_finish; +static pthread_barrier_t bar_dtor; +static pthread_mutex_t user_lock = PTHREAD_MUTEX_INITIALIZER; + +void +ctor (void) +{ + xpthread_barrier_wait (&bar_ctor); + dprintf (1, "thread 1: in ctor: started.\n"); + xpthread_mutex_lock (&user_lock); + dprintf (1, "thread 1: in ctor: locked user_lock.\n"); + xpthread_mutex_unlock (&user_lock); + dprintf (1, "thread 1: in ctor: unlocked user_lock.\n"); + dprintf (1, "thread 1: in ctor: done.\n"); + xpthread_barrier_wait (&bar_ctor_finish); +} + +void +dtor (void) +{ + xpthread_barrier_wait (&bar_dtor); + dprintf (1, "thread 1: in dtor: started.\n"); + xpthread_mutex_lock (&user_lock); + dprintf (1, "thread 1: in dtor: locked user_lock.\n"); + xpthread_mutex_unlock (&user_lock); + dprintf (1, "thread 1: in dtor: unlocked user_lock.\n"); + dprintf (1, "thread 1: in dtor: done.\n"); +} + +static void * +thread3 (void *a) +{ + dprintf (1, "thread 3: started.\n"); + dprintf (1, "thread 3: done.\n"); + return 0; +} + +static void * +thread2 (void *a) +{ + pthread_t t3; + dprintf (1, "thread 2: started.\n"); + + xpthread_mutex_lock (&user_lock); + dprintf (1, "thread 2: locked user_lock.\n"); + xpthread_barrier_wait (&bar_ctor); + t3 = xpthread_create (0, thread3, 0); + xpthread_mutex_unlock (&user_lock); + dprintf (1, "thread 2: unlocked user_lock.\n"); + xpthread_join (t3); + xpthread_barrier_wait (&bar_ctor_finish); + + xpthread_mutex_lock (&user_lock); + dprintf (1, "thread 2: locked user_lock.\n"); + xpthread_barrier_wait (&bar_dtor); + t3 = xpthread_create (0, thread3, 0); + xpthread_mutex_unlock (&user_lock); + dprintf (1, "thread 2: unlocked user_lock.\n"); + xpthread_join (t3); + + dprintf (1, "thread 2: done.\n"); + return 0; +} + +static void +thread1 (void) +{ + dprintf (1, "thread 1: started.\n"); + xpthread_barrier_init (&bar_ctor, NULL, 2); + xpthread_barrier_init (&bar_ctor_finish, NULL, 2); + xpthread_barrier_init (&bar_dtor, NULL, 2); + pthread_t t2 = xpthread_create (0, thread2, 0); + void *p = xdlopen ("tst-create1mod.so", RTLD_NOW | RTLD_GLOBAL); + dprintf (1, "thread 1: dlopen done.\n"); + xdlclose (p); + dprintf (1, "thread 1: dlclose done.\n"); + xpthread_join (t2); + dprintf (1, "thread 1: done.\n"); +} + +static int +do_test (void) +{ + thread1 (); + return 0; +} + +#include diff --git a/sysdeps/pthread/tst-create1mod.c b/sysdeps/pthread/tst-create1mod.c new file mode 100644 index 0000000000..62c9006961 --- /dev/null +++ b/sysdeps/pthread/tst-create1mod.c @@ -0,0 +1,41 @@ +/* Verify that pthread_create does not deadlock when ctors take locks. + Copyright (C) 2021 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 + . */ + +#include + +/* Require TLS setup for the module. */ +__thread int tlsvar; + +void ctor (void); +void dtor (void); + +static void __attribute__ ((constructor)) +do_init (void) +{ + dprintf (1, "constructor started: %d.\n", tlsvar++); + ctor (); + dprintf (1, "constructor done: %d.\n", tlsvar++); +} + +static void __attribute__ ((destructor)) +do_end (void) +{ + dprintf (1, "destructor started: %d.\n", tlsvar++); + dtor (); + dprintf (1, "destructor done: %d.\n", tlsvar++); +} diff --git a/sysdeps/pthread/tst-kill4.c b/sysdeps/pthread/tst-kill4.c deleted file mode 100644 index 9563939792..0000000000 --- a/sysdeps/pthread/tst-kill4.c +++ /dev/null @@ -1,90 +0,0 @@ -/* Copyright (C) 2003-2021 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Ulrich Drepper , 2003. - - 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 - . */ - -#include -#include -#include -#include -#include -#include - - -static void * -tf (void *a) -{ - return NULL; -} - - -int -do_test (void) -{ - pthread_attr_t at; - if (pthread_attr_init (&at) != 0) - { - puts ("attr_create failed"); - exit (1); - } - - /* Limit thread stack size, because if it is too large, pthread_join - will free it immediately rather than put it into stack cache. */ - if (pthread_attr_setstacksize (&at, 2 * 1024 * 1024) != 0) - { - puts ("setstacksize failed"); - exit (1); - } - - pthread_t th; - if (pthread_create (&th, &at, tf, NULL) != 0) - { - puts ("create failed"); - exit (1); - } - - pthread_attr_destroy (&at); - - if (pthread_join (th, NULL) != 0) - { - puts ("join failed"); - exit (1); - } - - /* The following only works because we assume here something about - the implementation. Namely, that the memory allocated for the - thread descriptor is not going away, that the TID field is - cleared and therefore the signal is sent to process 0, and that - we can savely assume there is no other process with this ID at - that time. */ - int e = pthread_kill (th, 0); - if (e == 0) - { - puts ("pthread_kill succeeded"); - exit (1); - } - if (e != ESRCH) - { - puts ("pthread_kill didn't return ESRCH"); - exit (1); - } - - return 0; -} - - -#define TEST_FUNCTION do_test () -#include "../test-skeleton.c" diff --git a/sysdeps/pthread/tst-pthread-exit-signal.c b/sysdeps/pthread/tst-pthread-exit-signal.c new file mode 100644 index 0000000000..b4526fe663 --- /dev/null +++ b/sysdeps/pthread/tst-pthread-exit-signal.c @@ -0,0 +1,45 @@ +/* Test that pending signals are not delivered on thread exit (bug 28607). + Copyright (C) 2021 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 + . */ + +/* Due to bug 28607, pthread_kill (or pthread_cancel) restored the + signal mask during during thread exit, triggering the delivery of a + blocked pending signal (SIGUSR1 in this test). */ + +#include +#include + +static void * +threadfunc (void *closure) +{ + sigset_t sigmask; + sigfillset (&sigmask); + xpthread_sigmask (SIG_SETMASK, &sigmask, NULL); + xpthread_kill (pthread_self (), SIGUSR1); + pthread_exit (NULL); + return NULL; +} + +static int +do_test (void) +{ + pthread_t thr = xpthread_create (NULL, threadfunc, NULL); + xpthread_join (thr); + return 0; +} + +#include diff --git a/sysdeps/pthread/tst-pthread-raise-blocked-self.c b/sysdeps/pthread/tst-pthread-raise-blocked-self.c new file mode 100644 index 0000000000..128e1a6071 --- /dev/null +++ b/sysdeps/pthread/tst-pthread-raise-blocked-self.c @@ -0,0 +1,92 @@ +/* Test that raise sends signal to current thread even if blocked. + Copyright (C) 2021 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 + . */ + +#include +#include +#include +#include +#include +#include + +/* Used to create a dummy thread ID distinct from all other thread + IDs. */ +static void * +noop (void *ignored) +{ + return NULL; +} + +static volatile pthread_t signal_thread; + +static void +signal_handler (int signo) +{ + signal_thread = pthread_self (); +} + +/* Used to ensure that waiting_thread has launched and can accept + signals. */ +static pthread_barrier_t barrier; + +static void * +waiting_thread (void *ignored) +{ + xpthread_barrier_wait (&barrier); + pause (); + return NULL; +} + +static int +do_test (void) +{ + xsignal (SIGUSR1, signal_handler); + xpthread_barrier_init (&barrier, NULL, 2); + + /* Distinct thread ID value to */ + pthread_t dummy = xpthread_create (NULL, noop, NULL); + signal_thread = dummy; + + pthread_t helper = xpthread_create (NULL, waiting_thread, NULL); + + /* Make sure that the thread is running. */ + xpthread_barrier_wait (&barrier); + + /* Block signals on this thread. */ + sigset_t set; + sigfillset (&set); + xpthread_sigmask (SIG_BLOCK, &set, NULL); + + /* Send the signal to this thread. It must not be delivered. */ + raise (SIGUSR1); + TEST_VERIFY (signal_thread == dummy); + + /* Wait a bit to give a chance for signal delivery (increases + chances of failure with bug 28407). */ + usleep (50 * 1000); + + /* Unblocking should cause synchronous delivery of the signal. */ + xpthread_sigmask (SIG_UNBLOCK, &set, NULL); + TEST_VERIFY (signal_thread == pthread_self ()); + + xpthread_cancel (helper); + xpthread_join (helper); + xpthread_join (dummy); + return 0; +} + +#include diff --git a/sysdeps/pthread/tst-pthread-setuid-loop.c b/sysdeps/pthread/tst-pthread-setuid-loop.c new file mode 100644 index 0000000000..fda2a49b7f --- /dev/null +++ b/sysdeps/pthread/tst-pthread-setuid-loop.c @@ -0,0 +1,61 @@ +/* Test that setuid, pthread_create, thread exit do not deadlock (bug 28361). + Copyright (C) 2021 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 + . */ + +#include +#include +#include + +/* How many threads to launch during each iteration. */ +enum { threads = 4 }; + +/* How many iterations to perform. This value seems to reproduce + bug 28361 in a bout one in three runs. */ +enum { iterations = 5000 }; + +/* Cache of the real user ID used by setuid_thread. */ +static uid_t uid; + +/* Start routine for the threads. */ +static void * +setuid_thread (void *closure) +{ + TEST_COMPARE (setuid (uid), 0); + return NULL; +} + +static int +do_test (void) +{ + /* The setxid machinery is still invoked even if the UID is + unchanged. (The kernel might reset other credentials as part of + the system call.) */ + uid = getuid (); + + for (int i = 0; i < iterations; ++i) + { + pthread_t thread_ids[threads]; + for (int j = 0; j < threads; ++j) + thread_ids[j] = xpthread_create (NULL, setuid_thread, NULL); + for (int j = 0; j < threads; ++j) + xpthread_join (thread_ids[j]); + } + + return 0; +} + +#include diff --git a/sysdeps/pthread/tst-pthread_cancel-exited.c b/sysdeps/pthread/tst-pthread_cancel-exited.c new file mode 100644 index 0000000000..811c9bee07 --- /dev/null +++ b/sysdeps/pthread/tst-pthread_cancel-exited.c @@ -0,0 +1,45 @@ +/* Test that pthread_kill succeeds for an exited thread. + Copyright (C) 2021 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 + . */ + +/* This test verifies that pthread_kill returns 0 (and not ESRCH) for + a thread that has exited on the kernel side. */ + +#include +#include +#include + +static void * +noop_thread (void *closure) +{ + return NULL; +} + +static int +do_test (void) +{ + pthread_t thr = xpthread_create (NULL, noop_thread, NULL); + + support_wait_for_thread_exit (); + + xpthread_cancel (thr); + xpthread_join (thr); + + return 0; +} + +#include diff --git a/sysdeps/pthread/tst-pthread_cancel-select-loop.c b/sysdeps/pthread/tst-pthread_cancel-select-loop.c new file mode 100644 index 0000000000..a62087589c --- /dev/null +++ b/sysdeps/pthread/tst-pthread_cancel-select-loop.c @@ -0,0 +1,87 @@ +/* Test that pthread_cancel succeeds during thread exit. + Copyright (C) 2021 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 + . */ + +/* This test tries to trigger an internal race condition in + pthread_cancel, where the cancellation signal is sent after the + thread has begun the cancellation process. This can result in a + spurious ESRCH error. For the original bug 12889, the window is + quite small, so the bug was not reproduced in every run. */ + +#include +#include +#include +#include +#include +#include +#include + +/* Set to true by timeout_thread_function when the test should + terminate. */ +static bool timeout; + +static void * +timeout_thread_function (void *unused) +{ + usleep (5 * 1000 * 1000); + __atomic_store_n (&timeout, true, __ATOMIC_RELAXED); + return NULL; +} + +/* Used for blocking the select function below. */ +static int pipe_fds[2]; + +static void * +canceled_thread_function (void *unused) +{ + while (true) + { + fd_set rfs; + fd_set wfs; + fd_set efs; + FD_ZERO (&rfs); + FD_ZERO (&wfs); + FD_ZERO (&efs); + FD_SET (pipe_fds[0], &rfs); + + /* If the cancellation request is recognized early, the thread + begins exiting while the cancellation signal arrives. */ + select (FD_SETSIZE, &rfs, &wfs, &efs, NULL); + } + return NULL; +} + +static int +do_test (void) +{ + xpipe (pipe_fds); + pthread_t thr_timeout = xpthread_create (NULL, timeout_thread_function, NULL); + + while (!__atomic_load_n (&timeout, __ATOMIC_RELAXED)) + { + pthread_t thr = xpthread_create (NULL, canceled_thread_function, NULL); + xpthread_cancel (thr); + TEST_VERIFY (xpthread_join (thr) == PTHREAD_CANCELED); + } + + xpthread_join (thr_timeout); + xclose (pipe_fds[0]); + xclose (pipe_fds[1]); + return 0; +} + +#include diff --git a/sysdeps/pthread/tst-pthread_kill-exited.c b/sysdeps/pthread/tst-pthread_kill-exited.c new file mode 100644 index 0000000000..a2fddad526 --- /dev/null +++ b/sysdeps/pthread/tst-pthread_kill-exited.c @@ -0,0 +1,63 @@ +/* Test that pthread_kill succeeds for an exited thread. + Copyright (C) 2021 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 + . */ + +/* This test verifies that the default pthread_kill returns 0 (and not + ESRCH) for a thread that has exited on the kernel side. */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static void * +noop_thread (void *closure) +{ + return NULL; +} + +#if TEST_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_34) && PTHREAD_IN_LIBC +extern __typeof (pthread_kill) compat_pthread_kill; +compat_symbol_reference (libpthread, compat_pthread_kill, pthread_kill, + GLIBC_2_0); +#endif + +static int +do_test (void) +{ + pthread_t thr = xpthread_create (NULL, noop_thread, NULL); + + support_wait_for_thread_exit (); + + /* NB: Always uses the default symbol due to separate compilation. */ + xpthread_kill (thr, SIGUSR1); + +#if TEST_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_34) && PTHREAD_IN_LIBC + /* Old binaries need the non-conforming ESRCH error code. */ + TEST_COMPARE (compat_pthread_kill (thr, SIGUSR1), ESRCH); +#endif + + xpthread_join (thr); + + return 0; +} + +#include diff --git a/sysdeps/pthread/tst-pthread_kill-exiting.c b/sysdeps/pthread/tst-pthread_kill-exiting.c new file mode 100644 index 0000000000..f803e94f11 --- /dev/null +++ b/sysdeps/pthread/tst-pthread_kill-exiting.c @@ -0,0 +1,123 @@ +/* Test that pthread_kill succeeds during thread exit. + Copyright (C) 2021 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 + . */ + +/* This test verifies that pthread_kill for a thread that is exiting + succeeds (with or without actually delivering the signal). */ + +#include +#include +#include +#include +#include +#include + +/* Set to true by timeout_thread_function when the test should + terminate. */ +static bool timeout; + +static void * +timeout_thread_function (void *unused) +{ + usleep (1000 * 1000); + __atomic_store_n (&timeout, true, __ATOMIC_RELAXED); + return NULL; +} + +/* Used to synchronize the sending threads with the target thread and + main thread. */ +static pthread_barrier_t barrier_1; +static pthread_barrier_t barrier_2; + +/* The target thread to which signals are to be sent. */ +static pthread_t target_thread; + +/* Set by the main thread to true after timeout has been set to + true. */ +static bool exiting; + +static void * +sender_thread_function (void *unused) +{ + while (true) + { + /* Wait until target_thread has been initialized. The target + thread and main thread participate in this barrier. */ + xpthread_barrier_wait (&barrier_1); + + if (exiting) + break; + + xpthread_kill (target_thread, SIGUSR1); + + /* Communicate that the signal has been sent. The main thread + participates in this barrier. */ + xpthread_barrier_wait (&barrier_2); + } + return NULL; +} + +static void * +target_thread_function (void *unused) +{ + target_thread = pthread_self (); + xpthread_barrier_wait (&barrier_1); + return NULL; +} + +static int +do_test (void) +{ + xsignal (SIGUSR1, SIG_IGN); + + pthread_t thr_timeout = xpthread_create (NULL, timeout_thread_function, NULL); + + pthread_t threads[4]; + xpthread_barrier_init (&barrier_1, NULL, array_length (threads) + 2); + xpthread_barrier_init (&barrier_2, NULL, array_length (threads) + 1); + + for (int i = 0; i < array_length (threads); ++i) + threads[i] = xpthread_create (NULL, sender_thread_function, NULL); + + while (!__atomic_load_n (&timeout, __ATOMIC_RELAXED)) + { + xpthread_create (NULL, target_thread_function, NULL); + + /* Wait for the target thread to be set up and signal sending to + start. */ + xpthread_barrier_wait (&barrier_1); + + /* Wait for signal sending to complete. */ + xpthread_barrier_wait (&barrier_2); + + xpthread_join (target_thread); + } + + exiting = true; + + /* Signal the sending threads to exit. */ + xpthread_create (NULL, target_thread_function, NULL); + xpthread_barrier_wait (&barrier_1); + + for (int i = 0; i < array_length (threads); ++i) + xpthread_join (threads[i]); + xpthread_join (thr_timeout); + + return 0; +} + +#include diff --git a/sysdeps/riscv/dl-relocate-ld.h b/sysdeps/riscv/dl-relocate-ld.h new file mode 100644 index 0000000000..2ab2b8ac6c --- /dev/null +++ b/sysdeps/riscv/dl-relocate-ld.h @@ -0,0 +1,25 @@ +/* Check if dynamic section should be relocated. RISC-V version. + Copyright (C) 2021 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 + . */ + +#ifndef _DL_RELOCATE_LD_H +#define _DL_RELOCATE_LD_H + +/* The dynamic section is readonly for ABI compatibility. */ +#define DL_RO_DYN_SECTION 1 + +#endif /* _DL_RELOCATE_LD_H */ diff --git a/sysdeps/riscv/ldsodefs.h b/sysdeps/riscv/ldsodefs.h index 0c696714a7..8947ffe4b5 100644 --- a/sysdeps/riscv/ldsodefs.h +++ b/sysdeps/riscv/ldsodefs.h @@ -38,11 +38,6 @@ struct La_riscv_retval; struct La_riscv_retval *, \ const char *); -/* Although the RISC-V ABI does not specify that the dynamic section has - to be read-only, it needs to be kept for ABI compatibility. */ - -#define DL_RO_DYN_SECTION 1 - #include_next #endif diff --git a/sysdeps/s390/dl-procinfo.c b/sysdeps/s390/dl-procinfo.c index c174e27b35..155f0bd99e 100644 --- a/sysdeps/s390/dl-procinfo.c +++ b/sysdeps/s390/dl-procinfo.c @@ -46,13 +46,13 @@ #if !defined PROCINFO_DECL && defined SHARED ._dl_s390_cap_flags #else -PROCINFO_CLASS const char _dl_s390_cap_flags[21][9] +PROCINFO_CLASS const char _dl_s390_cap_flags[23][9] #endif #ifndef PROCINFO_DECL = { "esan3", "zarch", "stfle", "msa", "ldisp", "eimm", "dfp", "edat", "etf3eh", "highgprs", "te", "vx", "vxd", "vxe", "gs", "vxe2", "vxp", "sort", "dflt", - "vxp2", "nnpa" + "vxp2", "nnpa", "pcimio", "sie" } #endif #if !defined SHARED || defined PROCINFO_DECL diff --git a/sysdeps/s390/dl-procinfo.h b/sysdeps/s390/dl-procinfo.h index 2d9c305808..e4e3e334a5 100644 --- a/sysdeps/s390/dl-procinfo.h +++ b/sysdeps/s390/dl-procinfo.h @@ -21,7 +21,7 @@ #define _DL_PROCINFO_H 1 #include -#define _DL_HWCAP_COUNT 21 +#define _DL_HWCAP_COUNT 23 #define _DL_PLATFORMS_COUNT 10 @@ -63,6 +63,8 @@ enum HWCAP_S390_DFLT = 1 << 18, HWCAP_S390_VXRS_PDE2 = 1 << 19, HWCAP_S390_NNPA = 1 << 20, + HWCAP_S390_PCI_MIO = 1 << 21, + HWCAP_S390_SIE = 1 << 22, }; #define HWCAP_IMPORTANT (HWCAP_S390_ZARCH | HWCAP_S390_LDISP \ diff --git a/sysdeps/s390/memmem-arch13.S b/sysdeps/s390/memmem-arch13.S index c5c8d8c97e..58df8cdb14 100644 --- a/sysdeps/s390/memmem-arch13.S +++ b/sysdeps/s390/memmem-arch13.S @@ -41,7 +41,7 @@ ENTRY(MEMMEM_ARCH13) # error The arch13 variant of memmem needs the z13 variant of memmem! # endif clgfi %r5,9 - jh MEMMEM_Z13 + jgh MEMMEM_Z13 aghik %r0,%r5,-1 /* vll needs highest index. */ bc 4,0(%r14) /* cc==1: return if needle-len == 0. */ diff --git a/sysdeps/s390/strstr-arch13.S b/sysdeps/s390/strstr-arch13.S index c7183e627c..222a6de91a 100644 --- a/sysdeps/s390/strstr-arch13.S +++ b/sysdeps/s390/strstr-arch13.S @@ -49,7 +49,7 @@ ENTRY(STRSTR_ARCH13) # error The arch13 variant of strstr needs the z13 variant of strstr! # endif clgfi %r4,9 - jh STRSTR_Z13 + jgh STRSTR_Z13 /* In case of a partial match, the vstrs instruction returns the index of the partial match in a vector-register. Then we have to diff --git a/sysdeps/unix/sysv/linux/aarch64/arch-syscall.h b/sysdeps/unix/sysv/linux/aarch64/arch-syscall.h index e9eb707d0a..bedab1abba 100644 --- a/sysdeps/unix/sysv/linux/aarch64/arch-syscall.h +++ b/sysdeps/unix/sysv/linux/aarch64/arch-syscall.h @@ -126,6 +126,7 @@ #define __NR_mbind 235 #define __NR_membarrier 283 #define __NR_memfd_create 279 +#define __NR_memfd_secret 447 #define __NR_migrate_pages 238 #define __NR_mincore 232 #define __NR_mkdirat 34 @@ -187,6 +188,7 @@ #define __NR_pwritev 70 #define __NR_pwritev2 287 #define __NR_quotactl 60 +#define __NR_quotactl_fd 443 #define __NR_read 63 #define __NR_readahead 213 #define __NR_readlinkat 78 diff --git a/sysdeps/unix/sysv/linux/alpha/arch-syscall.h b/sysdeps/unix/sysv/linux/alpha/arch-syscall.h index bd6b7d4003..91354ed9e2 100644 --- a/sysdeps/unix/sysv/linux/alpha/arch-syscall.h +++ b/sysdeps/unix/sysv/linux/alpha/arch-syscall.h @@ -337,6 +337,7 @@ #define __NR_pwritev2 521 #define __NR_query_module 347 #define __NR_quotactl 148 +#define __NR_quotactl_fd 553 #define __NR_read 3 #define __NR_readahead 379 #define __NR_readlink 58 diff --git a/sysdeps/unix/sysv/linux/arc/arch-syscall.h b/sysdeps/unix/sysv/linux/arc/arch-syscall.h index 10650549c1..ff5c7eb36d 100644 --- a/sysdeps/unix/sysv/linux/arc/arch-syscall.h +++ b/sysdeps/unix/sysv/linux/arc/arch-syscall.h @@ -190,6 +190,7 @@ #define __NR_pwritev 70 #define __NR_pwritev2 287 #define __NR_quotactl 60 +#define __NR_quotactl_fd 443 #define __NR_read 63 #define __NR_readahead 213 #define __NR_readlinkat 78 diff --git a/sysdeps/unix/sysv/linux/arm/arch-syscall.h b/sysdeps/unix/sysv/linux/arm/arch-syscall.h index 85c9b236ce..5772333cee 100644 --- a/sysdeps/unix/sysv/linux/arm/arch-syscall.h +++ b/sysdeps/unix/sysv/linux/arm/arch-syscall.h @@ -244,6 +244,7 @@ #define __NR_pwritev 362 #define __NR_pwritev2 393 #define __NR_quotactl 131 +#define __NR_quotactl_fd 443 #define __NR_read 3 #define __NR_readahead 225 #define __NR_readlink 85 diff --git a/sysdeps/unix/sysv/linux/bits/mman-linux.h b/sysdeps/unix/sysv/linux/bits/mman-linux.h index 3b1ae418e0..31451c28d9 100644 --- a/sysdeps/unix/sysv/linux/bits/mman-linux.h +++ b/sysdeps/unix/sysv/linux/bits/mman-linux.h @@ -89,6 +89,10 @@ # define MADV_KEEPONFORK 19 /* Undo MADV_WIPEONFORK. */ # define MADV_COLD 20 /* Deactivate these pages. */ # define MADV_PAGEOUT 21 /* Reclaim these pages. */ +# define MADV_POPULATE_READ 22 /* Populate (prefault) page tables + readable. */ +# define MADV_POPULATE_WRITE 23 /* Populate (prefault) page tables + writable. */ # define MADV_HWPOISON 100 /* Poison a page for testing. */ #endif diff --git a/sysdeps/unix/sysv/linux/bits/timex.h b/sysdeps/unix/sysv/linux/bits/timex.h index ee37694e8f..4a5db6deca 100644 --- a/sysdeps/unix/sysv/linux/bits/timex.h +++ b/sysdeps/unix/sysv/linux/bits/timex.h @@ -25,7 +25,7 @@ struct timex { -# ifdef __USE_TIME_BITS64 +# if defined __USE_TIME_BITS64 || (__TIMESIZE == 64 && __WORDSIZE == 32) unsigned int modes; /* mode selector */ int :32; /* pad */ long long offset; /* time offset (usec) */ diff --git a/sysdeps/unix/sysv/linux/csky/arch-syscall.h b/sysdeps/unix/sysv/linux/csky/arch-syscall.h index 24b0d1f94e..4af6d6202f 100644 --- a/sysdeps/unix/sysv/linux/csky/arch-syscall.h +++ b/sysdeps/unix/sysv/linux/csky/arch-syscall.h @@ -199,6 +199,7 @@ #define __NR_pwritev 70 #define __NR_pwritev2 287 #define __NR_quotactl 60 +#define __NR_quotactl_fd 443 #define __NR_read 63 #define __NR_readahead 213 #define __NR_readlinkat 78 diff --git a/sysdeps/unix/sysv/linux/getsysstats.c b/sysdeps/unix/sysv/linux/getsysstats.c index 1391e360b8..7fc6521942 100644 --- a/sysdeps/unix/sysv/linux/getsysstats.c +++ b/sysdeps/unix/sysv/linux/getsysstats.c @@ -18,6 +18,8 @@ . */ #include +#include +#include #include #include #include @@ -29,61 +31,170 @@ #include #include -/* Compute the population count of the entire array. */ -static int -__get_nprocs_count (const unsigned long int *array, size_t length) +int +__get_nprocs_sched (void) { - int count = 0; - for (size_t i = 0; i < length; ++i) - if (__builtin_add_overflow (count, __builtin_popcountl (array[i]), - &count)) - return INT_MAX; - return count; + enum + { + max_num_cpus = 32768, + cpu_bits_size = CPU_ALLOC_SIZE (32768) + }; + + /* This cannot use malloc because it is used on malloc initialization. */ + __cpu_mask cpu_bits[cpu_bits_size / sizeof (__cpu_mask)]; + int r = INTERNAL_SYSCALL_CALL (sched_getaffinity, 0, cpu_bits_size, + cpu_bits); + if (r > 0) + return CPU_COUNT_S (cpu_bits_size, (cpu_set_t*) cpu_bits); + else if (r == -EINVAL) + /* The input buffer is still not enough to store the number of cpus. This + is an arbitrary values assuming such systems should be rare and there + is no offline cpus. */ + return max_num_cpus; + /* Some other error. 2 is conservative (not a uniprocessor system, so + atomics are needed). */ + return 2; +} + +static char * +next_line (int fd, char *const buffer, char **cp, char **re, + char *const buffer_end) +{ + char *res = *cp; + char *nl = memchr (*cp, '\n', *re - *cp); + if (nl == NULL) + { + if (*cp != buffer) + { + if (*re == buffer_end) + { + memmove (buffer, *cp, *re - *cp); + *re = buffer + (*re - *cp); + *cp = buffer; + + ssize_t n = __read_nocancel (fd, *re, buffer_end - *re); + if (n < 0) + return NULL; + + *re += n; + + nl = memchr (*cp, '\n', *re - *cp); + while (nl == NULL && *re == buffer_end) + { + /* Truncate too long lines. */ + *re = buffer + 3 * (buffer_end - buffer) / 4; + n = __read_nocancel (fd, *re, buffer_end - *re); + if (n < 0) + return NULL; + + nl = memchr (*re, '\n', n); + **re = '\n'; + *re += n; + } + } + else + nl = memchr (*cp, '\n', *re - *cp); + + res = *cp; + } + + if (nl == NULL) + nl = *re - 1; + } + + *cp = nl + 1; + assert (*cp <= *re); + + return res == *re ? NULL : res; } -/* __get_nprocs with a large buffer. */ static int -__get_nprocs_large (void) +get_nproc_stat (char *buffer, size_t buffer_size) { - /* This code cannot use scratch_buffer because it is used during - malloc initialization. */ - size_t pagesize = GLRO (dl_pagesize); - unsigned long int *page = __mmap (0, pagesize, PROT_READ | PROT_WRITE, - MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); - if (page == MAP_FAILED) - return 2; - int r = INTERNAL_SYSCALL_CALL (sched_getaffinity, 0, pagesize, page); - int count; - if (r > 0) - count = __get_nprocs_count (page, pagesize / sizeof (unsigned long int)); - else if (r == -EINVAL) - /* One page is still not enough to store the bits. A more-or-less - arbitrary value. This assumes t hat such large systems never - happen in practice. */ - count = GLRO (dl_pagesize) * CHAR_BIT; - else - count = 2; - __munmap (page, GLRO (dl_pagesize)); - return count; + char *buffer_end = buffer + buffer_size; + char *cp = buffer_end; + char *re = buffer_end; + + /* Default to an SMP system in case we cannot obtain an accurate + number. */ + int result = 2; + + const int flags = O_RDONLY | O_CLOEXEC; + int fd = __open_nocancel ("/proc/stat", flags); + if (fd != -1) + { + result = 0; + + char *l; + while ((l = next_line (fd, buffer, &cp, &re, buffer_end)) != NULL) + /* The current format of /proc/stat has all the cpu* entries + at the front. We assume here that stays this way. */ + if (strncmp (l, "cpu", 3) != 0) + break; + else if (isdigit (l[3])) + ++result; + + __close_nocancel_nostatus (fd); + } + + return result; } int __get_nprocs (void) { - /* Fast path for most systems. The kernel expects a buffer size - that is a multiple of 8. */ - unsigned long int small_buffer[1024 / CHAR_BIT / sizeof (unsigned long int)]; - int r = INTERNAL_SYSCALL_CALL (sched_getaffinity, 0, - sizeof (small_buffer), small_buffer); - if (r > 0) - return __get_nprocs_count (small_buffer, r / sizeof (unsigned long int)); - else if (r == -EINVAL) - /* The kernel requests a larger buffer to store the data. */ - return __get_nprocs_large (); - else - /* Some other error. 2 is conservative (not a uniprocessor - system, so atomics are needed). */ - return 2; + enum { buffer_size = 1024 }; + char buffer[buffer_size]; + char *buffer_end = buffer + buffer_size; + char *cp = buffer_end; + char *re = buffer_end; + + const int flags = O_RDONLY | O_CLOEXEC; + /* This file contains comma-separated ranges. */ + int fd = __open_nocancel ("/sys/devices/system/cpu/online", flags); + char *l; + int result = 0; + if (fd != -1) + { + l = next_line (fd, buffer, &cp, &re, buffer_end); + if (l != NULL) + do + { + char *endp; + unsigned long int n = strtoul (l, &endp, 10); + if (l == endp) + { + result = 0; + break; + } + + unsigned long int m = n; + if (*endp == '-') + { + l = endp + 1; + m = strtoul (l, &endp, 10); + if (l == endp) + { + result = 0; + break; + } + } + + result += m - n + 1; + + l = endp; + if (l < re && *l == ',') + ++l; + } + while (l < re && *l != '\n'); + + __close_nocancel_nostatus (fd); + + if (result > 0) + return result; + } + + return get_nproc_stat (buffer, buffer_size); } libc_hidden_def (__get_nprocs) weak_alias (__get_nprocs, get_nprocs) @@ -117,7 +228,9 @@ __get_nprocs_conf (void) return count; } - return 1; + enum { buffer_size = 1024 }; + char buffer[buffer_size]; + return get_nproc_stat (buffer, buffer_size); } libc_hidden_def (__get_nprocs_conf) weak_alias (__get_nprocs_conf, get_nprocs_conf) diff --git a/sysdeps/unix/sysv/linux/hppa/arch-syscall.h b/sysdeps/unix/sysv/linux/hppa/arch-syscall.h index feb70abc3e..b07fc8549d 100644 --- a/sysdeps/unix/sysv/linux/hppa/arch-syscall.h +++ b/sysdeps/unix/sysv/linux/hppa/arch-syscall.h @@ -231,6 +231,7 @@ #define __NR_pwritev 316 #define __NR_pwritev2 348 #define __NR_quotactl 131 +#define __NR_quotactl_fd 443 #define __NR_read 3 #define __NR_readahead 207 #define __NR_readlink 85 diff --git a/sysdeps/unix/sysv/linux/i386/arch-syscall.h b/sysdeps/unix/sysv/linux/i386/arch-syscall.h index 3b1894a79b..6e4264698b 100644 --- a/sysdeps/unix/sysv/linux/i386/arch-syscall.h +++ b/sysdeps/unix/sysv/linux/i386/arch-syscall.h @@ -183,6 +183,7 @@ #define __NR_mbind 274 #define __NR_membarrier 375 #define __NR_memfd_create 356 +#define __NR_memfd_secret 447 #define __NR_migrate_pages 294 #define __NR_mincore 218 #define __NR_mkdir 39 @@ -266,6 +267,7 @@ #define __NR_pwritev2 379 #define __NR_query_module 167 #define __NR_quotactl 131 +#define __NR_quotactl_fd 443 #define __NR_read 3 #define __NR_readahead 225 #define __NR_readdir 89 diff --git a/sysdeps/unix/sysv/linux/ia64/arch-syscall.h b/sysdeps/unix/sysv/linux/ia64/arch-syscall.h index fb388a5fa4..1ca706d721 100644 --- a/sysdeps/unix/sysv/linux/ia64/arch-syscall.h +++ b/sysdeps/unix/sysv/linux/ia64/arch-syscall.h @@ -218,6 +218,7 @@ #define __NR_pwritev 1320 #define __NR_pwritev2 1349 #define __NR_quotactl 1137 +#define __NR_quotactl_fd 1467 #define __NR_read 1026 #define __NR_readahead 1216 #define __NR_readlink 1092 diff --git a/sysdeps/unix/sysv/linux/m68k/arch-syscall.h b/sysdeps/unix/sysv/linux/m68k/arch-syscall.h index 7bc8c4af92..2f10f71f90 100644 --- a/sysdeps/unix/sysv/linux/m68k/arch-syscall.h +++ b/sysdeps/unix/sysv/linux/m68k/arch-syscall.h @@ -254,6 +254,7 @@ #define __NR_pwritev2 378 #define __NR_query_module 167 #define __NR_quotactl 131 +#define __NR_quotactl_fd 443 #define __NR_read 3 #define __NR_readahead 240 #define __NR_readdir 89 diff --git a/sysdeps/unix/sysv/linux/microblaze/arch-syscall.h b/sysdeps/unix/sysv/linux/microblaze/arch-syscall.h index cf560d3af4..0607a4dfa6 100644 --- a/sysdeps/unix/sysv/linux/microblaze/arch-syscall.h +++ b/sysdeps/unix/sysv/linux/microblaze/arch-syscall.h @@ -266,6 +266,7 @@ #define __NR_pwritev2 394 #define __NR_query_module 167 #define __NR_quotactl 131 +#define __NR_quotactl_fd 443 #define __NR_read 3 #define __NR_readahead 225 #define __NR_readdir 89 diff --git a/sysdeps/unix/sysv/linux/mips/fxstat.c b/sysdeps/unix/sysv/linux/mips/fxstat.c index 11511d30b3..4a6016ff12 100644 --- a/sysdeps/unix/sysv/linux/mips/fxstat.c +++ b/sysdeps/unix/sysv/linux/mips/fxstat.c @@ -35,7 +35,9 @@ __fxstat (int vers, int fd, struct stat *buf) { struct kernel_stat kbuf; int r = INTERNAL_SYSCALL_CALL (fstat, fd, &kbuf); - return r ?: __xstat_conv (vers, &kbuf, buf); + if (r == 0) + return __xstat_conv (vers, &kbuf, buf); + return INLINE_SYSCALL_ERROR_RETURN_VALUE (-r); } } } diff --git a/sysdeps/unix/sysv/linux/mips/lxstat.c b/sysdeps/unix/sysv/linux/mips/lxstat.c index 871fb6c6c5..54f990a250 100644 --- a/sysdeps/unix/sysv/linux/mips/lxstat.c +++ b/sysdeps/unix/sysv/linux/mips/lxstat.c @@ -35,7 +35,9 @@ __lxstat (int vers, const char *name, struct stat *buf) { struct kernel_stat kbuf; int r = INTERNAL_SYSCALL_CALL (lstat, name, &kbuf); - return r ?: __xstat_conv (vers, &kbuf, buf); + if (r == 0) + return __xstat_conv (vers, &kbuf, buf); + return INLINE_SYSCALL_ERROR_RETURN_VALUE (-r); } } } diff --git a/sysdeps/unix/sysv/linux/mips/mips32/arch-syscall.h b/sysdeps/unix/sysv/linux/mips/mips32/arch-syscall.h index f346460f48..0055eec0b1 100644 --- a/sysdeps/unix/sysv/linux/mips/mips32/arch-syscall.h +++ b/sysdeps/unix/sysv/linux/mips/mips32/arch-syscall.h @@ -251,6 +251,7 @@ #define __NR_pwritev2 4362 #define __NR_query_module 4187 #define __NR_quotactl 4131 +#define __NR_quotactl_fd 4443 #define __NR_read 4003 #define __NR_readahead 4223 #define __NR_readdir 4089 diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/arch-syscall.h b/sysdeps/unix/sysv/linux/mips/mips64/n32/arch-syscall.h index 38ed84997a..8e8e9f91cc 100644 --- a/sysdeps/unix/sysv/linux/mips/mips64/n32/arch-syscall.h +++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/arch-syscall.h @@ -232,6 +232,7 @@ #define __NR_pwritev2 6326 #define __NR_query_module 6171 #define __NR_quotactl 6172 +#define __NR_quotactl_fd 6443 #define __NR_read 6000 #define __NR_readahead 6179 #define __NR_readlink 6087 diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/arch-syscall.h b/sysdeps/unix/sysv/linux/mips/mips64/n64/arch-syscall.h index e6a10c8421..ebd1545f80 100644 --- a/sysdeps/unix/sysv/linux/mips/mips64/n64/arch-syscall.h +++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/arch-syscall.h @@ -219,6 +219,7 @@ #define __NR_pwritev2 5322 #define __NR_query_module 5171 #define __NR_quotactl 5172 +#define __NR_quotactl_fd 5443 #define __NR_read 5000 #define __NR_readahead 5179 #define __NR_readlink 5087 diff --git a/sysdeps/unix/sysv/linux/mips/xstat.c b/sysdeps/unix/sysv/linux/mips/xstat.c index 9d810b6f65..86f4dc31a8 100644 --- a/sysdeps/unix/sysv/linux/mips/xstat.c +++ b/sysdeps/unix/sysv/linux/mips/xstat.c @@ -35,7 +35,9 @@ __xstat (int vers, const char *name, struct stat *buf) { struct kernel_stat kbuf; int r = INTERNAL_SYSCALL_CALL (stat, name, &kbuf); - return r ?: __xstat_conv (vers, &kbuf, buf); + if (r == 0) + return __xstat_conv (vers, &kbuf, buf); + return INLINE_SYSCALL_ERROR_RETURN_VALUE (-r); } } } diff --git a/sysdeps/unix/sysv/linux/mq_notify.c b/sysdeps/unix/sysv/linux/mq_notify.c index 9799dcdaa4..eccae2e4c6 100644 --- a/sysdeps/unix/sysv/linux/mq_notify.c +++ b/sysdeps/unix/sysv/linux/mq_notify.c @@ -131,7 +131,7 @@ helper_thread (void *arg) to wait until it is done with it. */ (void) __pthread_barrier_wait (¬ify_barrier); } - else if (data.raw[NOTIFY_COOKIE_LEN - 1] == NOTIFY_REMOVED) + else if (data.raw[NOTIFY_COOKIE_LEN - 1] == NOTIFY_REMOVED && data.attr != NULL) { /* The only state we keep is the copy of the thread attributes. */ __pthread_attr_destroy (data.attr); diff --git a/sysdeps/unix/sysv/linux/nios2/arch-syscall.h b/sysdeps/unix/sysv/linux/nios2/arch-syscall.h index 5314890289..2b530b1f88 100644 --- a/sysdeps/unix/sysv/linux/nios2/arch-syscall.h +++ b/sysdeps/unix/sysv/linux/nios2/arch-syscall.h @@ -198,6 +198,7 @@ #define __NR_pwritev 70 #define __NR_pwritev2 287 #define __NR_quotactl 60 +#define __NR_quotactl_fd 443 #define __NR_read 63 #define __NR_readahead 213 #define __NR_readlinkat 78 diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/arch-syscall.h b/sysdeps/unix/sysv/linux/powerpc/powerpc32/arch-syscall.h index b5b0758532..a32984a9c1 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/arch-syscall.h +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/arch-syscall.h @@ -260,6 +260,7 @@ #define __NR_pwritev2 381 #define __NR_query_module 166 #define __NR_quotactl 131 +#define __NR_quotactl_fd 443 #define __NR_read 3 #define __NR_readahead 191 #define __NR_readdir 89 diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-syscall.h b/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-syscall.h index c77435ca61..b01e464fb9 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-syscall.h +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-syscall.h @@ -243,6 +243,7 @@ #define __NR_pwritev2 381 #define __NR_query_module 166 #define __NR_quotactl 131 +#define __NR_quotactl_fd 443 #define __NR_read 3 #define __NR_readahead 191 #define __NR_readdir 89 diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h b/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h index 70854bb9e3..24d0a2c455 100644 --- a/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h +++ b/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h @@ -179,6 +179,7 @@ #define __NR_pwritev 70 #define __NR_pwritev2 287 #define __NR_quotactl 60 +#define __NR_quotactl_fd 443 #define __NR_read 63 #define __NR_readahead 213 #define __NR_readlinkat 78 diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h b/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h index 83b9f31aba..e526c89ae7 100644 --- a/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h +++ b/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h @@ -187,6 +187,7 @@ #define __NR_pwritev 70 #define __NR_pwritev2 287 #define __NR_quotactl 60 +#define __NR_quotactl_fd 443 #define __NR_read 63 #define __NR_readahead 213 #define __NR_readlinkat 78 diff --git a/sysdeps/unix/sysv/linux/s390/bits/hwcap.h b/sysdeps/unix/sysv/linux/s390/bits/hwcap.h index e9bd3684db..00e73a3e3b 100644 --- a/sysdeps/unix/sysv/linux/s390/bits/hwcap.h +++ b/sysdeps/unix/sysv/linux/s390/bits/hwcap.h @@ -22,6 +22,11 @@ /* * The following must match the kernels asm/elf.h. + * Note: The kernel commit 511ad531afd4090625def4d9aba1f5227bd44b8e + * "s390/hwcaps: shorten HWCAP defines" has shortened the prefix of the macros + * from "HWCAP_S390_" to "HWCAP_". For compatibility reasons, we do not + * change the prefix in public glibc header file. + * * Note that these are *not* the same as the STORE FACILITY LIST bits. */ #define HWCAP_S390_ESAN3 1 @@ -48,3 +53,5 @@ #define HWCAP_S390_DFLT 262144 #define HWCAP_S390_VXRS_PDE2 524288 #define HWCAP_S390_NNPA 1048576 +#define HWCAP_S390_PCI_MIO 2097152 +#define HWCAP_S390_SIE 4194304 diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/arch-syscall.h b/sysdeps/unix/sysv/linux/s390/s390-32/arch-syscall.h index b224c4aad4..d4c7b101b6 100644 --- a/sysdeps/unix/sysv/linux/s390/s390-32/arch-syscall.h +++ b/sysdeps/unix/sysv/linux/s390/s390-32/arch-syscall.h @@ -251,6 +251,7 @@ #define __NR_pwritev2 377 #define __NR_query_module 167 #define __NR_quotactl 131 +#define __NR_quotactl_fd 443 #define __NR_read 3 #define __NR_readahead 222 #define __NR_readdir 89 diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/arch-syscall.h b/sysdeps/unix/sysv/linux/s390/s390-64/arch-syscall.h index 59864af125..bd8c78d705 100644 --- a/sysdeps/unix/sysv/linux/s390/s390-64/arch-syscall.h +++ b/sysdeps/unix/sysv/linux/s390/s390-64/arch-syscall.h @@ -221,6 +221,7 @@ #define __NR_pwritev2 377 #define __NR_query_module 167 #define __NR_quotactl 131 +#define __NR_quotactl_fd 443 #define __NR_read 3 #define __NR_readahead 222 #define __NR_readdir 89 diff --git a/sysdeps/unix/sysv/linux/sh/arch-syscall.h b/sysdeps/unix/sysv/linux/sh/arch-syscall.h index 23612c9092..3b6ac3d084 100644 --- a/sysdeps/unix/sysv/linux/sh/arch-syscall.h +++ b/sysdeps/unix/sysv/linux/sh/arch-syscall.h @@ -246,6 +246,7 @@ #define __NR_pwritev 334 #define __NR_pwritev2 382 #define __NR_quotactl 131 +#define __NR_quotactl_fd 443 #define __NR_read 3 #define __NR_readahead 225 #define __NR_readdir 89 diff --git a/sysdeps/unix/sysv/linux/sparc/bits/struct_stat.h b/sysdeps/unix/sysv/linux/sparc/bits/struct_stat.h index b481b4f9f8..45db6b6ffb 100644 --- a/sysdeps/unix/sysv/linux/sparc/bits/struct_stat.h +++ b/sysdeps/unix/sysv/linux/sparc/bits/struct_stat.h @@ -28,32 +28,35 @@ struct stat { +#ifdef __USE_TIME_BITS64 +# include +#else __dev_t st_dev; /* Device. */ -#if __WORDSIZE == 64 || !defined __USE_FILE_OFFSET64 +# if __WORDSIZE == 64 || !defined __USE_FILE_OFFSET64 unsigned short int __pad1; __ino_t st_ino; /* File serial number. */ -#else +# else __ino64_t st_ino; /* File serial number. */ -#endif +# endif __mode_t st_mode; /* File mode. */ __nlink_t st_nlink; /* Link count. */ __uid_t st_uid; /* User ID of the file's owner. */ __gid_t st_gid; /* Group ID of the file's group.*/ __dev_t st_rdev; /* Device number, if device. */ unsigned short int __pad2; -#ifndef __USE_FILE_OFFSET64 +# ifndef __USE_FILE_OFFSET64 __off_t st_size; /* Size of file, in bytes. */ -#else +# else __off64_t st_size; /* Size of file, in bytes. */ -#endif +# endif __blksize_t st_blksize; /* Optimal block size for I/O. */ -#ifndef __USE_FILE_OFFSET64 +# ifndef __USE_FILE_OFFSET64 __blkcnt_t st_blocks; /* Number 512-byte blocks allocated. */ -#else +# else __blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */ -#endif -#ifdef __USE_XOPEN2K8 +# endif +# ifdef __USE_XOPEN2K8 /* Nanosecond resolution timestamps are stored in a format equivalent to 'struct timespec'. This is the type used whenever possible but the Unix namespace rules do not allow the @@ -63,28 +66,32 @@ struct stat struct timespec st_atim; /* Time of last access. */ struct timespec st_mtim; /* Time of last modification. */ struct timespec st_ctim; /* Time of last status change. */ -# define st_atime st_atim.tv_sec /* Backward compatibility. */ -# define st_mtime st_mtim.tv_sec -# define st_ctime st_ctim.tv_sec -#else +# define st_atime st_atim.tv_sec /* Backward compatibility. */ +# define st_mtime st_mtim.tv_sec +# define st_ctime st_ctim.tv_sec +# else __time_t st_atime; /* Time of last access. */ unsigned long int st_atimensec; /* Nscecs of last access. */ __time_t st_mtime; /* Time of last modification. */ unsigned long int st_mtimensec; /* Nsecs of last modification. */ __time_t st_ctime; /* Time of last status change. */ unsigned long int st_ctimensec; /* Nsecs of last status change. */ -#endif +# endif unsigned long int __glibc_reserved4; unsigned long int __glibc_reserved5; +#endif /* __USE_TIME_BITS64 */ }; #ifdef __USE_LARGEFILE64 struct stat64 { +# ifdef __USE_TIME_BITS64 +# include +# else __dev_t st_dev; /* Device. */ -# if __WORDSIZE == 64 +# if __WORDSIZE == 64 unsigned short int __pad1; -# endif +# endif __ino64_t st_ino; /* File serial number. */ __mode_t st_mode; /* File mode. */ __nlink_t st_nlink; /* Link count. */ @@ -96,7 +103,7 @@ struct stat64 __blksize_t st_blksize; /* Optimal block size for I/O. */ __blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */ -# ifdef __USE_XOPEN2K8 +# ifdef __USE_XOPEN2K8 /* Nanosecond resolution timestamps are stored in a format equivalent to 'struct timespec'. This is the type used whenever possible but the Unix namespace rules do not allow the @@ -106,19 +113,20 @@ struct stat64 struct timespec st_atim; /* Time of last access. */ struct timespec st_mtim; /* Time of last modification. */ struct timespec st_ctim; /* Time of last status change. */ -# define st_atime st_atim.tv_sec /* Backward compatibility. */ -# define st_mtime st_mtim.tv_sec -# define st_ctime st_ctim.tv_sec -# else +# define st_atime st_atim.tv_sec /* Backward compatibility. */ +# define st_mtime st_mtim.tv_sec +# define st_ctime st_ctim.tv_sec +# else __time_t st_atime; /* Time of last access. */ unsigned long int st_atimensec; /* Nscecs of last access. */ __time_t st_mtime; /* Time of last modification. */ unsigned long int st_mtimensec; /* Nsecs of last modification. */ __time_t st_ctime; /* Time of last status change. */ unsigned long int st_ctimensec; /* Nsecs of last status change. */ -# endif +# endif unsigned long int __glibc_reserved4; unsigned long int __glibc_reserved5; +# endif /* __USE_TIME_BITS64 */ }; #endif diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/arch-syscall.h b/sysdeps/unix/sysv/linux/sparc/sparc32/arch-syscall.h index 380cddb2d8..35221a707e 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc32/arch-syscall.h +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/arch-syscall.h @@ -252,6 +252,7 @@ #define __NR_pwritev2 359 #define __NR_query_module 184 #define __NR_quotactl 165 +#define __NR_quotactl_fd 443 #define __NR_read 3 #define __NR_readahead 205 #define __NR_readdir 204 diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/arch-syscall.h b/sysdeps/unix/sysv/linux/sparc/sparc64/arch-syscall.h index 2175eeb6ed..5ba2b20509 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc64/arch-syscall.h +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/arch-syscall.h @@ -231,6 +231,7 @@ #define __NR_pwritev2 359 #define __NR_query_module 184 #define __NR_quotactl 165 +#define __NR_quotactl_fd 443 #define __NR_read 3 #define __NR_readahead 205 #define __NR_readdir 204 diff --git a/sysdeps/unix/sysv/linux/sys/prctl.h b/sysdeps/unix/sysv/linux/sys/prctl.h index db88938b3a..f0e0d2f27f 100644 --- a/sysdeps/unix/sysv/linux/sys/prctl.h +++ b/sysdeps/unix/sysv/linux/sys/prctl.h @@ -42,7 +42,7 @@ __BEGIN_DECLS extern int prctl (int __option, ...) __THROW; #else # ifdef __REDIRECT -extern int __REDIRECT (prctl, (int __option, ...), __prctl_time64) __THROW; +extern int __REDIRECT_NTH (prctl, (int __option, ...), __prctl_time64); # else extern int __prctl_time64 (int __option,d ...) __THROW; # define ioctl __prctl_time64 diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list index 89c5895b9b..fd98893b0e 100644 --- a/sysdeps/unix/sysv/linux/syscall-names.list +++ b/sysdeps/unix/sysv/linux/syscall-names.list @@ -21,8 +21,8 @@ # This file can list all potential system calls. The names are only # used if the installed kernel headers also provide them. -# The list of system calls is current as of Linux 5.13. -kernel 5.13 +# The list of system calls is current as of Linux 5.14. +kernel 5.14 FAST_atomic_update FAST_cmpxchg @@ -247,6 +247,7 @@ madvise mbind membarrier memfd_create +memfd_secret memory_ordering migrate_pages mincore @@ -452,6 +453,7 @@ pwritev pwritev2 query_module quotactl +quotactl_fd read readahead readdir diff --git a/sysdeps/unix/sysv/linux/tst-close_range.c b/sysdeps/unix/sysv/linux/tst-close_range.c index dccb6189c5..f5069d1b8a 100644 --- a/sysdeps/unix/sysv/linux/tst-close_range.c +++ b/sysdeps/unix/sysv/linux/tst-close_range.c @@ -36,23 +36,12 @@ #define NFDS 100 -static int -open_multiple_temp_files (void) -{ - /* Check if the temporary file descriptor has no no gaps. */ - int lowfd = xopen ("/dev/null", O_RDONLY, 0600); - for (int i = 1; i <= NFDS; i++) - TEST_COMPARE (xopen ("/dev/null", O_RDONLY, 0600), - lowfd + i); - return lowfd; -} - static void close_range_test_max_upper_limit (void) { struct support_descriptors *descrs = support_descriptors_list (); - int lowfd = open_multiple_temp_files (); + int lowfd = support_open_dev_null_range (NFDS, O_RDONLY, 0600); { int r = close_range (lowfd, ~0U, 0); @@ -68,7 +57,7 @@ close_range_test_max_upper_limit (void) static void close_range_test_common (int lowfd, unsigned int flags) { - const int maximum_fd = lowfd + NFDS; + const int maximum_fd = lowfd + NFDS - 1; const int half_fd = lowfd + NFDS / 2; const int gap_1 = maximum_fd - 8; @@ -121,7 +110,7 @@ close_range_test (void) struct support_descriptors *descrs = support_descriptors_list (); /* Check if the temporary file descriptor has no no gaps. */ - int lowfd = open_multiple_temp_files (); + int lowfd = support_open_dev_null_range (NFDS, O_RDONLY, 0600); close_range_test_common (lowfd, 0); @@ -146,7 +135,7 @@ close_range_test_subprocess (void) struct support_descriptors *descrs = support_descriptors_list (); /* Check if the temporary file descriptor has no no gaps. */ - int lowfd = open_multiple_temp_files (); + int lowfd = support_open_dev_null_range (NFDS, O_RDONLY, 0600); struct support_stack stack = support_stack_alloc (4096); @@ -184,7 +173,7 @@ close_range_unshare_test (void) struct support_descriptors *descrs1 = support_descriptors_list (); /* Check if the temporary file descriptor has no no gaps. */ - int lowfd = open_multiple_temp_files (); + int lowfd = support_open_dev_null_range (NFDS, O_RDONLY, 0600); struct support_descriptors *descrs2 = support_descriptors_list (); @@ -200,7 +189,7 @@ close_range_unshare_test (void) support_stack_free (&stack); - for (int i = 0; i < NFDS; i++) + for (int i = lowfd; i < lowfd + NFDS; i++) TEST_VERIFY (fcntl (i, F_GETFL) > -1); support_descriptors_check (descrs2); @@ -226,9 +215,9 @@ static void close_range_cloexec_test (void) { /* Check if the temporary file descriptor has no no gaps. */ - const int lowfd = open_multiple_temp_files (); + int lowfd = support_open_dev_null_range (NFDS, O_RDONLY, 0600); - const int maximum_fd = lowfd + NFDS; + const int maximum_fd = lowfd + NFDS - 1; const int half_fd = lowfd + NFDS / 2; const int gap_1 = maximum_fd - 8; @@ -251,13 +240,13 @@ close_range_cloexec_test (void) /* Create some gaps, close up to a threshold, and check result. */ static int gap_close[] = { 57, 78, 81, 82, 84, 90 }; for (int i = 0; i < array_length (gap_close); i++) - xclose (gap_close[i]); + xclose (lowfd + gap_close[i]); TEST_COMPARE (close_range (half_fd + 1, gap_1, CLOSE_RANGE_CLOEXEC), 0); for (int i = half_fd + 1; i < gap_1; i++) { int flags = fcntl (i, F_GETFD); - if (is_in_array (gap_close, array_length (gap_close), i)) + if (is_in_array (gap_close, array_length (gap_close), i - lowfd)) TEST_COMPARE (flags, -1); else { diff --git a/sysdeps/unix/sysv/linux/tst-mman-consts.py b/sysdeps/unix/sysv/linux/tst-mman-consts.py index ee5b13ee12..810433c238 100644 --- a/sysdeps/unix/sysv/linux/tst-mman-consts.py +++ b/sysdeps/unix/sysv/linux/tst-mman-consts.py @@ -33,7 +33,7 @@ def main(): help='C compiler (including options) to use') args = parser.parse_args() linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc) - linux_version_glibc = (5, 13) + linux_version_glibc = (5, 14) sys.exit(glibcextract.compare_macro_consts( '#define _GNU_SOURCE 1\n' '#include \n', diff --git a/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h b/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h index 8e028eb62b..26d6ac68a6 100644 --- a/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h +++ b/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h @@ -154,6 +154,7 @@ #define __NR_mbind 237 #define __NR_membarrier 324 #define __NR_memfd_create 319 +#define __NR_memfd_secret 447 #define __NR_migrate_pages 256 #define __NR_mincore 27 #define __NR_mkdir 83 @@ -224,6 +225,7 @@ #define __NR_pwritev2 328 #define __NR_query_module 178 #define __NR_quotactl 179 +#define __NR_quotactl_fd 443 #define __NR_read 0 #define __NR_readahead 187 #define __NR_readlink 89 diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h b/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h index 004feb53f1..36847783f6 100644 --- a/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h +++ b/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h @@ -148,6 +148,7 @@ #define __NR_mbind 1073742061 #define __NR_membarrier 1073742148 #define __NR_memfd_create 1073742143 +#define __NR_memfd_secret 1073742271 #define __NR_migrate_pages 1073742080 #define __NR_mincore 1073741851 #define __NR_mkdir 1073741907 @@ -216,6 +217,7 @@ #define __NR_pwritev 1073742359 #define __NR_pwritev2 1073742371 #define __NR_quotactl 1073742003 +#define __NR_quotactl_fd 1073742267 #define __NR_read 1073741824 #define __NR_readahead 1073742011 #define __NR_readlink 1073741913 diff --git a/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S b/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S index 9f02624375..abde8438d4 100644 --- a/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S +++ b/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S @@ -325,7 +325,7 @@ L(movsb): /* Avoid slow backward REP MOVSB. */ jb L(more_8x_vec_backward) # if AVOID_SHORT_DISTANCE_REP_MOVSB - andl $X86_STRING_CONTROL_AVOID_SHORT_DISTANCE_REP_MOVSB, __x86_string_control(%rip) + testl $X86_STRING_CONTROL_AVOID_SHORT_DISTANCE_REP_MOVSB, __x86_string_control(%rip) jz 3f movq %rdi, %rcx subq %rsi, %rcx @@ -333,7 +333,7 @@ L(movsb): # endif 1: # if AVOID_SHORT_DISTANCE_REP_MOVSB - andl $X86_STRING_CONTROL_AVOID_SHORT_DISTANCE_REP_MOVSB, __x86_string_control(%rip) + testl $X86_STRING_CONTROL_AVOID_SHORT_DISTANCE_REP_MOVSB, __x86_string_control(%rip) jz 3f movq %rsi, %rcx subq %rdi, %rcx diff -pruN glibc-2.32.orig/sysdeps/unix/sysv/linux/x86_64/64/configure glibc-2.32/sysdeps/unix/sysv/linux/x86_64/64/configure --- glibc-2.32.orig/sysdeps/unix/sysv/linux/x86_64/64/configure 2021-09-18 21:02:32.741186019 +1000 +++ glibc-2.32/sysdeps/unix/sysv/linux/x86_64/64/configure 2021-09-18 21:03:05.314302356 +1000 @@ -4,10 +4,10 @@ test -n "$libc_cv_slibdir" || case "$prefix" in /usr | /usr/) - libc_cv_slibdir='/lib64' - libc_cv_rtlddir='/lib64' + libc_cv_slibdir='/lib' + libc_cv_rtlddir='/lib' if test "$libdir" = '${exec_prefix}/lib'; then - libdir='${exec_prefix}/lib64'; + libdir='${exec_prefix}/lib'; # Locale data can be shared between 32-bit and 64-bit libraries. libc_cv_complocaledir='${exec_prefix}/lib/locale' fi diff -pruN glibc-2.32.orig/sysdeps/unix/sysv/linux/x86_64/ldconfig.h glibc-2.32/sysdeps/unix/sysv/linux/x86_64/ldconfig.h --- glibc-2.32.orig/sysdeps/unix/sysv/linux/x86_64/ldconfig.h 2021-09-18 21:02:32.742186053 +1000 +++ glibc-2.32/sysdeps/unix/sysv/linux/x86_64/ldconfig.h 2021-09-18 21:03:05.314302356 +1000 @@ -18,9 +18,9 @@ #include #define SYSDEP_KNOWN_INTERPRETER_NAMES \ - { "/lib/ld-linux.so.2", FLAG_ELF_LIBC6 }, \ + { "/lib32/ld-linux.so.2", FLAG_ELF_LIBC6 }, \ { "/libx32/ld-linux-x32.so.2", FLAG_ELF_LIBC6 }, \ - { "/lib64/ld-linux-x86-64.so.2", FLAG_ELF_LIBC6 }, + { "/lib/ld-linux-x86-64.so.2", FLAG_ELF_LIBC6 }, #define SYSDEP_KNOWN_LIBRARY_NAMES \ { "libc.so.6", FLAG_ELF_LIBC6 }, \ { "libm.so.6", FLAG_ELF_LIBC6 },