git-updates
authorGNU Libc Maintainers <debian-glibc@lists.debian.org>
Wed, 26 Jan 2022 22:01:02 +0000 (22:01 +0000)
committerAurelien Jarno <aurel32@debian.org>
Wed, 26 Jan 2022 22:01:02 +0000 (22:01 +0000)
GIT update of https://sourceware.org/git/glibc.git/release/2.33/master from glibc-2.33

GIT update of https://sourceware.org/git/glibc.git/release/2.33/master from glibc-2.33

Gbp-Pq: Name git-updates.diff

148 files changed:
NEWS
config.h.in
dlfcn/dlerror.c
elf/Makefile
elf/Versions
elf/dl-cache.c
elf/dl-diagnostics-cpu.c [new file with mode: 0644]
elf/dl-diagnostics-kernel.c [new file with mode: 0644]
elf/dl-diagnostics.c [new file with mode: 0644]
elf/dl-diagnostics.h [new file with mode: 0644]
elf/dl-error-skeleton.c
elf/dl-libc.c
elf/dl-load.c
elf/dl-main.h
elf/dl-open.c
elf/dl-tunable-types.h
elf/dl-tunables.c
elf/dl-tunables.h
elf/dl-tunables.list
elf/dl-usage.c
elf/rtld.c
elf/tst-dlmopen-dlerror-mod.c [new file with mode: 0644]
elf/tst-dlmopen-dlerror.c [new file with mode: 0644]
elf/tst-dlmopen-gethostbyname-mod.c [new file with mode: 0644]
elf/tst-dlmopen-gethostbyname.c [new file with mode: 0644]
elf/tst-dst-static.c [new file with mode: 0644]
elf/tst-env-setuid-tunables.c
elf/tst-env-setuid.c
elf/tst-rtld-list-tunables.exp
iconvdata/Makefile
iconvdata/bug-iconv15.c [new file with mode: 0644]
iconvdata/iso-2022-jp-3.c
include/libc-symbols.h
include/sys/un.h
include/time.h
io/Makefile
io/fstat.c
io/fstat64.c
io/tst-stat-lfs.c [new file with mode: 0644]
io/tst-stat.c [new file with mode: 0644]
malloc/malloc.c
misc/Makefile
misc/tst-select.c [new file with mode: 0644]
nptl/Makefile
nptl/pthreadP.h
nptl/pthread_create.c
nptl/pthread_once.c
nptl/tst-once5.cc
nptl/tst-pthread-gdb-attach-static.c [new file with mode: 0644]
nptl/tst-pthread-gdb-attach.c [new file with mode: 0644]
nptl_db/structs.def
nptl_db/td_init.c
nptl_db/thread_dbP.h
nscd/netgroupcache.c
nss/nss_database.c
nss/tst-nss-files-hosts-long.root/etc/nsswitch.conf [new file with mode: 0644]
nss/tst-reload2.c
nss/tst-reload2.root/etc/hosts [new file with mode: 0644]
nss/tst-reload2.root/etc/nsswitch.conf
nss/tst-reload2.root/subdir/etc/hosts [new file with mode: 0644]
nss/tst-reload2.root/subdir/etc/nsswitch.conf
posix/bits/unistd.h
posix/unistd.h
posix/wordexp-test.c
posix/wordexp.c
rt/Makefile
rt/tst-bz28213.c [new file with mode: 0644]
socket/Makefile
socket/sockaddr_un_set.c [new file with mode: 0644]
socket/tst-sockaddr_un_set.c [new file with mode: 0644]
stdlib/Makefile
stdlib/canonicalize.c
stdlib/tst-realpath-toolong.c [new file with mode: 0644]
stdlib/tst-secure-getenv.c
string/rawmemchr.c
sunrpc/Makefile
sunrpc/clnt_gen.c
sunrpc/svc_unix.c
sunrpc/svcauth_des.c
sunrpc/tst-bug22542.c [new file with mode: 0644]
sunrpc/tst-bug28768.c [new file with mode: 0644]
support/Makefile
support/capture_subprocess.h
support/subprocess.h
support/support.h
support/support_capture_subprocess.c
support/support_select_modifies_timeout.c [new file with mode: 0644]
support/support_select_normalizes_timeout.c [new file with mode: 0644]
support/support_subprocess.c
support/temp_file.c
support/temp_file.h
support/test-container.c
support/xclone.c [new file with mode: 0644]
support/xpthread_kill.c [new file with mode: 0644]
support/xsched.h [new file with mode: 0644]
support/xthread.h
sysdeps/generic/ldsodefs.h
sysdeps/nios2/libm-test-ulps
sysdeps/nptl/lowlevellock-futex.h
sysdeps/posix/getcwd.c
sysdeps/powerpc/Makefile
sysdeps/powerpc/powerpc64/sysdep.h
sysdeps/powerpc/powerpc64/tst-ucontext-ppc64-vscr.c
sysdeps/powerpc/tst-set_ppr.c
sysdeps/pthread/Makefile
sysdeps/pthread/tst-oncey3.c [new file with mode: 0644]
sysdeps/pthread/tst-oncey4.c [new file with mode: 0644]
sysdeps/pthread/tst-pthread-exit-signal.c [new file with mode: 0644]
sysdeps/riscv/rv64/rvd/libm-test-ulps
sysdeps/s390/configure
sysdeps/s390/configure.ac
sysdeps/s390/dl-procinfo.c
sysdeps/s390/dl-procinfo.h
sysdeps/s390/memmem-arch13.S
sysdeps/s390/memmove.c
sysdeps/s390/multiarch/ifunc-impl-list.c
sysdeps/s390/strstr-arch13.S
sysdeps/unix/sysv/linux/Makefile
sysdeps/unix/sysv/linux/aarch64/clone.S
sysdeps/unix/sysv/linux/aarch64/cpu-features.c
sysdeps/unix/sysv/linux/dl-diagnostics-kernel.c [new file with mode: 0644]
sysdeps/unix/sysv/linux/fstat.c
sysdeps/unix/sysv/linux/fstat64.c
sysdeps/unix/sysv/linux/mips/fxstat.c
sysdeps/unix/sysv/linux/mips/lxstat.c
sysdeps/unix/sysv/linux/mips/xstat.c
sysdeps/unix/sysv/linux/mq_notify.c
sysdeps/unix/sysv/linux/powerpc/syscall.S
sysdeps/unix/sysv/linux/s390/bits/hwcap.h
sysdeps/unix/sysv/linux/select.c
sysdeps/unix/sysv/linux/sys/prctl.h
sysdeps/unix/sysv/linux/tst-getcwd-smallbuff.c [new file with mode: 0644]
sysdeps/unix/sysv/linux/tst-sysvshm-linux.c
sysdeps/x86/Makefile
sysdeps/x86/cacheinfo.c
sysdeps/x86/cacheinfo.h
sysdeps/x86/configure
sysdeps/x86/configure.ac
sysdeps/x86/dl-cacheinfo.h
sysdeps/x86/dl-diagnostics-cpu.c [new file with mode: 0644]
sysdeps/x86/include/cpu-features-preferred_feature_index_1.def [new file with mode: 0644]
sysdeps/x86/include/cpu-features.h
sysdeps/x86/isa-level.c
sysdeps/x86/tst-cpu-features-supports.c
sysdeps/x86/tst-sysconf-cache-linesize-static.c [new file with mode: 0644]
sysdeps/x86/tst-sysconf-cache-linesize.c [new file with mode: 0644]
sysdeps/x86_64/configure [changed mode: 0644->0755]
sysdeps/x86_64/configure.ac

diff --git a/NEWS b/NEWS
index 71f5d20324a92ddd5aad861f2194bac2f4357df2..cc026f03b14c887f2ca5b208d1d9675e119312d2 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,60 @@ See the end for copying conditions.
 Please send GNU C library bug reports via <https://sourceware.org/bugzilla/>
 using `glibc' in the "product" field.
 \f
+Version 2.33.1
+
+Major new features:
+
+* The dynamic linker implements the --list-diagnostics option, printing
+  a dump of information related to IFUNC resolver operation and
+  glibc-hwcaps subdirectory selection.
+
+Security related changes:
+
+  CVE-2021-33574: The mq_notify function has a potential use-after-free
+  issue when using a notification type of SIGEV_THREAD and a thread
+  attribute with a non-default affinity mask.
+
+  CVE-2022-23219: Passing an overlong file name to the clnt_create
+  legacy function could result in a stack-based buffer overflow when
+  using the "unix" protocol.  Reported by Martin Sebor.
+
+  CVE-2022-23218: Passing an overlong file name to the svcunix_create
+  legacy function could result in a stack-based buffer overflow.
+
+  CVE-2021-3998: Passing a path longer than PATH_MAX to the realpath
+  function could result in a memory leak and potential access of
+  uninitialized memory.  Reported by Qualys.
+
+  CVE-2021-3999: Passing a buffer of size exactly 1 byte to the getcwd
+  function may result in an off-by-one buffer underflow and overflow
+  when the current working directory is longer than PATH_MAX and also
+  corresponds to the / directory through an unprivileged mount
+  namespace.  Reported by Qualys.
+
+The following bugs are resolved with this release:
+
+  [15271] dlfcn function failure after dlmopen terminates process
+  [18435] pthread_once hangs when init routine throws an exception
+  [22542] CVE-2022-23219: Buffer overflow in sunrpc clnt_create for "unix"
+  [23462] Static binary with dynamic string tokens ($LIB, $PLATFORM, $ORIGIN)
+    crashes
+  [27304] pthread_cond_destroy does not pass private flag to futex system calls
+  [27537] test-container: Always copy test-specific support files
+  [27577] elf/ld.so --help doesn't work
+  [27646] gethostbyname and NSS crashes after dlmopen
+  [27648] FAIL: misc/tst-select
+  [27651] Performance regression after updating to 2.33
+  [27706] select fails to update timeout on error
+  [27744] Support different libpthread/ld.so load orders for gdb -p
+  [27892] powerpc: scv ABI error handling fails to check IS_ERR_VALUE
+  [28607] Masked signals are delivered on thread exit
+  [28524] Conversion from ISO-2022-JP-3 with iconv may emit spurious NULs
+  [28532] powerpc64[le]: CFI for assembly templated syscalls is incorrect
+  [28768] CVE-2022-23218: Buffer overflow in sunrpc svcunix_create
+  [28769] CVE-2021-3999: Off-by-one buffer overflow/underflow in getcwd()
+  [28770] CVE-2021-3998: Unexpected return value from realpath() for too long results
+\f
 Version 2.33
 
 Major new features:
@@ -238,6 +292,7 @@ The following bugs are resolved with this release:
   [27237] malloc: deadlock in malloc/tst-malloc-stats-cancellation
   [27256] locale: Assertion failure in ISO-2022-JP-3 gconv module
     related to combining characters (CVE-2021-3326)
+  [28784] x86: crash in 32bit memset-sse2.s when the cache size can not be determined
 
 \f
 Version 2.32
index 06ee8ae26a0eb8332cb6c0b85cea2cf7aaab8b09..f21bf04e4791e5dc8d1c680361d2899dba035751 100644 (file)
 /* Define if x86 ISA level should be included in shared libraries.  */
 #undef INCLUDE_X86_ISA_LEVEL
 
+/* Define if -msahf is enabled by default on x86.  */
+#undef HAVE_X86_LAHF_SAHF
+
+/* Define if -mmovbe is enabled by default on x86.  */
+#undef HAVE_X86_MOVBE
+
 #endif
index 48b4c25bead9f0c89fbafc90dafec105d01a15e5..ff7c7b9228c4a6d861b8cfb047617731876d302b 100644 (file)
@@ -167,8 +167,17 @@ _dlerror_run (void (*operate) (void *), void *args)
       result->errstring = NULL;
     }
 
-  result->errcode = _dl_catch_error (&result->objname, &result->errstring,
-                                    &result->malloced, operate, args);
+#ifdef SHARED
+  result->errcode = _dl_catch_error_ptr (&result->objname,
+                                        &result->errstring,
+                                        &result->malloced,
+                                        operate, args);
+#else
+  result->errcode = _dl_catch_error (&result->objname,
+                                    &result->errstring,
+                                    &result->malloced,
+                                    operate, args);
+#endif
 
   /* If no error we mark that no error string is available.  */
   result->returned = result->errstring == NULL;
index 5d666b1b0c7ba82c7f62609393e8682c0fa66c0e..4fc3bd8239c8a99b61967ac50b60e55a3e80909a 100644 (file)
@@ -66,7 +66,7 @@ elide-routines.os = $(all-dl-routines) dl-support enbl-secure dl-origin \
 # interpreter and operating independent of libc.
 rtld-routines  = rtld $(all-dl-routines) dl-sysdep dl-environ dl-minimal \
   dl-error-minimal dl-conflict dl-hwcaps dl-hwcaps_split dl-hwcaps-subdirs \
-  dl-usage
+  dl-usage dl-diagnostics dl-diagnostics-kernel dl-diagnostics-cpu
 all-rtld-routines = $(rtld-routines) $(sysdep-rtld-routines)
 
 CFLAGS-dl-runtime.c += -fexceptions -fasynchronous-unwind-tables
@@ -164,7 +164,8 @@ tests-static-normal := tst-leaks1-static tst-array1-static tst-array5-static \
               tst-dl-iter-static \
               tst-tlsalign-static tst-tlsalign-extern-static \
               tst-linkall-static tst-env-setuid tst-env-setuid-tunables \
-              tst-single_threaded-static tst-single_threaded-pthread-static
+              tst-single_threaded-static tst-single_threaded-pthread-static \
+              tst-dst-static
 
 tests-static-internal := tst-tls1-static tst-tls2-static \
               tst-ptrguard1-static tst-stackguard1-static \
@@ -225,7 +226,8 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \
         tst-audit14 tst-audit15 tst-audit16 \
         tst-single_threaded tst-single_threaded-pthread \
         tst-tls-ie tst-tls-ie-dlmopen argv0test \
-        tst-glibc-hwcaps tst-glibc-hwcaps-prepend tst-glibc-hwcaps-mask
+        tst-glibc-hwcaps tst-glibc-hwcaps-prepend tst-glibc-hwcaps-mask \
+        tst-dlmopen-dlerror tst-dlmopen-gethostbyname
 #       reldep9
 tests-internal += loadtest unload unload2 circleload1 \
         neededtest neededtest2 neededtest3 neededtest4 \
@@ -244,7 +246,7 @@ tests += $(tests-execstack-$(have-z-execstack))
 ifeq ($(run-built-tests),yes)
 tests-special += $(objpfx)tst-leaks1-mem.out \
                 $(objpfx)tst-leaks1-static-mem.out $(objpfx)noload-mem.out \
-                $(objpfx)tst-ldconfig-X.out
+                $(objpfx)tst-ldconfig-X.out $(objpfx)tst-rtld-help.out
 endif
 tlsmod17a-suffixes = 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
 tlsmod18a-suffixes = 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
@@ -347,6 +349,7 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
                libmarkermod2-1 libmarkermod2-2 \
                libmarkermod3-1 libmarkermod3-2 libmarkermod3-3 \
                libmarkermod4-1 libmarkermod4-2 libmarkermod4-3 libmarkermod4-4 \
+               tst-dlmopen-dlerror-mod tst-dlmopen-gethostbyname-mod \
 
 # Most modules build with _ISOMAC defined, but those filtered out
 # depend on internal headers.
@@ -432,7 +435,8 @@ endif
 ifeq (yes,$(build-shared))
 ifeq ($(run-built-tests),yes)
 tests-special += $(objpfx)tst-pathopt.out $(objpfx)tst-rtld-load-self.out \
-                $(objpfx)tst-rtld-preload.out $(objpfx)argv0test.out
+                $(objpfx)tst-rtld-preload.out $(objpfx)argv0test.out \
+                $(objpfx)tst-rtld-help.out
 endif
 tests-special += $(objpfx)check-textrel.out $(objpfx)check-execstack.out \
                 $(objpfx)check-wx-segment.out \
@@ -678,6 +682,9 @@ CFLAGS-cache.c += $(SYSCONF-FLAGS)
 CFLAGS-rtld.c += $(SYSCONF-FLAGS)
 CFLAGS-dl-usage.c += $(SYSCONF-FLAGS) \
   -D'RTLD="$(rtlddir)/$(rtld-installed-name)"'
+CFLAGS-dl-diagnostics.c += $(SYSCONF-FLAGS) \
+  -D'PREFIX="$(prefix)"' \
+  -D'RTLD="$(rtlddir)/$(rtld-installed-name)"'
 
 cpp-srcs-left := $(all-rtld-routines:=.os)
 lib := rtld
@@ -1578,6 +1585,10 @@ $(objpfx)tst-sonamemove-dlopen.out: \
   $(objpfx)tst-sonamemove-runmod1.so \
   $(objpfx)tst-sonamemove-runmod2.so
 
+$(objpfx)tst-dlmopen-dlerror: $(libdl)
+$(objpfx)tst-dlmopen-dlerror-mod.so: $(libdl) $(libsupport)
+$(objpfx)tst-dlmopen-dlerror.out: $(objpfx)tst-dlmopen-dlerror-mod.so
+
 # Override -z defs, so that we can reference an undefined symbol.
 # Force lazy binding for the same reason.
 LDFLAGS-tst-latepthreadmod.so = \
@@ -1653,8 +1664,6 @@ $(objpfx)tst-nodelete-dlclose.out: $(objpfx)tst-nodelete-dlclose-dso.so \
 
 tst-env-setuid-ENV = MALLOC_CHECK_=2 MALLOC_MMAP_THRESHOLD_=4096 \
                     LD_HWCAP_MASK=0x1
-tst-env-setuid-tunables-ENV = \
-       GLIBC_TUNABLES=glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096
 
 $(objpfx)tst-debug1: $(libdl)
 $(objpfx)tst-debug1.out: $(objpfx)tst-debug1mod1.so
@@ -1902,3 +1911,21 @@ $(objpfx)list-tunables.out: tst-rtld-list-tunables.sh $(objpfx)ld.so
        cmp tst-rtld-list-tunables.exp \
            $(objpfx)/tst-rtld-list-tunables.out > $@; \
        $(evaluate-test)
+
+tst-dst-static-ENV = LD_LIBRARY_PATH='$$ORIGIN'
+
+$(objpfx)tst-rtld-help.out: $(objpfx)ld.so
+       $(test-wrapper) $(rtld-prefix) --help > $@; \
+       status=$$?; \
+       echo "info: ld.so exit status: $$status" >> $@; \
+       if ! grep -q 'Legacy HWCAP subdirectories under library search path directories' $@; then \
+         echo "error: missing subdirectory pattern" >> $@; \
+         if test $$status -eq 0; then \
+           status=1; \
+         fi; \
+       fi; \
+       (exit $$status); \
+       $(evaluate-test)
+
+$(objpfx)tst-dlmopen-gethostbyname: $(libdl)
+$(objpfx)tst-dlmopen-gethostbyname.out: $(objpfx)tst-dlmopen-gethostbyname-mod.so
index be88c48e6d45a937c1d6a60c499aeff6c83cc5e5..cdfd7b4d2f0c6a125c5e3ed7d7010a07039c3c84 100644 (file)
@@ -72,7 +72,7 @@ ld {
 
     # Internal error handling support.  Interposed by libc.so.
     _dl_signal_exception; _dl_catch_exception;
-    _dl_signal_error; _dl_catch_error;
+    _dl_signal_error; _dl_catch_error; _dl_catch_error_ptr;
 
     # Set value of a tunable.
     __tunable_get_val;
index 32f3bef5ead040791eb4baad02568ad3e573d1d7..2b8da8650d0a96e55dc3e9bc350fe48117db0a17 100644 (file)
@@ -269,81 +269,77 @@ search_cache (const char *string_table, uint32_t string_table_size,
              if (_dl_cache_check_flags (flags)
                  && _dl_cache_verify_ptr (lib->value, string_table_size))
                {
-                 if (best == NULL || flags == GLRO (dl_correct_cache_id))
-                   {
-                     /* Named/extension hwcaps get slightly different
-                        treatment: We keep searching for a better
-                        match.  */
-                     bool named_hwcap = false;
+                 /* Named/extension hwcaps get slightly different
+                    treatment: We keep searching for a better
+                    match.  */
+                 bool named_hwcap = false;
 
-                     if (entry_size >= sizeof (struct file_entry_new))
-                       {
-                         /* The entry is large enough to include
-                            HWCAP data.  Check it.  */
-                         struct file_entry_new *libnew
-                           = (struct file_entry_new *) lib;
+                 if (entry_size >= sizeof (struct file_entry_new))
+                   {
+                     /* The entry is large enough to include
+                        HWCAP data.  Check it.  */
+                     struct file_entry_new *libnew
+                       = (struct file_entry_new *) lib;
 
 #ifdef SHARED
-                         named_hwcap = dl_cache_hwcap_extension (libnew);
-                         if (named_hwcap
-                             && !dl_cache_hwcap_isa_level_compatible (libnew))
-                           continue;
+                     named_hwcap = dl_cache_hwcap_extension (libnew);
+                     if (named_hwcap
+                         && !dl_cache_hwcap_isa_level_compatible (libnew))
+                       continue;
 #endif
 
-                         /* The entries with named/extension hwcaps
-                            have been exhausted.  Return the best
-                            match encountered so far if there is
-                            one.  */
-                         if (!named_hwcap && best != NULL)
-                           break;
+                     /* The entries with named/extension hwcaps have
+                        been exhausted (they are listed before all
+                        other entries).  Return the best match
+                        encountered so far if there is one.  */
+                     if (!named_hwcap && best != NULL)
+                       break;
 
-                         if ((libnew->hwcap & hwcap_exclude) && !named_hwcap)
-                           continue;
-                         if (GLRO (dl_osversion)
-                             && libnew->osversion > GLRO (dl_osversion))
-                           continue;
-                         if (_DL_PLATFORMS_COUNT
-                             && (libnew->hwcap & _DL_HWCAP_PLATFORM) != 0
-                             && ((libnew->hwcap & _DL_HWCAP_PLATFORM)
-                                 != platform))
-                           continue;
+                     if ((libnew->hwcap & hwcap_exclude) && !named_hwcap)
+                       continue;
+                     if (GLRO (dl_osversion)
+                         && libnew->osversion > GLRO (dl_osversion))
+                       continue;
+                     if (_DL_PLATFORMS_COUNT
+                         && (libnew->hwcap & _DL_HWCAP_PLATFORM) != 0
+                         && ((libnew->hwcap & _DL_HWCAP_PLATFORM)
+                             != platform))
+                       continue;
 
 #ifdef SHARED
-                         /* For named hwcaps, determine the priority
-                            and see if beats what has been found so
-                            far.  */
-                         if (named_hwcap)
-                           {
-                             uint32_t entry_priority
-                               = glibc_hwcaps_priority (libnew->hwcap);
-                             if (entry_priority == 0)
-                               /* Not usable at all.  Skip.  */
-                               continue;
-                             else if (best == NULL
-                                      || entry_priority < best_priority)
-                               /* This entry is of higher priority
-                                  than the previous one, or it is the
-                                  first entry.  */
-                               best_priority = entry_priority;
-                             else
-                               /* An entry has already been found,
-                                  but it is a better match.  */
-                               continue;
-                           }
-#endif /* SHARED */
+                     /* For named hwcaps, determine the priority and
+                        see if beats what has been found so far.  */
+                     if (named_hwcap)
+                       {
+                         uint32_t entry_priority
+                           = glibc_hwcaps_priority (libnew->hwcap);
+                         if (entry_priority == 0)
+                           /* Not usable at all.  Skip.  */
+                           continue;
+                         else if (best == NULL
+                                  || entry_priority < best_priority)
+                           /* This entry is of higher priority
+                              than the previous one, or it is the
+                              first entry.  */
+                           best_priority = entry_priority;
+                         else
+                           /* An entry has already been found,
+                              but it is a better match.  */
+                           continue;
                        }
+#endif /* SHARED */
+                   }
 
-                     best = string_table + lib->value;
+                 best = string_table + lib->value;
 
-                     if (flags == GLRO (dl_correct_cache_id)
-                         && !named_hwcap)
-                       /* We've found an exact match for the shared
-                          object and no general `ELF' release.  Stop
-                          searching, but not if a named (extension)
-                          hwcap is used.  In this case, an entry with
-                          a higher priority may come up later.  */
-                       break;
-                   }
+                 if (!named_hwcap && flags == _DL_CACHE_DEFAULT_ID)
+                   /* With named hwcaps, we need to keep searching to
+                      see if we find a better match.  A better match
+                      is also possible if the flags of the current
+                      entry do not match the expected cache flags.
+                      But if the flags match, no better entry will be
+                      found.  */
+                   break;
                }
            }
          while (++middle <= right);
diff --git a/elf/dl-diagnostics-cpu.c b/elf/dl-diagnostics-cpu.c
new file mode 100644 (file)
index 0000000..f7d1497
--- /dev/null
@@ -0,0 +1,24 @@
+/* Print CPU diagnostics data in ld.so.  Stub 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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <dl-diagnostics.h>
+
+void
+_dl_diagnostics_cpu (void)
+{
+}
diff --git a/elf/dl-diagnostics-kernel.c b/elf/dl-diagnostics-kernel.c
new file mode 100644 (file)
index 0000000..831c358
--- /dev/null
@@ -0,0 +1,24 @@
+/* Print kernel diagnostics data in ld.so.  Stub 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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <dl-diagnostics.h>
+
+void
+_dl_diagnostics_kernel (void)
+{
+}
diff --git a/elf/dl-diagnostics.c b/elf/dl-diagnostics.c
new file mode 100644 (file)
index 0000000..bef224b
--- /dev/null
@@ -0,0 +1,265 @@
+/* Print diagnostics data in ld.so.
+   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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <gnu/lib-names.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <unistd.h>
+
+#include <dl-diagnostics.h>
+#include <dl-hwcaps.h>
+#include <dl-main.h>
+#include <dl-procinfo.h>
+#include <dl-sysdep.h>
+#include <ldsodefs.h>
+#include "trusted-dirs.h"
+#include "version.h"
+
+/* Write CH to standard output.  */
+static void
+_dl_putc (char ch)
+{
+  _dl_write (STDOUT_FILENO, &ch, 1);
+}
+
+/* Print CH to standard output, quoting it if necessary.  */
+static void
+print_quoted_char (char ch)
+{
+  if (ch < ' ' || ch > '~')
+    {
+      char buf[4];
+      buf[0] = '\\';
+      buf[1] = '0' + ((ch >> 6) & 7);
+      buf[2] = '0' + ((ch >> 6) & 7);
+      buf[3] = '0' + (ch & 7);
+      _dl_write (STDOUT_FILENO, buf, 4);
+    }
+  else
+    {
+      if (ch == '\\' || ch == '"')
+        _dl_putc ('\\');
+      _dl_putc (ch);
+    }
+}
+
+/* Print S of LEN bytes to standard output, quoting characters as
+   needed.  */
+static void
+print_string_length (const char *s, size_t len)
+{
+  _dl_putc ('"');
+  for (size_t i = 0; i < len; ++i)
+    print_quoted_char (s[i]);
+  _dl_putc ('"');
+}
+
+void
+_dl_diagnostics_print_string (const char *s)
+{
+  if (s == NULL)
+    {
+      _dl_printf ("0x0");
+      return;
+    }
+
+  _dl_putc ('"');
+  while (*s != '\0')
+    {
+      print_quoted_char (*s);
+      ++s;
+    }
+  _dl_putc ('"');
+}
+
+void
+_dl_diagnostics_print_labeled_string (const char *label, const char *s)
+{
+  _dl_printf ("%s=", label);
+  _dl_diagnostics_print_string (s);
+  _dl_putc ('\n');
+}
+
+void
+_dl_diagnostics_print_labeled_value (const char *label, uint64_t value)
+{
+  if (sizeof (value) == sizeof (unsigned long int))
+    /* _dl_printf can print 64-bit values directly.  */
+    _dl_printf ("%s=0x%lx\n", label, (unsigned long int) value);
+  else
+    {
+      uint32_t high = value >> 32;
+      uint32_t low = value;
+      if (high == 0)
+        _dl_printf ("%s=0x%x\n", label, low);
+      else
+        _dl_printf ("%s=0x%x%08x\n", label, high, low);
+    }
+}
+
+/* Return true if ENV is an unfiltered environment variable.  */
+static bool
+unfiltered_envvar (const char *env, size_t *name_length)
+{
+  char *env_equal = strchr (env, '=');
+  if (env_equal == NULL)
+    {
+      /* Always dump malformed entries.  */
+      *name_length = strlen (env);
+      return true;
+    }
+  size_t envname_length = env_equal - env;
+  *name_length = envname_length;
+
+  /* LC_ and LD_ variables.  */
+  if (env[0] == 'L' && (env[1] == 'C' || env[1] == 'D')
+      && env[2] == '_')
+    return true;
+
+  /* MALLOC_ variables.  */
+  if (strncmp (env, "MALLOC_", strlen ("MALLOC_")) == 0)
+    return true;
+
+  static const char unfiltered[] =
+    "DATEMSK\0"
+    "GCONV_PATH\0"
+    "GETCONF_DIR\0"
+    "GETCONF_DIR\0"
+    "GLIBC_TUNABLES\0"
+    "GMON_OUTPUT_PREFIX\0"
+    "HESIOD_CONFIG\0"
+    "HES_DOMAIN\0"
+    "HOSTALIASES\0"
+    "I18NPATH\0"
+    "IFS\0"
+    "LANG\0"
+    "LOCALDOMAIN\0"
+    "LOCPATH\0"
+    "MSGVERB\0"
+    "NIS_DEFAULTS\0"
+    "NIS_GROUP\0"
+    "NIS_PATH\0"
+    "NLSPATH\0"
+    "PATH\0"
+    "POSIXLY_CORRECT\0"
+    "RESOLV_HOST_CONF\0"
+    "RES_OPTIONS\0"
+    "SEV_LEVEL\0"
+    "TMPDIR\0"
+    "TZ\0"
+    "TZDIR\0"
+    /* Two null bytes at the end to mark the end of the list via an
+       empty substring.  */
+    ;
+  for (const char *candidate = unfiltered; *candidate != '\0'; )
+    {
+      size_t candidate_length = strlen (candidate);
+      if (candidate_length == envname_length
+          && memcmp (candidate, env, candidate_length) == 0)
+        return true;
+      candidate += candidate_length + 1;
+    }
+
+  return false;
+}
+
+/* Dump the process environment.  */
+static void
+print_environ (char **environ)
+{
+  unsigned int index = 0;
+  for (char **envp = environ; *envp != NULL; ++envp)
+    {
+      char *env = *envp;
+      size_t name_length;
+      bool unfiltered = unfiltered_envvar (env, &name_length);
+      _dl_printf ("env%s[0x%x]=",
+                  unfiltered ? "" : "_filtered", index);
+      if (unfiltered)
+        _dl_diagnostics_print_string (env);
+      else
+        print_string_length (env, name_length);
+      _dl_putc ('\n');
+      ++index;
+    }
+}
+
+/* Print configured paths and the built-in search path.  */
+static void
+print_paths (void)
+{
+  _dl_diagnostics_print_labeled_string ("path.prefix", PREFIX);
+  _dl_diagnostics_print_labeled_string ("path.rtld", RTLD);
+  _dl_diagnostics_print_labeled_string ("path.sysconfdir", SYSCONFDIR);
+
+  unsigned int index = 0;
+  static const char *system_dirs = SYSTEM_DIRS "\0";
+  for (const char *e = system_dirs; *e != '\0'; )
+    {
+      size_t len = strlen (e);
+      _dl_printf ("path.system_dirs[0x%x]=", index);
+      print_string_length (e, len);
+      _dl_putc ('\n');
+      ++index;
+      e += len + 1;
+    }
+}
+
+/* Print information about the glibc version.  */
+static void
+print_version (void)
+{
+  _dl_diagnostics_print_labeled_string ("version.release", RELEASE);
+  _dl_diagnostics_print_labeled_string ("version.version", VERSION);
+}
+
+void
+_dl_print_diagnostics (char **environ)
+{
+#ifdef HAVE_DL_DISCOVER_OSVERSION
+  _dl_diagnostics_print_labeled_value
+    ("dl_discover_osversion", _dl_discover_osversion ());
+#endif
+  _dl_diagnostics_print_labeled_string ("dl_dst_lib", DL_DST_LIB);
+  _dl_diagnostics_print_labeled_value ("dl_hwcap", GLRO (dl_hwcap));
+  _dl_diagnostics_print_labeled_value ("dl_hwcap_important", HWCAP_IMPORTANT);
+  _dl_diagnostics_print_labeled_value ("dl_hwcap2", GLRO (dl_hwcap2));
+  _dl_diagnostics_print_labeled_string
+    ("dl_hwcaps_subdirs", _dl_hwcaps_subdirs);
+  _dl_diagnostics_print_labeled_value
+    ("dl_hwcaps_subdirs_active", _dl_hwcaps_subdirs_active ());
+  _dl_diagnostics_print_labeled_value ("dl_osversion", GLRO (dl_osversion));
+  _dl_diagnostics_print_labeled_value ("dl_pagesize", GLRO (dl_pagesize));
+  _dl_diagnostics_print_labeled_string ("dl_platform", GLRO (dl_platform));
+  _dl_diagnostics_print_labeled_string
+    ("dl_profile_output", GLRO (dl_profile_output));
+  _dl_diagnostics_print_labeled_value
+    ("dl_string_platform", _dl_string_platform ( GLRO (dl_platform)));
+
+  _dl_diagnostics_print_labeled_string ("dso.ld", LD_SO);
+  _dl_diagnostics_print_labeled_string ("dso.libc", LIBC_SO);
+
+  print_environ (environ);
+  print_paths ();
+  print_version ();
+
+  _dl_diagnostics_kernel ();
+  _dl_diagnostics_cpu ();
+
+  _exit (EXIT_SUCCESS);
+}
diff --git a/elf/dl-diagnostics.h b/elf/dl-diagnostics.h
new file mode 100644 (file)
index 0000000..27dcb12
--- /dev/null
@@ -0,0 +1,46 @@
+/* Interfaces for printing diagnostics in ld.so.
+   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
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _DL_DIAGNOSTICS_H
+#define _DL_DIAGNOSTICS_H
+
+#include <stdint.h>
+
+/* Write the null-terminated string to standard output, surrounded in
+   quotation marks.  */
+void _dl_diagnostics_print_string (const char *s) attribute_hidden;
+
+/* Like _dl_diagnostics_print_string, but add a LABEL= prefix, and a
+   newline character as a suffix.  */
+void _dl_diagnostics_print_labeled_string (const char *label, const char *s)
+  attribute_hidden;
+
+/* Print LABEL=VALUE to standard output, followed by a newline
+   character.  */
+void _dl_diagnostics_print_labeled_value (const char *label, uint64_t value)
+  attribute_hidden;
+
+/* Print diagnostics data for the kernel.  Called from
+   _dl_print_diagnostics.  */
+void _dl_diagnostics_kernel (void) attribute_hidden;
+
+/* Print diagnostics data for the CPU(s).  Called from
+   _dl_print_diagnostics.  */
+void _dl_diagnostics_cpu (void) attribute_hidden;
+
+#endif /* _DL_DIAGNOSTICS_H */
index 2fd62777cfc4f34d847f6c02013f45dfe13da011..0de505f2584612e01818dd1cadea678a8dcae2c9 100644 (file)
@@ -248,4 +248,19 @@ _dl_receive_error (receiver_fct fct, void (*operate) (void *), void *args)
   catch_hook = old_catch;
   receiver = old_receiver;
 }
+
+/* Forwarder used for initializing _dl_catch_error_ptr.  */
+int
+_rtld_catch_error (const char **objname, const char **errstring,
+                  bool *mallocedp, void (*operate) (void *),
+                  void *args)
+{
+  /* The reference to _dl_catch_error will eventually be relocated to
+     point to the implementation in libc.so.  */
+  return _dl_catch_error (objname, errstring, mallocedp, operate, args);
+}
+
+__typeof (_dl_catch_error) *_dl_catch_error_ptr = _rtld_catch_error;
+rtld_hidden_data_def (_dl_catch_error_ptr);
+
 #endif /* DL_ERROR_BOOTSTRAP */
index ed551f6e56b3cb31ca7c1730722c33cddf72eb98..e2236d87d1df4cfaf004b2cb430bb953dbbbe2c2 100644 (file)
@@ -43,9 +43,15 @@ dlerror_run (void (*operate) (void *), void *args)
   const char *last_errstring = NULL;
   bool malloced;
 
+#ifdef SHARED
+  int result = (_dl_catch_error_ptr (&objname, &last_errstring, &malloced,
+                                    operate, args)
+               ?: last_errstring != NULL);
+#else
   int result = (_dl_catch_error (&objname, &last_errstring, &malloced,
-                               operate, args)
+                                operate, args)
                ?: last_errstring != NULL);
+#endif
 
   if (result && malloced)
     free ((char *) last_errstring);
index 9e2089cfaa7dd4b1abd23426dc2d5e78e7ce1f8e..2f760503c5f117f8fd3c85b8ef5ec2bac068a1b8 100644 (file)
@@ -758,50 +758,51 @@ _dl_init_paths (const char *llp, const char *source,
   max_dirnamelen = SYSTEM_DIRS_MAX_LEN;
   *aelem = NULL;
 
-#ifdef SHARED
-  /* This points to the map of the main object.  */
+  /* This points to the map of the main object.  If there is no main
+     object (e.g., under --help, use the dynamic loader itself as a
+     stand-in.  */
   l = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
-  if (l != NULL)
+#ifdef SHARED
+  if (l == NULL)
+    l = &GL (dl_rtld_map);
+#endif
+  assert (l->l_type != lt_loaded);
+
+  if (l->l_info[DT_RUNPATH])
+    {
+      /* Allocate room for the search path and fill in information
+        from RUNPATH.  */
+      decompose_rpath (&l->l_runpath_dirs,
+                      (const void *) (D_PTR (l, l_info[DT_STRTAB])
+                                      + l->l_info[DT_RUNPATH]->d_un.d_val),
+                      l, "RUNPATH");
+      /* During rtld init the memory is allocated by the stub malloc,
+        prevent any attempt to free it by the normal malloc.  */
+      l->l_runpath_dirs.malloced = 0;
+
+      /* The RPATH is ignored.  */
+      l->l_rpath_dirs.dirs = (void *) -1;
+    }
+  else
     {
-      assert (l->l_type != lt_loaded);
+      l->l_runpath_dirs.dirs = (void *) -1;
 
-      if (l->l_info[DT_RUNPATH])
+      if (l->l_info[DT_RPATH])
        {
          /* Allocate room for the search path and fill in information
-            from RUNPATH.  */
-         decompose_rpath (&l->l_runpath_dirs,
+            from RPATH.  */
+         decompose_rpath (&l->l_rpath_dirs,
                           (const void *) (D_PTR (l, l_info[DT_STRTAB])
-                                          + l->l_info[DT_RUNPATH]->d_un.d_val),
-                          l, "RUNPATH");
-         /* During rtld init the memory is allocated by the stub malloc,
-            prevent any attempt to free it by the normal malloc.  */
-         l->l_runpath_dirs.malloced = 0;
-
-         /* The RPATH is ignored.  */
-         l->l_rpath_dirs.dirs = (void *) -1;
+                                          + l->l_info[DT_RPATH]->d_un.d_val),
+                          l, "RPATH");
+         /* During rtld init the memory is allocated by the stub
+            malloc, prevent any attempt to free it by the normal
+            malloc.  */
+         l->l_rpath_dirs.malloced = 0;
        }
       else
-       {
-         l->l_runpath_dirs.dirs = (void *) -1;
-
-         if (l->l_info[DT_RPATH])
-           {
-             /* Allocate room for the search path and fill in information
-                from RPATH.  */
-             decompose_rpath (&l->l_rpath_dirs,
-                              (const void *) (D_PTR (l, l_info[DT_STRTAB])
-                                              + l->l_info[DT_RPATH]->d_un.d_val),
-                              l, "RPATH");
-             /* During rtld init the memory is allocated by the stub
-                malloc, prevent any attempt to free it by the normal
-                malloc.  */
-             l->l_rpath_dirs.malloced = 0;
-           }
-         else
-           l->l_rpath_dirs.dirs = (void *) -1;
-       }
+       l->l_rpath_dirs.dirs = (void *) -1;
     }
-#endif /* SHARED */
 
   if (llp != NULL && *llp != '\0')
     {
index 3a5e13c73923ad68f7f6a719703ce1bde9dda779..d3820e00631438784773332fb7c7e2a932ccfc8d 100644 (file)
@@ -63,7 +63,7 @@ struct audit_list
 enum rtld_mode
   {
     rtld_mode_normal, rtld_mode_list, rtld_mode_verify, rtld_mode_trace,
-    rtld_mode_list_tunables, rtld_mode_help,
+    rtld_mode_list_tunables, rtld_mode_list_diagnostics, rtld_mode_help,
   };
 
 /* Aggregated state information extracted from environment variables
@@ -121,4 +121,7 @@ _Noreturn void _dl_version (void) attribute_hidden;
 _Noreturn void _dl_help (const char *argv0, struct dl_main_state *state)
   attribute_hidden;
 
+/* Print a diagnostics dump.  */
+_Noreturn void _dl_print_diagnostics (char **environ) attribute_hidden;
+
 #endif /* _DL_MAIN */
index ab7aaa345eb36cf84d4858dcd69abee9827f5617..1b965457c4fb8270d45df4d5fcbad2df797900b9 100644 (file)
@@ -881,7 +881,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.  */
index 3fcc0806f5f2ec04907d0cf6a8a68837a1c48047..39bf738d930efca2a3aaf181d8124525d16eec7d 100644 (file)
@@ -38,8 +38,8 @@ typedef enum
 typedef struct
 {
   tunable_type_code_t type_code;
-  int64_t min;
-  int64_t max;
+  tunable_num_t min;
+  tunable_num_t max;
 } tunable_type_t;
 
 /* Security level for tunables.  This decides what to do with individual
@@ -81,4 +81,21 @@ struct _tunable
 
 typedef struct _tunable tunable_t;
 
+static __always_inline bool
+unsigned_tunable_type (tunable_type_code_t t)
+{
+  switch (t)
+    {
+    case TUNABLE_TYPE_INT_32:
+      return false;
+    case TUNABLE_TYPE_UINT_64:
+    case TUNABLE_TYPE_SIZE_T:
+      return true;
+    case TUNABLE_TYPE_STRING:
+    default:
+      break;
+    }
+  __builtin_unreachable ();
+}
+
 #endif
index b1a50b84693d15de59eaedb4cd5b7db24e223845..8009e54ee5db32beb228e69b05352e80c809c42c 100644 (file)
@@ -93,88 +93,49 @@ get_next_env (char **envp, char **name, size_t *namelen, char **val,
   return NULL;
 }
 
-#define TUNABLE_SET_VAL_IF_VALID_RANGE(__cur, __val, __type)                 \
-({                                                                           \
-  __type min = (__cur)->type.min;                                            \
-  __type max = (__cur)->type.max;                                            \
-                                                                             \
-  if ((__type) (__val) >= min && (__type) (__val) <= max)                    \
-    {                                                                        \
-      (__cur)->val.numval = (__val);                                         \
-      (__cur)->initialized = true;                                           \
-    }                                                                        \
-})
-
-#define TUNABLE_SET_BOUNDS_IF_VALID(__cur, __minp, __maxp, __type)           \
-({                                                                           \
-  if (__minp != NULL)                                                        \
-    {                                                                        \
-      /* MIN is specified.  */                                               \
-      __type min = *((__type *) __minp);                                     \
-      if (__maxp != NULL)                                                    \
-       {                                                                     \
-          /* Both MIN and MAX are specified.  */                             \
-           __type max = *((__type *) __maxp);                                \
-         if (max >= min                                                      \
-             && max <= (__cur)->type.max                                     \
-             && min >= (__cur)->type.min)                                    \
-           {                                                                 \
-             (__cur)->type.min = min;                                        \
-             (__cur)->type.max = max;                                        \
-           }                                                                 \
-       }                                                                     \
-      else if (min > (__cur)->type.min && min <= (__cur)->type.max)          \
-       {                                                                     \
-         /* Only MIN is specified.  */                                       \
-         (__cur)->type.min = min;                                            \
-       }                                                                     \
-    }                                                                        \
-  else if (__maxp != NULL)                                                   \
-    {                                                                        \
-      /* Only MAX is specified.  */                                          \
-      __type max = *((__type *) __maxp);                                     \
-      if (max < (__cur)->type.max && max >= (__cur)->type.min)               \
-       (__cur)->type.max = max;                                              \
-    }                                                                        \
-})
-
 static void
-do_tunable_update_val (tunable_t *cur, const void *valp,
-                      const void *minp, const void *maxp)
+do_tunable_update_val (tunable_t *cur, const tunable_val_t *valp,
+                      const tunable_num_t *minp,
+                      const tunable_num_t *maxp)
 {
-  uint64_t val;
+  tunable_num_t val, min, max;
 
-  if (cur->type.type_code != TUNABLE_TYPE_STRING)
-    val = *((int64_t *) valp);
+  if (cur->type.type_code == TUNABLE_TYPE_STRING)
+    {
+      cur->val.strval = valp->strval;
+      cur->initialized = true;
+      return;
+    }
 
-  switch (cur->type.type_code)
+  bool unsigned_cmp = unsigned_tunable_type (cur->type.type_code);
+
+  val = valp->numval;
+  min = minp != NULL ? *minp : cur->type.min;
+  max = maxp != NULL ? *maxp : cur->type.max;
+
+  /* We allow only increasingly restrictive bounds.  */
+  if (tunable_val_lt (min, cur->type.min, unsigned_cmp))
+    min = cur->type.min;
+
+  if (tunable_val_gt (max, cur->type.max, unsigned_cmp))
+    max = cur->type.max;
+
+  /* Skip both bounds if they're inconsistent.  */
+  if (tunable_val_gt (min, max, unsigned_cmp))
     {
-    case TUNABLE_TYPE_INT_32:
-       {
-         TUNABLE_SET_BOUNDS_IF_VALID (cur, minp, maxp, int64_t);
-         TUNABLE_SET_VAL_IF_VALID_RANGE (cur, val, int64_t);
-         break;
-       }
-    case TUNABLE_TYPE_UINT_64:
-       {
-         TUNABLE_SET_BOUNDS_IF_VALID (cur, minp, maxp, uint64_t);
-         TUNABLE_SET_VAL_IF_VALID_RANGE (cur, val, uint64_t);
-         break;
-       }
-    case TUNABLE_TYPE_SIZE_T:
-       {
-         TUNABLE_SET_BOUNDS_IF_VALID (cur, minp, maxp, uint64_t);
-         TUNABLE_SET_VAL_IF_VALID_RANGE (cur, val, uint64_t);
-         break;
-       }
-    case TUNABLE_TYPE_STRING:
-       {
-         cur->val.strval = valp;
-         break;
-       }
-    default:
-      __builtin_unreachable ();
+      min = cur->type.min;
+      max = cur->type.max;
     }
+
+  /* Bail out if the bounds are not valid.  */
+  if (tunable_val_lt (val, min, unsigned_cmp)
+      || tunable_val_lt (max, val, unsigned_cmp))
+    return;
+
+  cur->val.numval = val;
+  cur->type.min = min;
+  cur->type.max = max;
+  cur->initialized = true;
 }
 
 /* Validate range of the input value and initialize the tunable CUR if it looks
@@ -182,24 +143,18 @@ do_tunable_update_val (tunable_t *cur, const void *valp,
 static void
 tunable_initialize (tunable_t *cur, const char *strval)
 {
-  uint64_t val;
-  const void *valp;
+  tunable_val_t val;
 
   if (cur->type.type_code != TUNABLE_TYPE_STRING)
-    {
-      val = _dl_strtoul (strval, NULL);
-      valp = &val;
-    }
+    val.numval = (tunable_num_t) _dl_strtoul (strval, NULL);
   else
-    {
-      cur->initialized = true;
-      valp = strval;
-    }
-  do_tunable_update_val (cur, valp, NULL, NULL);
+    val.strval = strval;
+  do_tunable_update_val (cur, &val, NULL, NULL);
 }
 
 void
-__tunable_set_val (tunable_id_t id, void *valp, void *minp, void *maxp)
+__tunable_set_val (tunable_id_t id, tunable_val_t *valp, tunable_num_t *minp,
+                  tunable_num_t *maxp)
 {
   tunable_t *cur = &tunable_list[id];
 
@@ -219,6 +174,7 @@ parse_tunables (char *tunestr, char *valstring)
     return;
 
   char *p = tunestr;
+  size_t off = 0;
 
   while (true)
     {
@@ -232,7 +188,11 @@ parse_tunables (char *tunestr, char *valstring)
       /* If we reach the end of the string before getting a valid name-value
         pair, bail out.  */
       if (p[len] == '\0')
-       return;
+       {
+         if (__libc_enable_secure)
+           tunestr[off] = '\0';
+         return;
+       }
 
       /* We did not find a valid name-value pair before encountering the
         colon.  */
@@ -258,35 +218,28 @@ parse_tunables (char *tunestr, char *valstring)
 
          if (tunable_is_name (cur->name, name))
            {
-             /* If we are in a secure context (AT_SECURE) then ignore the tunable
-                unless it is explicitly marked as secure.  Tunable values take
-                precedence over their envvar aliases.  */
+             /* If we are in a secure context (AT_SECURE) then ignore the
+                tunable unless it is explicitly marked as secure.  Tunable
+                values take precedence over their envvar aliases.  We write
+                the tunables that are not SXID_ERASE back to TUNESTR, thus
+                dropping all SXID_ERASE tunables and any invalid or
+                unrecognized tunables.  */
              if (__libc_enable_secure)
                {
-                 if (cur->security_level == TUNABLE_SECLEVEL_SXID_ERASE)
+                 if (cur->security_level != TUNABLE_SECLEVEL_SXID_ERASE)
                    {
-                     if (p[len] == '\0')
-                       {
-                         /* Last tunable in the valstring.  Null-terminate and
-                            return.  */
-                         *name = '\0';
-                         return;
-                       }
-                     else
-                       {
-                         /* Remove the current tunable from the string.  We do
-                            this by overwriting the string starting from NAME
-                            (which is where the current tunable begins) with
-                            the remainder of the string.  We then have P point
-                            to NAME so that we continue in the correct
-                            position in the valstring.  */
-                         char *q = &p[len + 1];
-                         p = name;
-                         while (*q != '\0')
-                           *name++ = *q++;
-                         name[0] = '\0';
-                         len = 0;
-                       }
+                     if (off > 0)
+                       tunestr[off++] = ':';
+
+                     const char *n = cur->name;
+
+                     while (*n != '\0')
+                       tunestr[off++] = *n++;
+
+                     tunestr[off++] = '=';
+
+                     for (size_t j = 0; j < len; j++)
+                       tunestr[off++] = value[j];
                    }
 
                  if (cur->security_level != TUNABLE_SECLEVEL_NONE)
@@ -299,9 +252,7 @@ parse_tunables (char *tunestr, char *valstring)
            }
        }
 
-      if (p[len] == '\0')
-       return;
-      else
+      if (p[len] != '\0')
        p += len + 1;
     }
 }
index 971376ba8d3bad1c8c51362604c635fdda08d81b..3880e4aab623771eda3df7fcf7f47f8b48217c58 100644 (file)
@@ -33,9 +33,11 @@ __tunables_init (char **unused __attribute__ ((unused)))
 # include <stddef.h>
 # include <stdint.h>
 
+typedef intmax_t tunable_num_t;
+
 typedef union
 {
-  int64_t numval;
+  tunable_num_t numval;
   const char *strval;
 } tunable_val_t;
 
@@ -52,7 +54,8 @@ typedef void (*tunable_callback_t) (tunable_val_t *);
 extern void __tunables_init (char **);
 extern void __tunables_print (void);
 extern void __tunable_get_val (tunable_id_t, void *, tunable_callback_t);
-extern void __tunable_set_val (tunable_id_t, void *, void *, void *);
+extern void __tunable_set_val (tunable_id_t, tunable_val_t *, tunable_num_t *,
+                              tunable_num_t *);
 rtld_hidden_proto (__tunables_init)
 rtld_hidden_proto (__tunables_print)
 rtld_hidden_proto (__tunable_get_val)
@@ -64,20 +67,18 @@ rtld_hidden_proto (__tunable_set_val)
 #if defined TOP_NAMESPACE && defined TUNABLE_NAMESPACE
 # define TUNABLE_GET(__id, __type, __cb) \
   TUNABLE_GET_FULL (TOP_NAMESPACE, TUNABLE_NAMESPACE, __id, __type, __cb)
-# define TUNABLE_SET(__id, __type, __val) \
-  TUNABLE_SET_FULL (TOP_NAMESPACE, TUNABLE_NAMESPACE, __id, __type, __val)
-# define TUNABLE_SET_WITH_BOUNDS(__id, __type, __val, __min, __max) \
+# define TUNABLE_SET(__id, __val) \
+  TUNABLE_SET_FULL (TOP_NAMESPACE, TUNABLE_NAMESPACE, __id, __val)
+# define TUNABLE_SET_WITH_BOUNDS(__id, __val, __min, __max) \
   TUNABLE_SET_WITH_BOUNDS_FULL (TOP_NAMESPACE, TUNABLE_NAMESPACE, __id, \
-                               __type, __val, __min, __max)
+                               __val, __min, __max)
 #else
 # define TUNABLE_GET(__top, __ns, __id, __type, __cb) \
   TUNABLE_GET_FULL (__top, __ns, __id, __type, __cb)
-# define TUNABLE_SET(__top, __ns, __id, __type, __val) \
-  TUNABLE_SET_FULL (__top, __ns, __id, __type, __val)
-# define TUNABLE_SET_WITH_BOUNDS(__top, __ns, __id, __type, __val, \
-                                __min, __max) \
-  TUNABLE_SET_WITH_BOUNDS_FULL (__top, __ns, __id, __type, __val, \
-                               __min, __max)
+# define TUNABLE_SET(__top, __ns, __id, __val) \
+  TUNABLE_SET_FULL (__top, __ns, __id, __val)
+# define TUNABLE_SET_WITH_BOUNDS(__top, __ns, __id, __val, __min, __max) \
+  TUNABLE_SET_WITH_BOUNDS_FULL (__top, __ns, __id, __val, __min, __max)
 #endif
 
 /* Get and return a tunable value.  If the tunable was set externally and __CB
@@ -91,19 +92,19 @@ rtld_hidden_proto (__tunable_set_val)
 })
 
 /* Set a tunable value.  */
-# define TUNABLE_SET_FULL(__top, __ns, __id, __type, __val) \
+# define TUNABLE_SET_FULL(__top, __ns, __id, __val) \
 ({                                                                           \
   __tunable_set_val (TUNABLE_ENUM_NAME (__top, __ns, __id),                  \
-                    & (__type) {__val}, NULL, NULL);                         \
+                    & (tunable_val_t) {.numval = __val}, NULL, NULL);        \
 })
 
 /* Set a tunable value together with min/max values.  */
-# define TUNABLE_SET_WITH_BOUNDS_FULL(__top, __ns, __id, __type, __val,              \
-                                     __min, __max)                           \
+# define TUNABLE_SET_WITH_BOUNDS_FULL(__top, __ns, __id,__val, __min, __max)  \
 ({                                                                           \
   __tunable_set_val (TUNABLE_ENUM_NAME (__top, __ns, __id),                  \
-                    & (__type) {__val},  & (__type) {__min},                 \
-                    & (__type) {__max});                                     \
+                    & (tunable_val_t) {.numval = __val},                     \
+                    & (tunable_num_t) {__min},                               \
+                    & (tunable_num_t) {__max});                              \
 })
 
 /* Namespace sanity for callback functions.  Use this macro to keep the
@@ -114,6 +115,24 @@ rtld_hidden_proto (__tunable_set_val)
 /* The default value for TUNABLES_FRONTEND.  */
 # define TUNABLES_FRONTEND_yes TUNABLES_FRONTEND_valstring
 
+static __always_inline bool
+tunable_val_lt (tunable_num_t lhs, tunable_num_t rhs, bool unsigned_cmp)
+{
+  if (unsigned_cmp)
+    return (uintmax_t) lhs < (uintmax_t) rhs;
+  else
+    return lhs < rhs;
+}
+
+static __always_inline bool
+tunable_val_gt (tunable_num_t lhs, tunable_num_t rhs, bool unsigned_cmp)
+{
+  if (unsigned_cmp)
+    return (uintmax_t) lhs > (uintmax_t) rhs;
+  else
+    return lhs > rhs;
+}
+
 /* Compare two name strings, bounded by the name hardcoded in glibc.  */
 static __always_inline bool
 tunable_is_name (const char *orig, const char *envname)
index 3cf0ad83eca89200fd4eefe49b5b32ae1d3b6b1d..8ddd4a23142a941b95900a31b0610e4723c94d02 100644 (file)
@@ -64,6 +64,7 @@ glibc {
       type: INT_32
       env_alias: MALLOC_MMAP_MAX_
       security_level: SXID_IGNORE
+      minval: 0
     }
     arena_max {
       type: SIZE_T
@@ -109,22 +110,27 @@ glibc {
     skip_lock_busy {
       type: INT_32
       default: 3
+      minval: 0
     }
     skip_lock_internal_abort {
       type: INT_32
       default: 3
+      minval: 0
     }
     skip_lock_after_retries {
       type: INT_32
       default: 3
+      minval: 0
     }
     tries {
       type: INT_32
       default: 3
+      minval: 0
     }
     skip_trylock_internal_abort {
       type: INT_32
       default: 3
+      minval: 0
     }
   }
 
index 6e26818bd753a09f30e513f28be672a2db86e084..5ad3a72559c0fc280c0cccb541b53b8b571cd37c 100644 (file)
@@ -261,6 +261,7 @@ setting environment variables (which would be inherited by subprocesses).\n\
   --list-tunables       list all tunables with minimum and maximum values\n"
 #endif
 "\
+  --list-diagnostics    list diagnostics information\n\
   --help                display this help and exit\n\
   --version             output version information and exit\n\
 \n\
index 596b6ac3d99d7d8e1b51374893fe1233f7b0d70a..489e58c551890023d2d13a0167db43c71fcec05e 100644 (file)
@@ -141,6 +141,7 @@ static void dl_main_state_init (struct dl_main_state *state);
 /* Process all environments variables the dynamic linker must recognize.
    Since all of them start with `LD_' we are a bit smarter while finding
    all the entries.  */
+extern char **_environ attribute_hidden;
 static void process_envvars (struct dl_main_state *state);
 
 #ifdef DL_ARGV_NOT_RELRO
@@ -379,7 +380,6 @@ struct rtld_global_ro _rtld_global_ro attribute_relro =
 extern struct rtld_global_ro _rtld_local_ro
     __attribute__ ((alias ("_rtld_global_ro"), visibility ("hidden")));
 
-
 static void dl_main (const ElfW(Phdr) *phdr, ElfW(Word) phnum,
                     ElfW(Addr) *user_entry, ElfW(auxv_t) *auxv);
 
@@ -1287,6 +1287,14 @@ dl_main (const ElfW(Phdr) *phdr,
            ++_dl_argv;
          }
 #endif
+       else if (! strcmp (_dl_argv[1], "--list-diagnostics"))
+         {
+           state.mode = rtld_mode_list_diagnostics;
+
+           ++_dl_skip_args;
+           --_dl_argc;
+           ++_dl_argv;
+         }
        else if (strcmp (_dl_argv[1], "--help") == 0)
          {
            state.mode = rtld_mode_help;
@@ -1315,6 +1323,9 @@ dl_main (const ElfW(Phdr) *phdr,
        }
 #endif
 
+      if (state.mode == rtld_mode_list_diagnostics)
+       _dl_print_diagnostics (_environ);
+
       /* If we have no further argument the program was called incorrectly.
         Grant the user some education.  */
       if (_dl_argc < 2)
@@ -2649,12 +2660,6 @@ a filename can be specified using the LD_DEBUG_OUTPUT environment variable.\n");
     }
 }
 \f
-/* Process all environments variables the dynamic linker must recognize.
-   Since all of them start with `LD_' we are a bit smarter while finding
-   all the entries.  */
-extern char **_environ attribute_hidden;
-
-
 static void
 process_envvars (struct dl_main_state *state)
 {
diff --git a/elf/tst-dlmopen-dlerror-mod.c b/elf/tst-dlmopen-dlerror-mod.c
new file mode 100644 (file)
index 0000000..7e95dcd
--- /dev/null
@@ -0,0 +1,41 @@
+/* Check that dlfcn errors are reported properly after dlmopen.  Test module.
+   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
+   <http://www.gnu.org/licenses/>.  */
+
+#include <dlfcn.h>
+#include <stddef.h>
+#include <support/check.h>
+
+/* Note: This object is not linked into the main program, so we cannot
+   use delayed test failure reporting via TEST_VERIFY etc., and have
+   to use FAIL_EXIT1 (or something else that calls exit).  */
+
+void
+call_dlsym (void)
+{
+  void *ptr = dlsym (NULL, "does not exist");
+  if (ptr != NULL)
+    FAIL_EXIT1 ("dlsym did not fail as expected");
+}
+
+void
+call_dlopen (void)
+{
+  void *handle = dlopen ("tst-dlmopen-dlerror does not exist", RTLD_NOW);
+  if (handle != NULL)
+    FAIL_EXIT1 ("dlopen did not fail as expected");
+}
diff --git a/elf/tst-dlmopen-dlerror.c b/elf/tst-dlmopen-dlerror.c
new file mode 100644 (file)
index 0000000..e864d2f
--- /dev/null
@@ -0,0 +1,37 @@
+/* Check that dlfcn errors are reported properly after dlmopen.
+   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
+   <http://www.gnu.org/licenses/>.  */
+
+#include <stddef.h>
+#include <support/check.h>
+#include <support/xdlfcn.h>
+
+static int
+do_test (void)
+{
+  void *handle = xdlmopen (LM_ID_NEWLM, "tst-dlmopen-dlerror-mod.so",
+                           RTLD_NOW);
+  void (*call_dlsym) (void) = xdlsym (handle, "call_dlsym");
+  void (*call_dlopen) (void) = xdlsym (handle, "call_dlopen");
+
+  call_dlsym ();
+  call_dlopen ();
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/elf/tst-dlmopen-gethostbyname-mod.c b/elf/tst-dlmopen-gethostbyname-mod.c
new file mode 100644 (file)
index 0000000..9a68ea5
--- /dev/null
@@ -0,0 +1,29 @@
+/* Exercise dlerror_run in elf/dl-libc.c after dlmopen, via NSS.  Helper module.
+   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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <netdb.h>
+#include <nss.h>
+
+void
+call_gethostbyname (void)
+{
+  __nss_configure_lookup ("hosts", "files");
+  /* This should not terminate the process due to a missing
+     _nss_files_getcanonname_r symbol.  */
+  gethostbyname ("localhost");
+}
diff --git a/elf/tst-dlmopen-gethostbyname.c b/elf/tst-dlmopen-gethostbyname.c
new file mode 100644 (file)
index 0000000..12deb29
--- /dev/null
@@ -0,0 +1,31 @@
+/* Exercise dlerror_run in elf/dl-libc.c after dlmopen, via NSS (bug 27646).
+   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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <support/xdlfcn.h>
+
+static int
+do_test (void)
+{
+  void *handle = xdlmopen (LM_ID_NEWLM, "tst-dlmopen-gethostbyname-mod.so",
+                           RTLD_NOW);
+  void (*call_gethostbyname) (void) = xdlsym (handle, "call_gethostbyname");
+  call_gethostbyname ();
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/elf/tst-dst-static.c b/elf/tst-dst-static.c
new file mode 100644 (file)
index 0000000..56eb371
--- /dev/null
@@ -0,0 +1,32 @@
+/* Test DST expansion for static binaries doesn't carsh.  Bug 23462.
+   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
+   <https://www.gnu.org/licenses/>.  */
+
+/* The purpose of this test is to exercise the code in elf/dl-loac.c
+   (_dl_init_paths) or thereabout and ensure that static binaries
+   don't crash when expanding DSTs.
+
+   If the dynamic loader code linked into the static binary cannot
+   handle expanding the DSTs e.g. null-deref on an incomplete link
+   map, then it will crash before reaching main, so the test harness
+   is unnecessary.  */
+
+int
+main (void)
+{
+  return 0;
+}
index 50bef8683df0e9c1199ef736fa537e76e9c8ab16..05619c9adc8b269800b7eaddee99f4f50821cb54 100644 (file)
 #include "config.h"
 #undef _LIBC
 
-#define test_parent test_parent_tunables
-#define test_child test_child_tunables
-
-static int test_child_tunables (void);
-static int test_parent_tunables (void);
-
-#include "tst-env-setuid.c"
-
-#define CHILD_VALSTRING_VALUE "glibc.malloc.mmap_threshold=4096"
-#define PARENT_VALSTRING_VALUE \
-  "glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096"
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <intprops.h>
+#include <array_length.h>
+
+#include <support/check.h>
+#include <support/support.h>
+#include <support/test-driver.h>
+#include <support/capture_subprocess.h>
+
+const char *teststrings[] =
+{
+  "glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096",
+  "glibc.malloc.check=2:glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096",
+  "glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096:glibc.malloc.check=2",
+  "glibc.malloc.perturb=0x800",
+  "glibc.malloc.perturb=0x800:glibc.malloc.mmap_threshold=4096",
+  "glibc.malloc.perturb=0x800:not_valid.malloc.check=2:glibc.malloc.mmap_threshold=4096",
+  "glibc.not_valid.check=2:glibc.malloc.mmap_threshold=4096",
+  "not_valid.malloc.check=2:glibc.malloc.mmap_threshold=4096",
+  "glibc.malloc.garbage=2:glibc.maoc.mmap_threshold=4096:glibc.malloc.check=2",
+  "glibc.malloc.check=4:glibc.malloc.garbage=2:glibc.maoc.mmap_threshold=4096",
+  ":glibc.malloc.garbage=2:glibc.malloc.check=1",
+  "glibc.malloc.check=1:glibc.malloc.check=2",
+  "not_valid.malloc.check=2",
+  "glibc.not_valid.check=2",
+};
+
+const char *resultstrings[] =
+{
+  "glibc.malloc.mmap_threshold=4096",
+  "glibc.malloc.mmap_threshold=4096",
+  "glibc.malloc.mmap_threshold=4096",
+  "glibc.malloc.perturb=0x800",
+  "glibc.malloc.perturb=0x800:glibc.malloc.mmap_threshold=4096",
+  "glibc.malloc.perturb=0x800:glibc.malloc.mmap_threshold=4096",
+  "glibc.malloc.mmap_threshold=4096",
+  "glibc.malloc.mmap_threshold=4096",
+  "",
+  "",
+  "",
+  "",
+  "",
+  "",
+};
 
 static int
-test_child_tunables (void)
+test_child (int off)
 {
   const char *val = getenv ("GLIBC_TUNABLES");
 
 #if HAVE_TUNABLES
-  if (val != NULL && strcmp (val, CHILD_VALSTRING_VALUE) == 0)
+  if (val != NULL && strcmp (val, resultstrings[off]) == 0)
     return 0;
 
   if (val != NULL)
-    printf ("Unexpected GLIBC_TUNABLES VALUE %s\n", val);
+    printf ("[%d] Unexpected GLIBC_TUNABLES VALUE %s\n", off, val);
 
   return 1;
 #else
   if (val != NULL)
     {
-      printf ("GLIBC_TUNABLES not cleared\n");
+      printf ("[%d] GLIBC_TUNABLES not cleared\n", off);
       return 1;
     }
   return 0;
@@ -61,15 +102,48 @@ test_child_tunables (void)
 }
 
 static int
-test_parent_tunables (void)
+do_test (int argc, char **argv)
 {
-  const char *val = getenv ("GLIBC_TUNABLES");
+  /* Setgid child process.  */
+  if (argc == 2)
+    {
+      if (getgid () == getegid ())
+       /* This can happen if the file system is mounted nosuid.  */
+       FAIL_UNSUPPORTED ("SGID failed: GID and EGID match (%jd)\n",
+                         (intmax_t) getgid ());
 
-  if (val != NULL && strcmp (val, PARENT_VALSTRING_VALUE) == 0)
-    return 0;
+      int ret = test_child (atoi (argv[1]));
 
-  if (val != NULL)
-    printf ("Unexpected GLIBC_TUNABLES VALUE %s\n", val);
+      if (ret != 0)
+       exit (1);
 
-  return 1;
+      exit (EXIT_SUCCESS);
+    }
+  else
+    {
+      int ret = 0;
+
+      /* Spawn tests.  */
+      for (int i = 0; i < array_length (teststrings); i++)
+       {
+         char buf[INT_BUFSIZE_BOUND (int)];
+
+         printf ("Spawned test for %s (%d)\n", teststrings[i], i);
+         snprintf (buf, sizeof (buf), "%d\n", i);
+         if (setenv ("GLIBC_TUNABLES", teststrings[i], 1) != 0)
+           exit (1);
+
+         int status = support_capture_subprogram_self_sgid (buf);
+
+         /* Bail out early if unsupported.  */
+         if (WEXITSTATUS (status) == EXIT_UNSUPPORTED)
+           return EXIT_UNSUPPORTED;
+
+         ret |= status;
+       }
+      return ret;
+    }
 }
+
+#define TEST_FUNCTION_ARGV do_test
+#include <support/test-driver.c>
index 60ae0ca38050a87158fe092c93d6df52aff95ca0..49b5e319e27c240455ec84f310567edfce6d58c0 100644 (file)
 #include <sys/wait.h>
 #include <unistd.h>
 
+#include <support/check.h>
 #include <support/support.h>
 #include <support/test-driver.h>
+#include <support/capture_subprocess.h>
 
 static char SETGID_CHILD[] = "setgid-child";
-#define CHILD_STATUS 42
-
-/* Return a GID which is not our current GID, but is present in the
-   supplementary group list.  */
-static gid_t
-choose_gid (void)
-{
-  const int count = 64;
-  gid_t groups[count];
-  int ret = getgroups (count, groups);
-  if (ret < 0)
-    {
-      printf ("getgroups: %m\n");
-      exit (1);
-    }
-  gid_t current = getgid ();
-  for (int i = 0; i < ret; ++i)
-    {
-      if (groups[i] != current)
-       return groups[i];
-    }
-  return 0;
-}
-
-/* Spawn and execute a program and verify that it returns the CHILD_STATUS.  */
-static pid_t
-do_execve (char **args)
-{
-  pid_t kid = vfork ();
-
-  if (kid < 0)
-    {
-      printf ("vfork: %m\n");
-      return -1;
-    }
-
-  if (kid == 0)
-    {
-      /* Child process.  */
-      execve (args[0], args, environ);
-      _exit (-errno);
-    }
-
-  if (kid < 0)
-    return 1;
-
-  int status;
-
-  if (waitpid (kid, &status, 0) < 0)
-    {
-      printf ("waitpid: %m\n");
-      return 1;
-    }
-
-  if (WEXITSTATUS (status) == EXIT_UNSUPPORTED)
-    return EXIT_UNSUPPORTED;
-
-  if (!WIFEXITED (status) || WEXITSTATUS (status) != CHILD_STATUS)
-    {
-      printf ("Unexpected exit status %d from child process\n",
-             WEXITSTATUS (status));
-      return 1;
-    }
-  return 0;
-}
-
-/* Copies the executable into a restricted directory, so that we can
-   safely make it SGID with the TARGET group ID.  Then runs the
-   executable.  */
-static int
-run_executable_sgid (gid_t target)
-{
-  char *dirname = xasprintf ("%s/tst-tunables-setuid.%jd",
-                            test_dir, (intmax_t) getpid ());
-  char *execname = xasprintf ("%s/bin", dirname);
-  int infd = -1;
-  int outfd = -1;
-  int ret = 0;
-  if (mkdir (dirname, 0700) < 0)
-    {
-      printf ("mkdir: %m\n");
-      goto err;
-    }
-  infd = open ("/proc/self/exe", O_RDONLY);
-  if (infd < 0)
-    {
-      printf ("open (/proc/self/exe): %m\n");
-      goto err;
-    }
-  outfd = open (execname, O_WRONLY | O_CREAT | O_EXCL, 0700);
-  if (outfd < 0)
-    {
-      printf ("open (%s): %m\n", execname);
-      goto err;
-    }
-  char buf[4096];
-  for (;;)
-    {
-      ssize_t rdcount = read (infd, buf, sizeof (buf));
-      if (rdcount < 0)
-       {
-         printf ("read: %m\n");
-         goto err;
-       }
-      if (rdcount == 0)
-       break;
-      char *p = buf;
-      char *end = buf + rdcount;
-      while (p != end)
-       {
-         ssize_t wrcount = write (outfd, buf, end - p);
-         if (wrcount == 0)
-           errno = ENOSPC;
-         if (wrcount <= 0)
-           {
-             printf ("write: %m\n");
-             goto err;
-           }
-         p += wrcount;
-       }
-    }
-  if (fchown (outfd, getuid (), target) < 0)
-    {
-      printf ("fchown (%s): %m\n", execname);
-      goto err;
-    }
-  if (fchmod (outfd, 02750) < 0)
-    {
-      printf ("fchmod (%s): %m\n", execname);
-      goto err;
-    }
-  if (close (outfd) < 0)
-    {
-      printf ("close (outfd): %m\n");
-      goto err;
-    }
-  if (close (infd) < 0)
-    {
-      printf ("close (infd): %m\n");
-      goto err;
-    }
-
-  char *args[] = {execname, SETGID_CHILD, NULL};
-
-  ret = do_execve (args);
-
-err:
-  if (outfd >= 0)
-    close (outfd);
-  if (infd >= 0)
-    close (infd);
-  if (execname)
-    {
-      unlink (execname);
-      free (execname);
-    }
-  if (dirname)
-    {
-      rmdir (dirname);
-      free (dirname);
-    }
-  return ret;
-}
 
 #ifndef test_child
 static int
@@ -256,40 +95,32 @@ do_test (int argc, char **argv)
   if (argc == 2 && strcmp (argv[1], SETGID_CHILD) == 0)
     {
       if (getgid () == getegid ())
-       {
-         /* This can happen if the file system is mounted nosuid.  */
-         fprintf (stderr, "SGID failed: GID and EGID match (%jd)\n",
-                  (intmax_t) getgid ());
-         exit (EXIT_UNSUPPORTED);
-       }
+       /* This can happen if the file system is mounted nosuid.  */
+       FAIL_UNSUPPORTED ("SGID failed: GID and EGID match (%jd)\n",
+                         (intmax_t) getgid ());
 
       int ret = test_child ();
 
       if (ret != 0)
        exit (1);
 
-      exit (CHILD_STATUS);
+      exit (EXIT_SUCCESS);
     }
   else
     {
       if (test_parent () != 0)
        exit (1);
 
-      /* Try running a setgid program.  */
-      gid_t target = choose_gid ();
-      if (target == 0)
-       {
-         fprintf (stderr,
-                  "Could not find a suitable GID for user %jd, skipping test\n",
-                  (intmax_t) getuid ());
-         exit (0);
-       }
+      int status = support_capture_subprogram_self_sgid (SETGID_CHILD);
 
-      return run_executable_sgid (target);
-    }
+      if (WEXITSTATUS (status) == EXIT_UNSUPPORTED)
+       return EXIT_UNSUPPORTED;
+
+      if (!WIFEXITED (status))
+       FAIL_EXIT1 ("Unexpected exit status %d from child process\n", status);
 
-  /* Something went wrong and our argv was corrupted.  */
-  _exit (1);
+      return 0;
+    }
 }
 
 #define TEST_FUNCTION_ARGV do_test
index 4f3f7ee4e30a2b423ef9aca9edd485ad090328c2..9f66c528855fb21db9f6d646f06a80036f040c08 100644 (file)
@@ -1,7 +1,7 @@
 glibc.malloc.arena_max: 0x0 (min: 0x1, max: 0x[f]+)
 glibc.malloc.arena_test: 0x0 (min: 0x1, max: 0x[f]+)
 glibc.malloc.check: 0 (min: 0, max: 3)
-glibc.malloc.mmap_max: 0 (min: -2147483648, max: 2147483647)
+glibc.malloc.mmap_max: 0 (min: 0, max: 2147483647)
 glibc.malloc.mmap_threshold: 0x0 (min: 0x0, max: 0x[f]+)
 glibc.malloc.mxfast: 0x0 (min: 0x0, max: 0x[f]+)
 glibc.malloc.perturb: 0 (min: 0, max: 255)
index 55c527a5f7ac63649635fb671ae4cd7ed703b9fa..2612d25579453f55c7a4d164ce0d88903598e278 100644 (file)
@@ -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
@@ -324,6 +325,8 @@ $(objpfx)bug-iconv12.out: $(objpfx)gconv-modules \
                          $(addprefix $(objpfx),$(modules.so))
 $(objpfx)bug-iconv14.out: $(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 $(objpfx)gconv-modules \
                         $(addprefix $(objpfx),$(modules.so)) \
diff --git a/iconvdata/bug-iconv15.c b/iconvdata/bug-iconv15.c
new file mode 100644 (file)
index 0000000..cc04bd0
--- /dev/null
@@ -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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <stddef.h>
+#include <iconv.h>
+#include <support/check.h>
+
+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 <support/test-driver.c>
index c8ba88cdc9fe9200c1f0cc91337371892dcff5ac..5fc0c0f7397935fe079e41b49cb6911c0ce675d7 100644 (file)
@@ -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 <drepper@cygnus.com>, 1998,
    and Bruno Haible <bruno@clisp.org>, 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                                                                   \
        {                                                                     \
index ea126ae70cd9a0aa7d65ac79225df9d260164a97..c83e550b03fa9a2d6716b22fc2396100739be9c3 100644 (file)
 # define IN_MODULE (-1)
 #endif
 
+/* Use symbol_version_reference to specify the version a symbol
+   reference should link to.  Use symbol_version or
+   default_symbol_version for the definition of a versioned symbol.
+   The difference is that the latter is a no-op in non-shared
+   builds.  */
+#ifdef __ASSEMBLER__
+# define symbol_version_reference(real, name, version) \
+     .symver real, name##@##version
+#else  /* !__ASSEMBLER__ */
+# define symbol_version_reference(real, name, version) \
+  __asm__ (".symver " #real "," #name "@" #version)
+#endif
+
 #ifndef _ISOMAC
 
 /* This is defined for the compilation of all C library code.  features.h
@@ -396,19 +409,6 @@ for linking")
    past the last element in SET.  */
 #define symbol_set_end_p(set, ptr) ((ptr) >= (void *const *) &__stop_##set)
 
-/* Use symbol_version_reference to specify the version a symbol
-   reference should link to.  Use symbol_version or
-   default_symbol_version for the definition of a versioned symbol.
-   The difference is that the latter is a no-op in non-shared
-   builds.  */
-#ifdef __ASSEMBLER__
-# define symbol_version_reference(real, name, version) \
-     .symver real, name##@##version
-#else  /* !__ASSEMBLER__ */
-# define symbol_version_reference(real, name, version) \
-  __asm__ (".symver " #real "," #name "@" #version)
-#endif
-
 #ifdef SHARED
 # define symbol_version(real, name, version) \
   symbol_version_reference(real, name, version)
index bdbee999806930f4788e2af67c5a494239dccf12..152afd9fc7426d8bcb1db6219556f139d20134b4 100644 (file)
@@ -1 +1,13 @@
 #include <socket/sys/un.h>
+
+#ifndef _ISOMAC
+
+/* Set ADDR->sun_family to AF_UNIX and ADDR->sun_path to PATHNAME.
+   Return 0 on success or -1 on failure (due to overlong PATHNAME).
+   The caller should always use sizeof (struct sockaddr_un) as the
+   socket address length, disregaring the length of PATHNAME.
+   Only concrete (non-abstract) pathnames are supported.  */
+int __sockaddr_un_set (struct sockaddr_un *addr, const char *pathname)
+  attribute_hidden;
+
+#endif /* _ISOMAC */
index caf2af5e74ed6179e182e0ab7ce2012b2c421a10..e0636132a6ee3fe97d6bcfaa29b6e5ff48885d59 100644 (file)
@@ -502,6 +502,11 @@ time_now (void)
   __clock_gettime (TIME_CLOCK_GETTIME_CLOCKID, &ts);
   return ts.tv_sec;
 }
+
+#define NSEC_PER_SEC    1000000000L  /* Nanoseconds per second.  */
+#define USEC_PER_SEC    1000000L     /* Microseconds per second.  */
+#define NSEC_PER_USEC   1000L        /* Nanoseconds per microsecond.  */
+
 #endif
 
 #endif
index b7bebe923f84e878ececfd482f65f0e1a9e5e8bf..d145d88f4e3faabffd3af7ae256147c16c9238d0 100644 (file)
@@ -68,7 +68,7 @@ tests         := test-utime test-stat test-stat2 test-lfs tst-getcwd \
                   tst-fts tst-fts-lfs tst-open-tmpfile \
                   tst-copy_file_range tst-getcwd-abspath tst-lockf \
                   tst-ftw-lnk tst-file_change_detection tst-lchmod \
-                  tst-ftw-bz26353
+                  tst-ftw-bz26353 tst-stat tst-stat-lfs
 
 # Likewise for statx, but we do not need static linking here.
 tests-internal += tst-statx
index dc117361ffe7064be7c6746465388803e203adcf..17f31bf3b3a65a124b7a2e2e983acbc1e4583e1b 100644 (file)
    <https://www.gnu.org/licenses/>.  */
 
 #include <sys/stat.h>
+#include <errno.h>
 
 int
 __fstat (int fd, struct stat *buf)
 {
+  if (fd < 0)
+    {
+      __set_errno (EBADF);
+      return -1;
+    }
   return __fstatat (fd, "", buf, AT_EMPTY_PATH);
 }
 
index addf3797754f16b3b679a2c95a93f615d1817c1e..618170695cd56eeceaad3fc2e15415377db6a9a3 100644 (file)
    <https://www.gnu.org/licenses/>.  */
 
 #include <sys/stat.h>
+#include <errno.h>
 
 int
 __fstat64 (int fd, struct stat64 *buf)
 {
+  if (fd < 0)
+    {
+      __set_errno (EBADF);
+      return -1;
+    }
   return __fstatat64 (fd, "", buf, AT_EMPTY_PATH);
 }
 hidden_def (__fstat64)
diff --git a/io/tst-stat-lfs.c b/io/tst-stat-lfs.c
new file mode 100644 (file)
index 0000000..b53f460
--- /dev/null
@@ -0,0 +1,2 @@
+#define _FILE_OFFSET_BITS 64
+#include "tst-stat.c"
diff --git a/io/tst-stat.c b/io/tst-stat.c
new file mode 100644 (file)
index 0000000..445ac41
--- /dev/null
@@ -0,0 +1,102 @@
+/* Basic tests for stat, lstat, fstat, and fstatat.
+   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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <array_length.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <support/check.h>
+#include <support/support.h>
+#include <support/temp_file.h>
+#include <support/xunistd.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+#include <unistd.h>
+
+static void
+stat_check (int fd, const char *path, struct stat *st)
+{
+  TEST_COMPARE (stat (path, st), 0);
+}
+
+static void
+lstat_check (int fd, const char *path, struct stat *st)
+{
+  TEST_COMPARE (lstat (path, st), 0);
+}
+
+static void
+fstat_check (int fd, const char *path, struct stat *st)
+{
+  /* Test for invalid fstat input (BZ #27559).  */
+  TEST_COMPARE (fstat (AT_FDCWD, st), -1);
+  TEST_COMPARE (errno, EBADF);
+
+  TEST_COMPARE (fstat (fd, st), 0);
+}
+
+static void
+fstatat_check (int fd, const char *path, struct stat *st)
+{
+  TEST_COMPARE (fstatat (fd, "", st, 0), -1);
+  TEST_COMPARE (errno, ENOENT);
+
+  TEST_COMPARE (fstatat (fd, path, st, 0), 0);
+}
+
+typedef void (*test_t)(int, const char *path, struct stat *);
+
+static int
+do_test (void)
+{
+  char *path;
+  int fd = create_temp_file ("tst-fstat.", &path);
+  TEST_VERIFY_EXIT (fd >= 0);
+  support_write_file_string (path, "abc");
+
+  struct statx stx;
+  TEST_COMPARE (statx (fd, path, 0, STATX_BASIC_STATS, &stx), 0);
+
+  test_t tests[] = { stat_check, lstat_check, fstat_check, fstatat_check };
+
+  for (int i = 0; i < array_length (tests); i++)
+    {
+      struct stat st;
+      tests[i](fd, path, &st);
+
+      TEST_COMPARE (stx.stx_dev_major, major (st.st_dev));
+      TEST_COMPARE (stx.stx_dev_minor, minor (st.st_dev));
+      TEST_COMPARE (stx.stx_ino, st.st_ino);
+      TEST_COMPARE (stx.stx_mode, st.st_mode);
+      TEST_COMPARE (stx.stx_nlink, st.st_nlink);
+      TEST_COMPARE (stx.stx_uid, st.st_uid);
+      TEST_COMPARE (stx.stx_gid, st.st_gid);
+      TEST_COMPARE (stx.stx_rdev_major, major (st.st_rdev));
+      TEST_COMPARE (stx.stx_rdev_minor, minor (st.st_rdev));
+      TEST_COMPARE (stx.stx_blksize, st.st_blksize);
+      TEST_COMPARE (stx.stx_blocks, st.st_blocks);
+
+      TEST_COMPARE (stx.stx_ctime.tv_sec, st.st_ctim.tv_sec);
+      TEST_COMPARE (stx.stx_ctime.tv_nsec, st.st_ctim.tv_nsec);
+      TEST_COMPARE (stx.stx_mtime.tv_sec, st.st_mtim.tv_sec);
+      TEST_COMPARE (stx.stx_mtime.tv_nsec, st.st_mtim.tv_nsec);
+    }
+
+  return 0;
+}
+
+#include <support/test-driver.c>
index 1f4bbd8edf8b97701b779f183475565c7d0a6762..8f8f12c2768124055050cf4ec8cb8163968c4c7b 100644 (file)
@@ -3446,7 +3446,9 @@ __libc_realloc (void *oldmem, size_t bytes)
       newp = __libc_malloc (bytes);
       if (newp != NULL)
         {
-          memcpy (newp, oldmem, oldsize - SIZE_SZ);
+         size_t sz = CHUNK_AVAILABLE_SIZE (oldp) - CHUNK_HDR_SZ;
+         memcpy (newp, oldmem, sz);
+         (void) TAG_REGION (chunk2rawmem (oldp), sz);
           _int_free (ar_ptr, oldp, 0);
         }
     }
index b08d7c68ab25d5a8a29a8d57b5e6d9728cfd4ad6..05ad034bafdc4ec73d141f024085b6487ce7f236 100644 (file)
@@ -88,7 +88,7 @@ tests := tst-dirname tst-tsearch tst-fdset tst-mntent tst-hsearch \
         tst-preadvwritev tst-preadvwritev64 tst-makedev tst-empty \
         tst-preadvwritev2 tst-preadvwritev64v2 tst-warn-wide \
         tst-ldbl-warn tst-ldbl-error tst-dbl-efgcvt tst-ldbl-efgcvt \
-        tst-mntent-autofs tst-syscalls tst-mntent-escape
+        tst-mntent-autofs tst-syscalls tst-mntent-escape tst-select
 
 # Tests which need libdl.
 ifeq (yes,$(build-shared))
diff --git a/misc/tst-select.c b/misc/tst-select.c
new file mode 100644 (file)
index 0000000..52aa266
--- /dev/null
@@ -0,0 +1,143 @@
+/* Test for select timeout.
+   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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <support/capture_subprocess.h>
+#include <support/check.h>
+#include <support/support.h>
+#include <support/timespec.h>
+#include <support/xunistd.h>
+#include <support/xtime.h>
+#include <support/xsignal.h>
+
+struct child_args
+{
+  int fds[2][2];
+  struct timeval tmo;
+};
+
+static void
+alarm_handler (int signum)
+{
+  /* Do nothing.  */
+}
+
+static void
+do_test_child (void *clousure)
+{
+  struct child_args *args = (struct child_args *) clousure;
+
+  close (args->fds[0][1]);
+  close (args->fds[1][0]);
+
+  fd_set rfds;
+  FD_ZERO (&rfds);
+  FD_SET (args->fds[0][0], &rfds);
+
+  struct timespec ts = xclock_now (CLOCK_REALTIME);
+  ts = timespec_add (ts, (struct timespec) { args->tmo.tv_sec, 0 });
+
+  int r = select (args->fds[0][0] + 1, &rfds, NULL, NULL, &args->tmo);
+  TEST_COMPARE (r, 0);
+
+  if (support_select_modifies_timeout ())
+    {
+      TEST_COMPARE (args->tmo.tv_sec, 0);
+      TEST_COMPARE (args->tmo.tv_usec, 0);
+    }
+
+  TEST_TIMESPEC_NOW_OR_AFTER (CLOCK_REALTIME, ts);
+
+  xwrite (args->fds[1][1], "foo", 3);
+}
+
+static void
+do_test_child_alarm (void *clousure)
+{
+  struct sigaction act = { .sa_handler = alarm_handler };
+  xsigaction (SIGALRM, &act, NULL);
+  alarm (1);
+
+  struct timeval tv = { .tv_sec = 10, .tv_usec = 0 };
+  int r = select (0, NULL, NULL, NULL, &tv);
+  TEST_COMPARE (r, -1);
+  TEST_COMPARE (errno, EINTR);
+
+  if (support_select_modifies_timeout ())
+    TEST_VERIFY (tv.tv_sec < 10);
+}
+
+static int
+do_test (void)
+{
+  struct child_args args;
+
+  xpipe (args.fds[0]);
+  xpipe (args.fds[1]);
+
+  /* The child select should timeout and write on its pipe end.  */
+  args.tmo = (struct timeval) { .tv_sec = 0, .tv_usec = 250000 };
+  {
+    struct support_capture_subprocess result;
+    result = support_capture_subprocess (do_test_child, &args);
+    support_capture_subprocess_check (&result, "tst-select-child", 0,
+                                     sc_allow_none);
+  }
+
+  if (support_select_normalizes_timeout ())
+    {
+      /* This is handled as 1 second instead of failing with EINVAL.  */
+      args.tmo = (struct timeval) { .tv_sec = 0, .tv_usec = 1000000 };
+      struct support_capture_subprocess result;
+      result = support_capture_subprocess (do_test_child, &args);
+      support_capture_subprocess_check (&result, "tst-select-child", 0,
+                                       sc_allow_none);
+    }
+
+  /* Same as before, but simulating polling.  */
+  args.tmo = (struct timeval) { .tv_sec = 0, .tv_usec = 0 };
+  {
+    struct support_capture_subprocess result;
+    result = support_capture_subprocess (do_test_child, &args);
+    support_capture_subprocess_check (&result, "tst-select-child", 0,
+                                     sc_allow_none);
+  }
+
+  xclose (args.fds[0][0]);
+  xclose (args.fds[1][1]);
+
+  {
+    struct support_capture_subprocess result;
+    result = support_capture_subprocess (do_test_child_alarm, NULL);
+    support_capture_subprocess_check (&result, "tst-select-child", 0,
+                                     sc_allow_none);
+  }
+
+  {
+    fd_set rfds;
+    FD_ZERO (&rfds);
+    FD_SET (args.fds[1][0], &rfds);
+
+    int r = select (args.fds[1][0] + 1, &rfds, NULL, NULL, &args.tmo);
+    TEST_COMPARE (r, 1);
+  }
+
+  return 0;
+}
+
+#include <support/test-driver.c>
index 0282e07390e8a249febe3a5bb0d5e32d9b659b2d..a1a8ef254b3c3b17e868bb4460ac9975dd66b769 100644 (file)
@@ -294,7 +294,8 @@ tests = tst-attr2 tst-attr3 tst-default-attr \
        tst-thread-affinity-sched \
        tst-pthread-defaultattr-free \
        tst-pthread-attr-sigmask \
-       tst-pthread-timedlock-lockloop
+       tst-pthread-timedlock-lockloop \
+       tst-pthread-gdb-attach tst-pthread-gdb-attach-static
 
 tests-container =  tst-pthread-getattr
 
@@ -314,10 +315,6 @@ xtests += tst-eintr1
 
 test-srcs = tst-oddstacklimit
 
-# Test expected to fail on most targets (except x86_64) due to bug
-# 18435 - pthread_once hangs when init routine throws an exception.
-test-xfail-tst-once5 = yes
-
 gen-as-const-headers = unwindbuf.sym \
                       pthread-pi-defines.sym
 
@@ -344,6 +341,22 @@ CPPFLAGS-test-cond-printers.c := $(CFLAGS-printers-tests)
 CPPFLAGS-test-rwlockattr-printers.c := $(CFLAGS-printers-tests)
 CPPFLAGS-test-rwlock-printers.c := $(CFLAGS-printers-tests)
 
+# Reuse the CFLAGS setting for the GDB attaching test.  It needs
+# debugging information.
+CFLAGS-tst-pthread-gdb-attach.c := $(CFLAGS-printers-tests)
+CPPFLAGS-tst-pthread-gdb-attach.c := $(CFLAGS-printers-tests)
+ifeq ($(build-shared)$(build-hardcoded-path-in-tests),yesno)
+CPPFLAGS-tst-pthread-gdb-attach.c += -DDO_ADD_SYMBOL_FILE=1
+else
+CPPFLAGS-tst-pthread-gdb-attach.c += -DDO_ADD_SYMBOL_FILE=0
+endif
+CFLAGS-tst-pthread-gdb-attach-static.c := $(CFLAGS-printers-tests)
+CPPFLAGS-tst-pthread-gdb-attach-static.c := \
+  $(CFLAGS-printers-tests) -DDO_ADD_SYMBOL_FILE=0
+# As of version 9.2, GDB cannot attach properly to PIE programs that
+# were launched with an explicit ld.so invocation.
+tst-pthread-gdb-attach-no-pie = yes
+
 ifeq ($(build-shared),yes)
 tests-printers-libs := $(shared-thread-library)
 else
@@ -415,7 +428,8 @@ link-libc-static := $(common-objpfx)libc.a $(static-gnulib) \
 tests-static += tst-stackguard1-static \
                tst-cancel24-static \
                tst-mutex8-static tst-mutexpi8-static tst-sem11-static \
-               tst-sem12-static tst-cond11-static
+               tst-sem12-static tst-cond11-static \
+               tst-pthread-gdb-attach-static
 
 tests += tst-cancel24-static
 
index e5efa2e62d3d23d8f072182ece879288671ed3f6..79be1bc70f4e9db8c2ea793e7c44b6ae82c33fe0 100644 (file)
@@ -602,6 +602,67 @@ extern void __pthread_cleanup_pop (struct _pthread_cleanup_buffer *buffer,
 # undef pthread_cleanup_pop
 # define pthread_cleanup_pop(execute)                   \
   __pthread_cleanup_pop (&_buffer, (execute)); }
+
+# if defined __EXCEPTIONS && !defined __cplusplus
+/* Structure to hold the cleanup handler information.  */
+struct __pthread_cleanup_combined_frame
+{
+  void (*__cancel_routine) (void *);
+  void *__cancel_arg;
+  int __do_it;
+  struct _pthread_cleanup_buffer __buffer;
+};
+
+/* Special cleanup macros which register cleanup both using
+   __pthread_cleanup_{push,pop} and using cleanup attribute.  This is needed
+   for pthread_once, so that it supports both throwing exceptions from the
+   pthread_once callback (only cleanup attribute works there) and cancellation
+   of the thread running the callback if the callback or some routines it
+   calls don't have unwind information.  */
+
+static __always_inline void
+__pthread_cleanup_combined_routine (struct __pthread_cleanup_combined_frame
+                                   *__frame)
+{
+  if (__frame->__do_it)
+    {
+      __frame->__cancel_routine (__frame->__cancel_arg);
+      __frame->__do_it = 0;
+      __pthread_cleanup_pop (&__frame->__buffer, 0);
+    }
+}
+
+static inline void
+__pthread_cleanup_combined_routine_voidptr (void *__arg)
+{
+  struct __pthread_cleanup_combined_frame *__frame
+    = (struct __pthread_cleanup_combined_frame *) __arg;
+  if (__frame->__do_it)
+    {
+      __frame->__cancel_routine (__frame->__cancel_arg);
+      __frame->__do_it = 0;
+    }
+}
+
+#  define pthread_cleanup_combined_push(routine, arg) \
+  do {                                                                       \
+    void (*__cancel_routine) (void *) = (routine);                           \
+    struct __pthread_cleanup_combined_frame __clframe                        \
+      __attribute__ ((__cleanup__ (__pthread_cleanup_combined_routine)))      \
+      = { .__cancel_routine = __cancel_routine, .__cancel_arg = (arg),       \
+         .__do_it = 1 };                                                     \
+    __pthread_cleanup_push (&__clframe.__buffer,                             \
+                           __pthread_cleanup_combined_routine_voidptr,       \
+                           &__clframe);
+
+#  define pthread_cleanup_combined_pop(execute) \
+    __pthread_cleanup_pop (&__clframe.__buffer, 0);                          \
+    __clframe.__do_it = 0;                                                   \
+    if (execute)                                                             \
+      __cancel_routine (__clframe.__cancel_arg);                             \
+  } while (0)
+
+# endif
 #endif
 
 extern void __pthread_cleanup_push_defer (struct _pthread_cleanup_buffer *buffer,
index 6c645aff48ed7dd787b0cccda97a02019ee669f3..337a7dcba643a1b3e795fec36cef978327fc2fcf 100644 (file)
@@ -51,6 +51,14 @@ static td_thr_events_t __nptl_threads_events __attribute_used__;
 /* Pointer to descriptor with the last event.  */
 static struct pthread *__nptl_last_event __attribute_used__;
 
+#ifdef SHARED
+/* This variable is used to access _rtld_global from libthread_db.  If
+   GDB loads libpthread before ld.so, it is not possible to resolve
+   _rtld_global directly during libpthread initialization.  */
+static struct rtld_global *__nptl_rtld_global __attribute_used__
+  = &_rtld_global;
+#endif
+
 /* Number of threads running.  */
 unsigned int __nptl_nthreads = 1;
 
@@ -426,8 +434,6 @@ START_THREAD_DEFN
   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);
@@ -437,6 +443,8 @@ START_THREAD_DEFN
       /* Store the new cleanup handler info.  */
       THREAD_SETMEM (pd, cleanup_jmp_buf, &unwind_buf);
 
+      __libc_signal_restore_set (&pd->sigmask);
+
       /* We are either in (a) or (b), and in either case we either own
          PD already (2) or are about to own PD (1), and so our only
         restriction would be that we can't free PD until we know we
index 28d97097c75f992d6b7c7e00f36155e040e2dcfa..7645da222a65bc3d3bec3715ba705ccacc5ee07b 100644 (file)
@@ -111,11 +111,11 @@ __pthread_once_slow (pthread_once_t *once_control, void (*init_routine) (void))
       /* This thread is the first here.  Do the initialization.
         Register a cleanup handler so that in case the thread gets
         interrupted the initialization can be restarted.  */
-      pthread_cleanup_push (clear_once_control, once_control);
+      pthread_cleanup_combined_push (clear_once_control, once_control);
 
       init_routine ();
 
-      pthread_cleanup_pop (0);
+      pthread_cleanup_combined_pop (0);
 
 
       /* Mark *once_control as having finished the initialization.  We need
index b797ab35622e78eb67d6a55bf9e4ed6c0ac61e1b..60fe1ef820f3832caf53cddd31d0f6955bd5caf0 100644 (file)
@@ -59,7 +59,7 @@ do_test (void)
                " throwing an exception", stderr);
     }
     catch (OnceException) {
-      if (1 < niter)
+      if (niter > 1)
         fputs ("pthread_once unexpectedly threw", stderr);
       result = 0;
     }
@@ -75,7 +75,5 @@ do_test (void)
   return result;
 }
 
-// The test currently hangs and is XFAILed.  Reduce the timeout.
-#define TIMEOUT 1
 #define TEST_FUNCTION do_test ()
 #include "../test-skeleton.c"
diff --git a/nptl/tst-pthread-gdb-attach-static.c b/nptl/tst-pthread-gdb-attach-static.c
new file mode 100644 (file)
index 0000000..e159632
--- /dev/null
@@ -0,0 +1 @@
+#include "tst-pthread-gdb-attach.c"
diff --git a/nptl/tst-pthread-gdb-attach.c b/nptl/tst-pthread-gdb-attach.c
new file mode 100644 (file)
index 0000000..901a120
--- /dev/null
@@ -0,0 +1,217 @@
+/* Smoke testing GDB process attach with thread-local variable access.
+   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
+   <https://www.gnu.org/licenses/>.  */
+
+/* This test runs GDB against a forked copy of itself, to check
+   whether libthread_db can be loaded, and that access to thread-local
+   variables works.  */
+
+#include <elf.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/support.h>
+#include <support/temp_file.h>
+#include <support/test-driver.h>
+#include <support/xstdio.h>
+#include <support/xthread.h>
+#include <support/xunistd.h>
+#include <unistd.h>
+
+/* Starts out as zero, changed to 1 or 2 by the debugger, depending on
+   the thread.  */
+__thread volatile int altered_by_debugger;
+
+/* Common prefix between 32-bit and 64-bit ELF.  */
+struct elf_prefix
+{
+  unsigned char e_ident[EI_NIDENT];
+  uint16_t e_type;
+  uint16_t e_machine;
+  uint32_t e_version;
+};
+_Static_assert (sizeof (struct elf_prefix) == EI_NIDENT + 8,
+                "padding in struct elf_prefix");
+
+/* Reads the ELF header from PATH.  Returns true if the header can be
+   read, false if the file is too short.  */
+static bool
+read_elf_header (const char *path, struct elf_prefix *elf)
+{
+  int fd = xopen (path, O_RDONLY, 0);
+  bool result = read (fd, elf, sizeof (*elf)) == sizeof (*elf);
+  xclose (fd);
+  return result;
+}
+
+/* Searches for "gdb" alongside the path variable.  See execvpe.  */
+static char *
+find_gdb (void)
+{
+  const char *path = getenv ("PATH");
+  if (path == NULL)
+    return NULL;
+  while (true)
+    {
+      const char *colon = strchrnul (path, ':');
+      char *candidate = xasprintf ("%.*s/gdb", (int) (colon - path), path);
+      if (access (candidate, X_OK) == 0)
+        return candidate;
+      free (candidate);
+      if (*colon == '\0')
+        break;
+      path = colon + 1;
+    }
+  return NULL;
+}
+
+/* Writes the GDB script to run the test to PATH.  */
+static void
+write_gdbscript (const char *path, int tested_pid)
+{
+  FILE *fp = xfopen (path, "w");
+  fprintf (fp,
+           "set trace-commands on\n"
+           "set debug libthread-db 1\n"
+#if DO_ADD_SYMBOL_FILE
+           /* Do not do this unconditionally to work around a GDB
+              assertion failure: ../../gdb/symtab.c:6404:
+              internal-error: CORE_ADDR get_msymbol_address(objfile*,
+              const minimal_symbol*): Assertion `(objf->flags &
+              OBJF_MAINLINE) == 0' failed.  */
+           "add-symbol-file %1$s/nptl/tst-pthread-gdb-attach\n"
+#endif
+           "set auto-load safe-path %1$s/nptl_db\n"
+           "set libthread-db-search-path %1$s/nptl_db\n"
+           "attach %2$d\n",
+           support_objdir_root, tested_pid);
+  fputs ("break debugger_inspection_point\n"
+         "continue\n"
+         "thread 1\n"
+         "print altered_by_debugger\n"
+         "print altered_by_debugger = 1\n"
+         "thread 2\n"
+         "print altered_by_debugger\n"
+         "print altered_by_debugger = 2\n"
+         "continue\n",
+         fp);
+  xfclose (fp);
+}
+
+/* The test sets a breakpoint on this function and alters the
+   altered_by_debugger thread-local variable.  */
+void __attribute__ ((weak))
+debugger_inspection_point (void)
+{
+}
+
+/* Thread function for the test thread in the subprocess.  */
+static void *
+subprocess_thread (void *closure)
+{
+  /* Wait until altered_by_debugger changes the value away from 0.  */
+  while (altered_by_debugger == 0)
+    {
+      usleep (100 * 1000);
+      debugger_inspection_point ();
+    }
+
+  TEST_COMPARE (altered_by_debugger, 2);
+  return NULL;
+}
+
+/* This function implements the subprocess under test.  It creates a
+   second thread, waiting for its value to change to 2, and checks
+   that the main thread also changed its value to 1.  */
+static void
+in_subprocess (void)
+{
+  pthread_t thr = xpthread_create (NULL, subprocess_thread, NULL);
+  TEST_VERIFY (xpthread_join (thr) == NULL);
+  TEST_COMPARE (altered_by_debugger, 1);
+  _exit (0);
+}
+
+static int
+do_test (void)
+{
+  char *gdb_path = find_gdb ();
+  if (gdb_path == NULL)
+    FAIL_UNSUPPORTED ("gdb command not found in PATH: %s", getenv ("PATH"));
+
+  /* Check that libthread_db is compatible with the gdb architecture
+     because gdb loads it via dlopen.  */
+  {
+    char *threaddb_path = xasprintf ("%s/nptl_db/libthread_db.so",
+                                     support_objdir_root);
+    struct elf_prefix elf_threaddb;
+    TEST_VERIFY_EXIT (read_elf_header (threaddb_path, &elf_threaddb));
+    struct elf_prefix elf_gdb;
+    /* If the ELF header cannot be read or "gdb" is not an ELF file,
+       assume this is a wrapper script that can run.  */
+    if (read_elf_header (gdb_path, &elf_gdb)
+        && memcmp (&elf_gdb, ELFMAG, SELFMAG) == 0)
+      {
+        if (elf_gdb.e_ident[EI_CLASS] != elf_threaddb.e_ident[EI_CLASS])
+          FAIL_UNSUPPORTED ("GDB at %s has wrong class", gdb_path);
+        if (elf_gdb.e_ident[EI_DATA] != elf_threaddb.e_ident[EI_DATA])
+          FAIL_UNSUPPORTED ("GDB at %s has wrong data", gdb_path);
+        if (elf_gdb.e_machine != elf_threaddb.e_machine)
+          FAIL_UNSUPPORTED ("GDB at %s has wrong machine", gdb_path);
+      }
+    free (threaddb_path);
+  }
+
+  pid_t tested_pid = xfork ();
+  if (tested_pid == 0)
+    in_subprocess ();
+  char *tested_pid_string = xasprintf ("%d", tested_pid);
+
+  char *gdbscript;
+  xclose (create_temp_file ("tst-pthread-gdb-attach-", &gdbscript));
+  write_gdbscript (gdbscript, tested_pid);
+
+  pid_t gdb_pid = xfork ();
+  if (gdb_pid == 0)
+    {
+      xdup2 (STDOUT_FILENO, STDERR_FILENO);
+      execl (gdb_path, "gdb", "-nx", "-batch", "-x", gdbscript, NULL);
+      if (errno == ENOENT)
+        _exit (EXIT_UNSUPPORTED);
+      else
+        _exit (1);
+    }
+
+  int status;
+  TEST_COMPARE (xwaitpid (gdb_pid, &status, 0), gdb_pid);
+  if (WIFEXITED (status) && WEXITSTATUS (status) == EXIT_UNSUPPORTED)
+    /* gdb is not installed.  */
+    return EXIT_UNSUPPORTED;
+  TEST_COMPARE (status, 0);
+  TEST_COMPARE (xwaitpid (tested_pid, &status, 0), tested_pid);
+  TEST_COMPARE (status, 0);
+
+  free (tested_pid_string);
+  free (gdbscript);
+  free (gdb_path);
+  return 0;
+}
+
+#include <support/test-driver.c>
index 999a9fc35a0c742fc11e70f21cd5c7c5103b70f9..8a613dd2f5fc016b6ea73f65d23ec8943aea17d9 100644 (file)
@@ -100,8 +100,7 @@ DB_STRUCT_FIELD (pthread, dtvp)
 #endif
 
 #if !(IS_IN (libpthread) && !defined SHARED)
-DB_STRUCT (rtld_global)
-DB_RTLD_VARIABLE (_rtld_global)
+DB_VARIABLE (__nptl_rtld_global)
 #endif
 DB_RTLD_GLOBAL_FIELD (dl_tls_dtv_slotinfo_list)
 DB_RTLD_GLOBAL_FIELD (dl_stack_user)
index 1d15681228470c3a16fa13f40e956e9030c2a895..06b5adc5c2941841a5aabc05d6598be0666d9a95 100644 (file)
@@ -33,13 +33,14 @@ td_init (void)
 bool
 __td_ta_rtld_global (td_thragent_t *ta)
 {
-  if (ta->ta_addr__rtld_global == 0
-      && td_mod_lookup (ta->ph, LD_SO, SYM__rtld_global,
-                        &ta->ta_addr__rtld_global) != PS_OK)
+  if (ta->ta_addr__rtld_global == 0)
     {
-      ta->ta_addr__rtld_global = (void*)-1;
-      return false;
+      psaddr_t rtldglobalp;
+      if (DB_GET_VALUE (rtldglobalp, ta, __nptl_rtld_global, 0) == TD_OK)
+        ta->ta_addr__rtld_global = rtldglobalp;
+      else
+        ta->ta_addr__rtld_global = (void *) -1;
     }
-  else
-    return ta->ta_addr__rtld_global != (void*)-1;
+
+  return ta->ta_addr__rtld_global != (void *)-1;
 }
index 580a70c471d459828f902c989fec443ab8aaf773..712fa3aeb6bd67defdcda725e11ce9eb64be34ec 100644 (file)
@@ -108,6 +108,8 @@ struct td_thragent
 # undef DB_SYMBOL
 # undef DB_VARIABLE
 
+  psaddr_t ta_addr__rtld_global;
+
   /* The method of locating a thread's th_unique value.  */
   enum
     {
index dba6ceec1be490bfae78ff4573a9aed5189e05f1..ad2daddafdc9d80cf81178415f22e3649ee64f52 100644 (file)
@@ -248,7 +248,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
                                             : NULL);
                                    ndomain = (ndomain ? newbuf + ndomaindiff
                                               : NULL);
-                                   buffer = newbuf;
+                                   *tofreep = buffer = newbuf;
                                  }
 
                                nhost = memcpy (buffer + bufused,
@@ -319,7 +319,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
                    else if (status == NSS_STATUS_TRYAGAIN && e == ERANGE)
                      {
                        buflen *= 2;
-                       buffer = xrealloc (buffer, buflen);
+                       *tofreep = buffer = xrealloc (buffer, buflen);
                      }
                    else if (status == NSS_STATUS_RETURN
                             || status == NSS_STATUS_NOTFOUND
index cf0306adc47f12d9bc761ab1b013629f4482b7e6..fb72d0cc03d5c0c872bca7afb3eb20d6f193ad14 100644 (file)
@@ -398,10 +398,10 @@ nss_database_check_reload_and_get (struct nss_database_state *local,
          && (str.st_ino != local->root_ino
              ||  str.st_dev != local->root_dev)))
     {
-      /* Change detected; disable reloading.  */
+      /* Change detected; disable reloading and return current state.  */
       atomic_store_release (&local->data.reload_disabled, 1);
+      *result = local->data.services[database_index];
       __libc_lock_unlock (local->lock);
-      __nss_module_disable_loading ();
       return true;
     }
   local->root_ino = str.st_ino;
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 (file)
index 0000000..5b0c6a4
--- /dev/null
@@ -0,0 +1 @@
+hosts: files
index 5dae16b4f05096e8d4a85ff331563014093f27fb..5ecb032e9fcd6868bb4066c1f8590e8c7ca9a45f 100644 (file)
@@ -26,6 +26,7 @@
 #include <pwd.h>
 #include <grp.h>
 #include <unistd.h>
+#include <netdb.h>
 
 #include <support/support.h>
 #include <support/check.h>
@@ -48,7 +49,7 @@ static const char *group_4[] = {
   "alpha", "beta", "gamma", "fred", NULL
 };
 
-static struct group group_table_data[] =
+static struct group group_table_data1[] =
   {
    GRP (4),
    GRP_LAST ()
@@ -58,7 +59,7 @@ void
 _nss_test1_init_hook (test_tables *t)
 {
   t->pwd_table = pwd_table1;
-  t->grp_table = group_table_data;
+  t->grp_table = group_table_data1;
 }
 
 static struct passwd pwd_table2[] =
@@ -68,10 +69,21 @@ static struct passwd pwd_table2[] =
    PWD_LAST ()
   };
 
+static const char *group_5[] = {
+  "fred", NULL
+};
+
+static struct group group_table_data2[] =
+  {
+   GRP (5),
+   GRP_LAST ()
+  };
+
 void
 _nss_test2_init_hook (test_tables *t)
 {
   t->pwd_table = pwd_table2;
+  t->grp_table = group_table_data2;
 }
 
 static int
@@ -79,6 +91,7 @@ do_test (void)
 {
   struct passwd *pw;
   struct group *gr;
+  struct hostent *he;
   char buf1[PATH_MAX];
   char buf2[PATH_MAX];
 
@@ -99,7 +112,9 @@ do_test (void)
     TEST_COMPARE (pw->pw_uid, 1234);
 
   /* This just loads the test2 DSO.  */
-  gr = getgrnam ("name4");
+  gr = getgrgid (5);
+  TEST_VERIFY (gr != NULL);
+
 
   /* Change the root dir.  */
 
@@ -114,15 +129,21 @@ do_test (void)
   if (pw)
     TEST_VERIFY (pw->pw_uid != 2468);
 
-  /* The "files" DSO should not be loaded.  */
-  gr = getgrnam ("test3");
-  TEST_VERIFY (gr == NULL);
-
   /* We should still be using the old configuration.  */
   pw = getpwnam ("test1");
   TEST_VERIFY (pw != NULL);
   if (pw)
     TEST_COMPARE (pw->pw_uid, 1234);
+  gr = getgrgid (5);
+  TEST_VERIFY (gr != NULL);
+  gr = getgrnam ("name4");
+  TEST_VERIFY (gr == NULL);
+
+  /* hosts in the outer nsswitch is files; the inner one is test1.
+     Verify that we're still using the outer nsswitch *and* that we
+     can load the files DSO. */
+  he = gethostbyname ("test2");
+  TEST_VERIFY (he != NULL);
 
   return 0;
 }
diff --git a/nss/tst-reload2.root/etc/hosts b/nss/tst-reload2.root/etc/hosts
new file mode 100644 (file)
index 0000000..bbd9e49
--- /dev/null
@@ -0,0 +1 @@
+1.2.3.4 test1
index 570795ae22d116f1192d5f476dab16de051fbeff..688a5895191a913b2ddc8a9290ce7583876decab 100644 (file)
@@ -1,2 +1,3 @@
 passwd: test1
 group: test2
+hosts: files
diff --git a/nss/tst-reload2.root/subdir/etc/hosts b/nss/tst-reload2.root/subdir/etc/hosts
new file mode 100644 (file)
index 0000000..0a2cbd4
--- /dev/null
@@ -0,0 +1 @@
+1.2.3.4 test2
index f1d73f8765116d1d027ee74b215f5aa12ebad88e..fea271869ef98458d3969d048d02e0a99e761e89 100644 (file)
@@ -1,2 +1,3 @@
 passwd: test2
 group: files
+hosts: test1
index f0831386c7ddb5744dc764ef38bbc9a741796825..622adeb2b28ed298889ccdcb047a03a724e15cfa 100644 (file)
@@ -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)
index 3f2276337944e67a68ea3d02f212a599bfdaded1..bede49c1ff58bc47ea194a4b1b764d398277b72c 100644 (file)
@@ -517,8 +517,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.
index f93a546d7eef9ac62353a0182660009f03dec7ee..9df02dbbb3ae58b70f6680f4efc4ed367a690c53 100644 (file)
@@ -183,6 +183,7 @@ struct test_case_struct
     { 0, NULL, "$var", 0, 0, { NULL, }, IFS },
     { 0, NULL, "\"\\n\"", 0, 1, { "\\n", }, IFS },
     { 0, NULL, "", 0, 0, { NULL, }, IFS },
+    { 0, NULL, "${1234567890123456789012}", 0, 0, { NULL, }, IFS },
 
     /* Flags not already covered (testit() has special handling for these) */
     { 0, NULL, "one two", WRDE_DOOFFS, 2, { "one", "two", }, IFS },
index bcbe96e48dfc825b2891dc10dbecfd5a8ddfd5fe..1f3b09f721bbee5c0376ad2756576a65eca9fef7 100644 (file)
@@ -1399,7 +1399,7 @@ envsubst:
   /* Is it a numeric parameter? */
   else if (isdigit (env[0]))
     {
-      int n = atoi (env);
+      unsigned long n = strtoul (env, NULL, 10);
 
       if (n >= __libc_argc)
        /* Substitute NULL. */
index 7b374f207333f14dbce97f731cff24c60cd795b1..c87d95793adcc0500c2e33afd8fdb0e59a1c74a7 100644 (file)
@@ -44,6 +44,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 (file)
index 0000000..0c096b5
--- /dev/null
@@ -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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <mqueue.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <support/check.h>
+
+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 <support/test-driver.c>
index 600891d5d1ddabdf55e322a30b2db80424b6c822..4ab67aed6975c92e21a74ce49b6d20abaf4dd3ef 100644 (file)
@@ -29,10 +29,14 @@ headers     := sys/socket.h sys/un.h bits/sockaddr.h bits/socket.h \
 routines := accept bind connect getpeername getsockname getsockopt     \
            listen recv recvfrom recvmsg send sendmsg sendto            \
            setsockopt shutdown socket socketpair isfdtype opensock     \
-           sockatmark accept4 recvmmsg sendmmsg
+           sockatmark accept4 recvmmsg sendmmsg sockaddr_un_set
 
 tests := tst-accept4
 
+tests-internal := \
+  tst-sockaddr_un_set \
+  # tests-internal
+
 aux     := sa_len
 
 include ../Rules
diff --git a/socket/sockaddr_un_set.c b/socket/sockaddr_un_set.c
new file mode 100644 (file)
index 0000000..0bd40dc
--- /dev/null
@@ -0,0 +1,41 @@
+/* Set the sun_path member of struct sockaddr_un.
+   Copyright (C) 2022 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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+int
+__sockaddr_un_set (struct sockaddr_un *addr, const char *pathname)
+{
+  size_t name_length = strlen (pathname);
+
+  /* The kernel supports names of exactly sizeof (addr->sun_path)
+     bytes, without a null terminator, but userspace does not; see the
+     SUN_LEN macro.  */
+  if (name_length >= sizeof (addr->sun_path))
+    {
+      __set_errno (EINVAL);     /* Error code used by the kernel.  */
+      return -1;
+    }
+
+  addr->sun_family = AF_UNIX;
+  memcpy (addr->sun_path, pathname, name_length + 1);
+  return 0;
+}
diff --git a/socket/tst-sockaddr_un_set.c b/socket/tst-sockaddr_un_set.c
new file mode 100644 (file)
index 0000000..29c2a81
--- /dev/null
@@ -0,0 +1,62 @@
+/* Test the __sockaddr_un_set function.
+   Copyright (C) 2022 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
+   <https://www.gnu.org/licenses/>.  */
+
+/* Re-compile the function because the version in libc is not
+   exported.  */
+#include "sockaddr_un_set.c"
+
+#include <support/check.h>
+
+static int
+do_test (void)
+{
+  struct sockaddr_un sun;
+
+  memset (&sun, 0xcc, sizeof (sun));
+  __sockaddr_un_set (&sun, "");
+  TEST_COMPARE (sun.sun_family, AF_UNIX);
+  TEST_COMPARE (__sockaddr_un_set (&sun, ""), 0);
+
+  memset (&sun, 0xcc, sizeof (sun));
+  TEST_COMPARE (__sockaddr_un_set (&sun, "/example"), 0);
+  TEST_COMPARE_STRING (sun.sun_path, "/example");
+
+  {
+    char pathname[108];         /* Length of sun_path (ABI constant).  */
+    memset (pathname, 'x', sizeof (pathname));
+    pathname[sizeof (pathname) - 1] = '\0';
+    memset (&sun, 0xcc, sizeof (sun));
+    TEST_COMPARE (__sockaddr_un_set (&sun, pathname), 0);
+    TEST_COMPARE (sun.sun_family, AF_UNIX);
+    TEST_COMPARE_STRING (sun.sun_path, pathname);
+  }
+
+  {
+    char pathname[109];
+    memset (pathname, 'x', sizeof (pathname));
+    pathname[sizeof (pathname) - 1] = '\0';
+    memset (&sun, 0xcc, sizeof (sun));
+    errno = 0;
+    TEST_COMPARE (__sockaddr_un_set (&sun, pathname), -1);
+    TEST_COMPARE (errno, EINVAL);
+  }
+
+  return 0;
+}
+
+#include <support/test-driver.c>
index b3b30ab73e317a7ddcc155723aa28e75deac06ad..b1eebd568ff3633800fc51406350a687c3fcb8e1 100644 (file)
@@ -86,7 +86,8 @@ tests         := tst-strtol tst-strtod testmb testrand testsort testdiv   \
                   tst-makecontext-align test-bz22786 tst-strtod-nan-sign \
                   tst-swapcontext1 tst-setcontext4 tst-setcontext5 \
                   tst-setcontext6 tst-setcontext7 tst-setcontext8 \
-                  tst-setcontext9 tst-bz20544 tst-canon-bz26341
+                  tst-setcontext9 tst-bz20544 tst-canon-bz26341 \
+                  tst-realpath-toolong
 
 tests-internal := tst-strtod1i tst-strtod3 tst-strtod4 tst-strtod5i \
                   tst-tls-atexit tst-tls-atexit-nodelete
index 698f9ede25570ef2775d3c772ff510336425b796..e2d4244fc7b8fa25b08f14968ed7e7ed3ad29c8c 100644 (file)
@@ -400,8 +400,16 @@ realpath_stk (const char *name, char *resolved,
 
 error:
   *dest++ = '\0';
-  if (resolved != NULL && dest - rname <= get_path_max ())
-    rname = strcpy (resolved, rname);
+  if (resolved != NULL)
+    {
+      if (dest - rname <= get_path_max ())
+       rname = strcpy (resolved, rname);
+      else if (!failed)
+       {
+         failed = true;
+         __set_errno (ENAMETOOLONG);
+       }
+    }
 
 error_nomem:
   scratch_buffer_free (&extra_buffer);
diff --git a/stdlib/tst-realpath-toolong.c b/stdlib/tst-realpath-toolong.c
new file mode 100644 (file)
index 0000000..4388890
--- /dev/null
@@ -0,0 +1,53 @@
+/* Verify that realpath returns NULL with ENAMETOOLONG if the result exceeds
+   NAME_MAX.
+   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
+   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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <support/check.h>
+#include <support/temp_file.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#define BASENAME "tst-realpath-toolong."
+
+#ifndef PATH_MAX
+# define PATH_MAX 1024
+#endif
+
+int
+do_test (void)
+{
+  char *base = support_create_and_chdir_toolong_temp_directory (BASENAME);
+
+  char buf[PATH_MAX + 1];
+  const char *res = realpath (".", buf);
+
+  /* canonicalize.c states that if the real path is >= PATH_MAX, then
+     realpath returns NULL and sets ENAMETOOLONG.  */
+  TEST_VERIFY (res == NULL);
+  TEST_VERIFY (errno == ENAMETOOLONG);
+
+  free (base);
+  return 0;
+}
+
+#include <support/test-driver.c>
index c9ec03866ff8ac3b82cb7fc9a082e2af0e9475e5..5567c9ae215fd924c0553ceceff0171c6775352d 100644 (file)
 #include <sys/wait.h>
 #include <unistd.h>
 
+#include <support/check.h>
 #include <support/support.h>
+#include <support/capture_subprocess.h>
 #include <support/test-driver.h>
 
 static char MAGIC_ARGUMENT[] = "run-actual-test";
-#define MAGIC_STATUS 19
-
-/* Return a GID which is not our current GID, but is present in the
-   supplementary group list.  */
-static gid_t
-choose_gid (void)
-{
-  int count = getgroups (0, NULL);
-  if (count < 0)
-    {
-      printf ("getgroups: %m\n");
-      exit (1);
-    }
-  gid_t *groups;
-  groups = xcalloc (count, sizeof (*groups));
-  int ret = getgroups (count, groups);
-  if (ret < 0)
-    {
-      printf ("getgroups: %m\n");
-      exit (1);
-    }
-  gid_t current = getgid ();
-  gid_t not_current = 0;
-  for (int i = 0; i < ret; ++i)
-    {
-      if (groups[i] != current)
-        {
-          not_current = groups[i];
-          break;
-        }
-    }
-  free (groups);
-  return not_current;
-}
-
-
-/* Copies the executable into a restricted directory, so that we can
-   safely make it SGID with the TARGET group ID.  Then runs the
-   executable.  */
-static int
-run_executable_sgid (gid_t target)
-{
-  char *dirname = xasprintf ("%s/secure-getenv.%jd",
-                            test_dir, (intmax_t) getpid ());
-  char *execname = xasprintf ("%s/bin", dirname);
-  int infd = -1;
-  int outfd = -1;
-  int ret = -1;
-  if (mkdir (dirname, 0700) < 0)
-    {
-      printf ("mkdir: %m\n");
-      goto err;
-    }
-  infd = open ("/proc/self/exe", O_RDONLY);
-  if (infd < 0)
-    {
-      printf ("open (/proc/self/exe): %m\n");
-      goto err;
-    }
-  outfd = open (execname, O_WRONLY | O_CREAT | O_EXCL, 0700);
-  if (outfd < 0)
-    {
-      printf ("open (%s): %m\n", execname);
-      goto err;
-    }
-  char buf[4096];
-  for (;;)
-    {
-      ssize_t rdcount = read (infd, buf, sizeof (buf));
-      if (rdcount < 0)
-       {
-         printf ("read: %m\n");
-         goto err;
-       }
-      if (rdcount == 0)
-       break;
-      char *p = buf;
-      char *end = buf + rdcount;
-      while (p != end)
-       {
-         ssize_t wrcount = write (outfd, buf, end - p);
-         if (wrcount == 0)
-           errno = ENOSPC;
-         if (wrcount <= 0)
-           {
-             printf ("write: %m\n");
-             goto err;
-           }
-         p += wrcount;
-       }
-    }
-  if (fchown (outfd, getuid (), target) < 0)
-    {
-      printf ("fchown (%s): %m\n", execname);
-      goto err;
-    }
-  if (fchmod (outfd, 02750) < 0)
-    {
-      printf ("fchmod (%s): %m\n", execname);
-      goto err;
-    }
-  if (close (outfd) < 0)
-    {
-      printf ("close (outfd): %m\n");
-      goto err;
-    }
-  if (close (infd) < 0)
-    {
-      printf ("close (infd): %m\n");
-      goto err;
-    }
-
-  int kid = fork ();
-  if (kid < 0)
-    {
-      printf ("fork: %m\n");
-      goto err;
-    }
-  if (kid == 0)
-    {
-      /* Child process.  */
-      char *args[] = { execname, MAGIC_ARGUMENT, NULL };
-      execve (execname, args, environ);
-      printf ("execve (%s): %m\n", execname);
-      _exit (1);
-    }
-  int status;
-  if (waitpid (kid, &status, 0) < 0)
-    {
-      printf ("waitpid: %m\n");
-      goto err;
-    }
-  if (!WIFEXITED (status) || WEXITSTATUS (status) != MAGIC_STATUS)
-    {
-      printf ("Unexpected exit status %d from child process\n",
-             status);
-      goto err;
-    }
-  ret = 0;
-
-err:
-  if (outfd >= 0)
-    close (outfd);
-  if (infd >= 0)
-    close (infd);
-  if (execname)
-    {
-      unlink (execname);
-      free (execname);
-    }
-  if (dirname)
-    {
-      rmdir (dirname);
-      free (dirname);
-    }
-  return ret;
-}
 
 static int
 do_test (void)
@@ -212,15 +57,15 @@ do_test (void)
       exit (1);
     }
 
-  gid_t target = choose_gid ();
-  if (target == 0)
-    {
-      fprintf (stderr,
-              "Could not find a suitable GID for user %jd, skipping test\n",
-              (intmax_t) getuid ());
-      exit (0);
-    }
-  return run_executable_sgid (target);
+  int status = support_capture_subprogram_self_sgid (MAGIC_ARGUMENT);
+
+  if (WEXITSTATUS (status) == EXIT_UNSUPPORTED)
+    return EXIT_UNSUPPORTED;
+
+  if (!WIFEXITED (status))
+    FAIL_EXIT1 ("Unexpected exit status %d from child process\n", status);
+
+  return 0;
 }
 
 static void
@@ -229,23 +74,15 @@ alternative_main (int argc, char **argv)
   if (argc == 2 && strcmp (argv[1], MAGIC_ARGUMENT) == 0)
     {
       if (getgid () == getegid ())
-       {
-         /* This can happen if the file system is mounted nosuid.  */
-         fprintf (stderr, "SGID failed: GID and EGID match (%jd)\n",
-                 (intmax_t) getgid ());
-         exit (MAGIC_STATUS);
-       }
+       /* This can happen if the file system is mounted nosuid.  */
+       FAIL_UNSUPPORTED ("SGID failed: GID and EGID match (%jd)\n",
+                  (intmax_t) getgid ());
       if (getenv ("PATH") == NULL)
-       {
-         printf ("PATH variable not present\n");
-         exit (3);
-       }
+       FAIL_EXIT (3, "PATH variable not present\n");
       if (secure_getenv ("PATH") != NULL)
-       {
-         printf ("PATH variable not filtered out\n");
-         exit (4);
-       }
-      exit (MAGIC_STATUS);
+       FAIL_EXIT (4, "PATH variable not filtered out\n");
+
+      exit (EXIT_SUCCESS);
     }
 }
 
index 59bbeeaa42e51056f34dd261e54db713daf05bd0..b8523118e5b3586e2f2e8b8d74e54eb368c6bf2b 100644 (file)
 # define RAWMEMCHR __rawmemchr
 #endif
 
-/* Find the first occurrence of C in S.  */
-void *
-RAWMEMCHR (const void *s, int c)
-{
-  DIAG_PUSH_NEEDS_COMMENT;
+/* The pragmata should be nested inside RAWMEMCHR below, but that
+   triggers GCC PR 98512.  */
+DIAG_PUSH_NEEDS_COMMENT;
 #if __GNUC_PREREQ (7, 0)
-  /* GCC 8 warns about the size passed to memchr being larger than
-     PTRDIFF_MAX; the use of SIZE_MAX is deliberate here.  */
-  DIAG_IGNORE_NEEDS_COMMENT (8, "-Wstringop-overflow=");
+/* GCC 8 warns about the size passed to memchr being larger than
+   PTRDIFF_MAX; the use of SIZE_MAX is deliberate here.  */
+DIAG_IGNORE_NEEDS_COMMENT (8, "-Wstringop-overflow=");
 #endif
 #if __GNUC_PREREQ (11, 0)
-  /* Likewise GCC 11, with a different warning option.  */
-  DIAG_IGNORE_NEEDS_COMMENT (11, "-Wstringop-overread");
+/* Likewise GCC 11, with a different warning option.  */
+DIAG_IGNORE_NEEDS_COMMENT (11, "-Wstringop-overread");
 #endif
+
+/* Find the first occurrence of C in S.  */
+void *
+RAWMEMCHR (const void *s, int c)
+{
   if (c != '\0')
     return memchr (s, c, (size_t)-1);
-  DIAG_POP_NEEDS_COMMENT;
   return (char *)s + strlen (s);
 }
 libc_hidden_def (__rawmemchr)
 weak_alias (__rawmemchr, rawmemchr)
+
+DIAG_POP_NEEDS_COMMENT;
index 9761585409ed56a2b65e1ce234a6a9db2f5ef779..a7cd3eafa4cdae75c069c5db809b35765a5c17e4 100644 (file)
@@ -65,7 +65,8 @@ shared-only-routines = $(routines)
 endif
 
 tests = tst-xdrmem tst-xdrmem2 test-rpcent tst-udp-error tst-udp-timeout \
-  tst-udp-nonblocking
+  tst-udp-nonblocking tst-bug22542 tst-bug28768
+
 xtests := tst-getmyaddr
 
 ifeq ($(have-thread-library),yes)
@@ -111,6 +112,8 @@ $(objpfx)tst-udp-nonblocking: $(common-objpfx)linkobj/libc.so
 $(objpfx)tst-udp-garbage: \
   $(common-objpfx)linkobj/libc.so $(shared-thread-library)
 
+$(objpfx)tst-bug22542: $(common-objpfx)linkobj/libc.so
+
 else # !have-GLIBC_2.31
 
 routines = $(routines-for-nss)
index 13ced8994e49d4ee744a35c3ac4bd840f5d0abb5..b44357cd88e60599b82635618229109fe91855a0 100644 (file)
@@ -57,9 +57,13 @@ clnt_create (const char *hostname, u_long prog, u_long vers,
 
   if (strcmp (proto, "unix") == 0)
     {
-      memset ((char *)&sun, 0, sizeof (sun));
-      sun.sun_family = AF_UNIX;
-      strcpy (sun.sun_path, hostname);
+      if (__sockaddr_un_set (&sun, hostname) < 0)
+       {
+         struct rpc_createerr *ce = &get_rpc_createerr ();
+         ce->cf_stat = RPC_SYSTEMERROR;
+         ce->cf_error.re_errno = errno;
+         return NULL;
+       }
       sock = RPC_ANYSOCK;
       client = clntunix_create (&sun, prog, vers, &sock, 0, 0);
       if (client == NULL)
index 679fbe9cb69587bddafc55c7f4105993c9d9f4c2..46f8d16fe94a3d4f5296268ec9d8d8af71f8f20b 100644 (file)
@@ -154,7 +154,10 @@ svcunix_create (int sock, u_int sendsize, u_int recvsize, char *path)
   SVCXPRT *xprt;
   struct unix_rendezvous *r;
   struct sockaddr_un addr;
-  socklen_t len = sizeof (struct sockaddr_in);
+  socklen_t len = sizeof (addr);
+
+  if (__sockaddr_un_set (&addr, path) < 0)
+    return NULL;
 
   if (sock == RPC_ANYSOCK)
     {
@@ -165,12 +168,6 @@ svcunix_create (int sock, u_int sendsize, u_int recvsize, char *path)
        }
       madesock = TRUE;
     }
-  memset (&addr, '\0', sizeof (addr));
-  addr.sun_family = AF_UNIX;
-  len = strlen (path) + 1;
-  memcpy (addr.sun_path, path, len);
-  len += sizeof (addr.sun_family);
-
   __bind (sock, (struct sockaddr *) &addr, len);
 
   if (__getsockname (sock, (struct sockaddr *) &addr, &len) != 0
index 7607abc8186813f6c2e1795aecb07f7d2585e60e..25a85c90970d4cedd9da724180bfc11016d7fec1 100644 (file)
@@ -58,7 +58,6 @@
 
 #define debug(msg)             /*printf("svcauth_des: %s\n", msg) */
 
-#define USEC_PER_SEC ((uint32_t) 1000000L)
 #define BEFORE(t1, t2) timercmp(t1, t2, <)
 
 /*
diff --git a/sunrpc/tst-bug22542.c b/sunrpc/tst-bug22542.c
new file mode 100644 (file)
index 0000000..d6cd797
--- /dev/null
@@ -0,0 +1,44 @@
+/* Test to verify that overlong hostname is rejected by clnt_create
+   and doesn't cause a buffer overflow (bug  22542).
+
+   Copyright (C) 2022 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <rpc/clnt.h>
+#include <string.h>
+#include <support/check.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+static int
+do_test (void)
+{
+  /* Create an arbitrary hostname that's longer than fits in sun_path.  */
+  char name [sizeof ((struct sockaddr_un*)0)->sun_path * 2];
+  memset (name, 'x', sizeof name - 1);
+  name [sizeof name - 1] = '\0';
+
+  errno = 0;
+  CLIENT *clnt = clnt_create (name, 0, 0, "unix");
+
+  TEST_VERIFY (clnt == NULL);
+  TEST_COMPARE (errno, EINVAL);
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sunrpc/tst-bug28768.c b/sunrpc/tst-bug28768.c
new file mode 100644 (file)
index 0000000..35a4b7b
--- /dev/null
@@ -0,0 +1,42 @@
+/* Test to verify that long path is rejected by svcunix_create (bug 28768).
+   Copyright (C) 2022 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <rpc/svc.h>
+#include <shlib-compat.h>
+#include <string.h>
+#include <support/check.h>
+
+/* svcunix_create does not have a default version in linkobj/libc.so.  */
+compat_symbol_reference (libc, svcunix_create, svcunix_create, GLIBC_2_1);
+
+static int
+do_test (void)
+{
+  char pathname[109];
+  memset (pathname, 'x', sizeof (pathname));
+  pathname[sizeof (pathname) - 1] = '\0';
+
+  errno = 0;
+  TEST_VERIFY (svcunix_create (RPC_ANYSOCK, 4096, 4096, pathname) == NULL);
+  TEST_COMPARE (errno, EINVAL);
+
+  return 0;
+}
+
+#include <support/test-driver.c>
index bb9889efb4be36303ace60dd6cc5202fc024a967..f631846c07d8180fd43c7dea11cc9a9b1746fbec 100644 (file)
@@ -67,6 +67,8 @@ libsupport-routines = \
   support_quote_string \
   support_record_failure \
   support_run_diff \
+  support_select_modifies_timeout \
+  support_select_normalizes_timeout \
   support_set_small_thread_stack_size \
   support_shared_allocate \
   support_small_stack_thread_attribute \
@@ -90,6 +92,7 @@ libsupport-routines = \
   xchdir \
   xchroot \
   xclock_gettime \
+  xclone \
   xclose \
   xchmod \
   xconnect \
@@ -139,6 +142,7 @@ libsupport-routines = \
   xpthread_join \
   xpthread_key_create \
   xpthread_key_delete \
+  xpthread_kill \
   xpthread_mutex_consistent \
   xpthread_mutex_destroy \
   xpthread_mutex_init \
index 8969d4a99a093657c96992b8e237a4c9db350e65..4be430f099bcc8cd191cfb2de2b88e60132ecb0d 100644 (file)
@@ -41,6 +41,12 @@ struct support_capture_subprocess support_capture_subprocess
 struct support_capture_subprocess support_capture_subprogram
   (const char *file, char *const argv[]);
 
+/* Copy the running program into a setgid binary and run it with CHILD_ID
+   argument.  If execution is successful, return the exit status of the child
+   program, otherwise return a non-zero failure exit code.  */
+int support_capture_subprogram_self_sgid
+  (char *child_id);
+
 /* Deallocate the subprocess data captured by
    support_capture_subprocess.  */
 void support_capture_subprocess_free (struct support_capture_subprocess *);
index 11cfc6a07f5ad94ac0fb21e80a3adac559a684a0..40d82c7e4db27090f84b07b937f21d1e0198669f 100644 (file)
@@ -38,6 +38,11 @@ struct support_subprocess support_subprocess
 struct support_subprocess support_subprogram
   (const char *file, char *const argv[]);
 
+/* Invoke program FILE with ARGV arguments by using posix_spawn and wait for it
+   to complete.  Return program exit status.  */
+int support_subprogram_wait
+  (const char *file, char *const argv[]);
+
 /* Wait for the subprocess indicated by PROC::PID.  Return the status
    indicate by waitpid call.  */
 int support_process_wait (struct support_subprocess *proc);
index 9cbc45572054fd907e3806d954521bfbb570b9cb..8c7890e0a6f94f8a3dd561729662651318c1ad5b 100644 (file)
@@ -23,6 +23,7 @@
 #ifndef SUPPORT_H
 #define SUPPORT_H
 
+#include <stdbool.h>
 #include <stddef.h>
 #include <sys/cdefs.h>
 /* For mode_t.  */
@@ -129,6 +130,14 @@ extern void support_copy_file (const char *from, const char *to);
 extern ssize_t support_copy_file_range (int, off64_t *, int, off64_t *,
                                        size_t, unsigned int);
 
+/* Return true if select modify the timeout to reflect the amount of time
+   no slept.  */
+extern bool support_select_modifies_timeout (void);
+
+/* Return true if select normalize the timeout input by taking in account
+   tv_usec larger than 1000000.  */
+extern bool support_select_normalizes_timeout (void);
+
 __END_DECLS
 
 #endif /* SUPPORT_H */
index a7afa0e70b48f6496275ddf61389140f111a52f4..27bfd19c9374a18340abb7d5b87643a43356e137 100644 (file)
 #include <support/capture_subprocess.h>
 
 #include <errno.h>
+#include <fcntl.h>
 #include <stdlib.h>
 #include <support/check.h>
 #include <support/xunistd.h>
 #include <support/xsocket.h>
 #include <support/xspawn.h>
+#include <support/support.h>
+#include <support/test-driver.h>
 
 static void
 transfer (const char *what, struct pollfd *pfd, struct xmemstream *stream)
@@ -36,7 +39,7 @@ transfer (const char *what, struct pollfd *pfd, struct xmemstream *stream)
       if (ret < 0)
         {
           support_record_failure ();
-          printf ("error: reading from subprocess %s: %m", what);
+          printf ("error: reading from subprocess %s: %m\n", what);
           pfd->events = 0;
           pfd->revents = 0;
         }
@@ -102,6 +105,129 @@ support_capture_subprogram (const char *file, char *const argv[])
   return result;
 }
 
+/* Copies the executable into a restricted directory, so that we can
+   safely make it SGID with the TARGET group ID.  Then runs the
+   executable.  */
+static int
+copy_and_spawn_sgid (char *child_id, gid_t gid)
+{
+  char *dirname = xasprintf ("%s/tst-tunables-setuid.%jd",
+                            test_dir, (intmax_t) getpid ());
+  char *execname = xasprintf ("%s/bin", dirname);
+  int infd = -1;
+  int outfd = -1;
+  int ret = 1, status = 1;
+
+  TEST_VERIFY (mkdir (dirname, 0700) == 0);
+  if (support_record_failure_is_failed ())
+    goto err;
+
+  infd = open ("/proc/self/exe", O_RDONLY);
+  if (infd < 0)
+    FAIL_UNSUPPORTED ("unsupported: Cannot read binary from procfs\n");
+
+  outfd = open (execname, O_WRONLY | O_CREAT | O_EXCL, 0700);
+  TEST_VERIFY (outfd >= 0);
+  if (support_record_failure_is_failed ())
+    goto err;
+
+  char buf[4096];
+  for (;;)
+    {
+      ssize_t rdcount = read (infd, buf, sizeof (buf));
+      TEST_VERIFY (rdcount >= 0);
+      if (support_record_failure_is_failed ())
+       goto err;
+      if (rdcount == 0)
+       break;
+      char *p = buf;
+      char *end = buf + rdcount;
+      while (p != end)
+       {
+         ssize_t wrcount = write (outfd, buf, end - p);
+         if (wrcount == 0)
+           errno = ENOSPC;
+         TEST_VERIFY (wrcount > 0);
+         if (support_record_failure_is_failed ())
+           goto err;
+         p += wrcount;
+       }
+    }
+  TEST_VERIFY (fchown (outfd, getuid (), gid) == 0);
+  if (support_record_failure_is_failed ())
+    goto err;
+  TEST_VERIFY (fchmod (outfd, 02750) == 0);
+  if (support_record_failure_is_failed ())
+    goto err;
+  TEST_VERIFY (close (outfd) == 0);
+  if (support_record_failure_is_failed ())
+    goto err;
+  TEST_VERIFY (close (infd) == 0);
+  if (support_record_failure_is_failed ())
+    goto err;
+
+  /* We have the binary, now spawn the subprocess.  Avoid using
+     support_subprogram because we only want the program exit status, not the
+     contents.  */
+  ret = 0;
+
+  char * const args[] = {execname, child_id, NULL};
+
+  status = support_subprogram_wait (args[0], args);
+
+err:
+  if (outfd >= 0)
+    close (outfd);
+  if (infd >= 0)
+    close (infd);
+  if (execname != NULL)
+    {
+      unlink (execname);
+      free (execname);
+    }
+  if (dirname != NULL)
+    {
+      rmdir (dirname);
+      free (dirname);
+    }
+
+  if (ret != 0)
+    FAIL_EXIT1("Failed to make sgid executable for test\n");
+
+  return status;
+}
+
+int
+support_capture_subprogram_self_sgid (char *child_id)
+{
+  gid_t target = 0;
+  const int count = 64;
+  gid_t groups[count];
+
+  /* Get a GID which is not our current GID, but is present in the
+     supplementary group list.  */
+  int ret = getgroups (count, groups);
+  if (ret < 0)
+    FAIL_UNSUPPORTED("Could not get group list for user %jd\n",
+                    (intmax_t) getuid ());
+
+  gid_t current = getgid ();
+  for (int i = 0; i < ret; ++i)
+    {
+      if (groups[i] != current)
+       {
+         target = groups[i];
+         break;
+       }
+    }
+
+  if (target == 0)
+    FAIL_UNSUPPORTED("Could not find a suitable GID for user %jd\n",
+                    (intmax_t) getuid ());
+
+  return copy_and_spawn_sgid (child_id, target);
+}
+
 void
 support_capture_subprocess_free (struct support_capture_subprocess *p)
 {
diff --git a/support/support_select_modifies_timeout.c b/support/support_select_modifies_timeout.c
new file mode 100644 (file)
index 0000000..653ea2c
--- /dev/null
@@ -0,0 +1,29 @@
+/* Return whether select modifies the timeout.
+   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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <support/support.h>
+
+bool
+support_select_modifies_timeout (void)
+{
+#ifdef __linux__
+  return true;
+#else
+  return false;
+#endif
+}
diff --git a/support/support_select_normalizes_timeout.c b/support/support_select_normalizes_timeout.c
new file mode 100644 (file)
index 0000000..987f9b0
--- /dev/null
@@ -0,0 +1,29 @@
+/* Return whether select normalizes the timeout.
+   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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <support/support.h>
+
+bool
+support_select_normalizes_timeout (void)
+{
+#ifdef __linux__
+  return true;
+#else
+  return false;
+#endif
+}
index 88489a3357f6aae0f9ed563d46bc811c43bb9db7..89e767ae47e454f191e32f6421cb3a6678e2d432 100644 (file)
@@ -27,7 +27,7 @@
 #include <support/subprocess.h>
 
 static struct support_subprocess
-support_suprocess_init (void)
+support_subprocess_init (void)
 {
   struct support_subprocess result;
 
@@ -48,7 +48,7 @@ support_suprocess_init (void)
 struct support_subprocess
 support_subprocess (void (*callback) (void *), void *closure)
 {
-  struct support_subprocess result = support_suprocess_init ();
+  struct support_subprocess result = support_subprocess_init ();
 
   result.pid = xfork ();
   if (result.pid == 0)
@@ -71,7 +71,7 @@ support_subprocess (void (*callback) (void *), void *closure)
 struct support_subprocess
 support_subprogram (const char *file, char *const argv[])
 {
-  struct support_subprocess result = support_suprocess_init ();
+  struct support_subprocess result = support_subprocess_init ();
 
   posix_spawn_file_actions_t fa;
   /* posix_spawn_file_actions_init does not fail.  */
@@ -84,7 +84,7 @@ support_subprogram (const char *file, char *const argv[])
   xposix_spawn_file_actions_addclose (&fa, result.stdout_pipe[1]);
   xposix_spawn_file_actions_addclose (&fa, result.stderr_pipe[1]);
 
-  result.pid = xposix_spawn (file, &fa, NULL, argv, NULL);
+  result.pid = xposix_spawn (file, &fa, NULL, argv, environ);
 
   xclose (result.stdout_pipe[1]);
   xclose (result.stderr_pipe[1]);
@@ -92,6 +92,19 @@ support_subprogram (const char *file, char *const argv[])
   return result;
 }
 
+int
+support_subprogram_wait (const char *file, char *const argv[])
+{
+  posix_spawn_file_actions_t fa;
+
+  posix_spawn_file_actions_init (&fa);
+  struct support_subprocess res = support_subprocess_init ();
+
+  res.pid = xposix_spawn (file, &fa, NULL, argv, environ);
+
+  return support_process_wait (&res);
+}
+
 int
 support_process_wait (struct support_subprocess *proc)
 {
index c6df641876285bb29b2b5db0176bfe4ec13d898a..e41128c2d43fe9038aee73c9492c5f712f744f1d 100644 (file)
@@ -1,5 +1,6 @@
 /* Temporary file handling for tests.
-   Copyright (C) 1998-2021 Free Software Foundation, Inc.
+   Copyright (C) 1998-2022 Free Software Foundation, Inc.
+   Copyright The GNU Tools Authors.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
    some 32-bit platforms. */
 #define _FILE_OFFSET_BITS 64
 
+#include <support/check.h>
 #include <support/temp_file.h>
 #include <support/temp_file-internal.h>
 #include <support/support.h>
 
+#include <errno.h>
 #include <paths.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <unistd.h>
+#include <xunistd.h>
 
 /* List of temporary files.  */
 static struct temp_name_list
@@ -36,14 +39,20 @@ static struct temp_name_list
   struct temp_name_list *next;
   char *name;
   pid_t owner;
+  bool toolong;
 } *temp_name_list;
 
 /* Location of the temporary files.  Set by the test skeleton via
    support_set_test_dir.  The string is not be freed.  */
 static const char *test_dir = _PATH_TMP;
 
-void
-add_temp_file (const char *name)
+/* Name of subdirectories in a too long temporary directory tree.  */
+static char toolong_subdir[NAME_MAX + 1];
+static bool toolong_initialized;
+static size_t toolong_path_max;
+
+static void
+add_temp_file_internal (const char *name, bool toolong)
 {
   struct temp_name_list *newp
     = (struct temp_name_list *) xcalloc (sizeof (*newp), 1);
@@ -53,12 +62,19 @@ add_temp_file (const char *name)
       newp->name = newname;
       newp->next = temp_name_list;
       newp->owner = getpid ();
+      newp->toolong = toolong;
       temp_name_list = newp;
     }
   else
     free (newp);
 }
 
+void
+add_temp_file (const char *name)
+{
+  add_temp_file_internal (name, false);
+}
+
 int
 create_temp_file_in_dir (const char *base, const char *dir, char **filename)
 {
@@ -90,8 +106,8 @@ create_temp_file (const char *base, char **filename)
   return create_temp_file_in_dir (base, test_dir, filename);
 }
 
-char *
-support_create_temp_directory (const char *base)
+static char *
+create_temp_directory_internal (const char *base, bool toolong)
 {
   char *path = xasprintf ("%s/%sXXXXXX", test_dir, base);
   if (mkdtemp (path) == NULL)
@@ -99,16 +115,132 @@ support_create_temp_directory (const char *base)
       printf ("error: mkdtemp (\"%s\"): %m", path);
       exit (1);
     }
-  add_temp_file (path);
+  add_temp_file_internal (path, toolong);
   return path;
 }
 
-/* Helper functions called by the test skeleton follow.  */
+char *
+support_create_temp_directory (const char *base)
+{
+  return create_temp_directory_internal (base, false);
+}
+
+static void
+ensure_toolong_initialized (void)
+{
+  if (!toolong_initialized)
+    FAIL_EXIT1 ("uninitialized toolong directory tree\n");
+}
+
+static void
+initialize_toolong (const char *base)
+{
+  long name_max = pathconf (base, _PC_NAME_MAX);
+  name_max = (name_max < 0 ? 64
+             : (name_max < sizeof (toolong_subdir) ? name_max
+                : sizeof (toolong_subdir) - 1));
+
+  long path_max = pathconf (base, _PC_PATH_MAX);
+  path_max = (path_max < 0 ? 1024
+             : path_max <= PTRDIFF_MAX ? path_max : PTRDIFF_MAX);
+
+  /* Sanity check to ensure that the test does not create temporary directories
+     in different filesystems because this API doesn't support it.  */
+  if (toolong_initialized)
+    {
+      if (name_max != strlen (toolong_subdir))
+       FAIL_UNSUPPORTED ("name_max: Temporary directories in different"
+                         " filesystems not supported yet\n");
+      if (path_max != toolong_path_max)
+       FAIL_UNSUPPORTED ("path_max: Temporary directories in different"
+                         " filesystems not supported yet\n");
+      return;
+    }
+
+  toolong_path_max = path_max;
+
+  size_t len = name_max;
+  memset (toolong_subdir, 'X', len);
+  toolong_initialized = true;
+}
+
+char *
+support_create_and_chdir_toolong_temp_directory (const char *basename)
+{
+  char *base = create_temp_directory_internal (basename, true);
+  xchdir (base);
+
+  initialize_toolong (base);
+
+  size_t sz = strlen (toolong_subdir);
+
+  /* Create directories and descend into them so that the final path is larger
+     than PATH_MAX.  */
+  for (size_t i = 0; i <= toolong_path_max / sz; i++)
+    {
+      int ret = mkdir (toolong_subdir, S_IRWXU);
+      if (ret != 0 && errno == ENAMETOOLONG)
+       FAIL_UNSUPPORTED ("Filesystem does not support creating too long "
+                         "directory trees\n");
+      else if (ret != 0)
+       FAIL_EXIT1 ("Failed to create directory tree: %m\n");
+      xchdir (toolong_subdir);
+    }
+  return base;
+}
 
 void
-support_set_test_dir (const char *path)
+support_chdir_toolong_temp_directory (const char *base)
 {
-  test_dir = path;
+  ensure_toolong_initialized ();
+
+  xchdir (base);
+
+  size_t sz = strlen (toolong_subdir);
+  for (size_t i = 0; i <= toolong_path_max / sz; i++)
+    xchdir (toolong_subdir);
+}
+
+/* Helper functions called by the test skeleton follow.  */
+
+static void
+remove_toolong_subdirs (const char *base)
+{
+  ensure_toolong_initialized ();
+
+  if (chdir (base) != 0)
+    {
+      printf ("warning: toolong cleanup base failed: chdir (\"%s\"): %m\n",
+             base);
+      return;
+    }
+
+  /* Descend.  */
+  int levels = 0;
+  size_t sz = strlen (toolong_subdir);
+  for (levels = 0; levels <= toolong_path_max / sz; levels++)
+    if (chdir (toolong_subdir) != 0)
+      {
+       printf ("warning: toolong cleanup failed: chdir (\"%s\"): %m\n",
+               toolong_subdir);
+       break;
+      }
+
+  /* Ascend and remove.  */
+  while (--levels >= 0)
+    {
+      if (chdir ("..") != 0)
+       {
+         printf ("warning: toolong cleanup failed: chdir (\"..\"): %m\n");
+         return;
+       }
+      if (remove (toolong_subdir) != 0)
+       {
+         printf ("warning: could not remove subdirectory: %s: %m\n",
+                 toolong_subdir);
+         return;
+       }
+    }
 }
 
 void
@@ -123,6 +255,9 @@ support_delete_temp_files (void)
         around, to prevent PID reuse.)  */
       if (temp_name_list->owner == pid)
        {
+         if (temp_name_list->toolong)
+           remove_toolong_subdirs (temp_name_list->name);
+
          if (remove (temp_name_list->name) != 0)
            printf ("warning: could not remove temporary file: %s: %m\n",
                    temp_name_list->name);
@@ -147,3 +282,9 @@ support_print_temp_files (FILE *f)
       fprintf (f, ")\n");
     }
 }
+
+void
+support_set_test_dir (const char *path)
+{
+  test_dir = path;
+}
index f3a7fb6f9ca44d19302f483e6dbe850d83789f70..a22964c6fa11abd2d9e60e5841067a828ec4acb2 100644 (file)
@@ -44,6 +44,15 @@ int create_temp_file_in_dir (const char *base, const char *dir,
    returns.  The caller should free this string.  */
 char *support_create_temp_directory (const char *base);
 
+/* Create a temporary directory tree that is longer than PATH_MAX and schedule
+   it for deletion.  BASENAME is used as a prefix for the unique directory
+   name, which the function returns.  The caller should free this string.  */
+char *support_create_and_chdir_toolong_temp_directory (const char *basename);
+
+/* Change into the innermost directory of the directory tree BASE, which was
+   created using support_create_and_chdir_toolong_temp_directory.  */
+void support_chdir_toolong_temp_directory (const char *base);
+
 __END_DECLS
 
 #endif /* SUPPORT_TEMP_FILE_H */
index 28cc44d9f1e28c10e3086f6f5e786ff5340230e9..94498d39019a4776067879c5dd62ef12b2b9e256 100644 (file)
@@ -481,7 +481,7 @@ need_sync (char *ap, char *bp, struct stat *a, struct stat *b)
 }
 
 static void
-rsync_1 (path_buf * src, path_buf * dest, int and_delete)
+rsync_1 (path_buf * src, path_buf * dest, int and_delete, int force_copies)
 {
   DIR *dir;
   struct dirent *de;
@@ -491,8 +491,9 @@ rsync_1 (path_buf * src, path_buf * dest, int and_delete)
   r_append ("/", dest);
 
   if (verbose)
-    printf ("sync %s to %s %s\n", src->buf, dest->buf,
-           and_delete ? "and delete" : "");
+    printf ("sync %s to %s%s%s\n", src->buf, dest->buf,
+           and_delete ? " and delete" : "",
+           force_copies ? " (forced)" : "");
 
   size_t staillen = src->len;
 
@@ -521,10 +522,10 @@ rsync_1 (path_buf * src, path_buf * dest, int and_delete)
         missing.  */
       lstat (dest->buf, &d);
 
-      if (! need_sync (src->buf, dest->buf, &s, &d))
+      if (! force_copies && ! need_sync (src->buf, dest->buf, &s, &d))
        {
          if (S_ISDIR (s.st_mode))
-           rsync_1 (src, dest, and_delete);
+           rsync_1 (src, dest, and_delete, force_copies);
          continue;
        }
 
@@ -559,7 +560,7 @@ rsync_1 (path_buf * src, path_buf * dest, int and_delete)
          if (verbose)
            printf ("+D %s\n", dest->buf);
          maybe_xmkdir (dest->buf, (s.st_mode & 0777) | 0700);
-         rsync_1 (src, dest, and_delete);
+         rsync_1 (src, dest, and_delete, force_copies);
          break;
 
        case S_IFLNK:
@@ -639,12 +640,12 @@ rsync_1 (path_buf * src, path_buf * dest, int and_delete)
 }
 
 static void
-rsync (char *src, char *dest, int and_delete)
+rsync (char *src, char *dest, int and_delete, int force_copies)
 {
   r_setup (src, &spath);
   r_setup (dest, &dpath);
 
-  rsync_1 (&spath, &dpath, and_delete);
+  rsync_1 (&spath, &dpath, and_delete, force_copies);
 }
 
 \f
@@ -846,11 +847,11 @@ main (int argc, char **argv)
     do_ldconfig = true;
 
   rsync (pristine_root_path, new_root_path,
-        file_exists (concat (command_root, "/preclean.req", NULL)));
+        file_exists (concat (command_root, "/preclean.req", NULL)), 0);
 
   if (stat (command_root, &st) >= 0
       && S_ISDIR (st.st_mode))
-    rsync (command_root, new_root_path, 0);
+    rsync (command_root, new_root_path, 0, 1);
 
   new_objdir_path = xstrdup (concat (new_root_path,
                                    support_objdir_root, NULL));
@@ -1044,7 +1045,7 @@ main (int argc, char **argv)
 
          /* Child has exited, we can post-clean the test root.  */
          printf("running post-clean rsync\n");
-         rsync (pristine_root_path, new_root_path, 1);
+         rsync (pristine_root_path, new_root_path, 1, 0);
 
          if (WIFEXITED (status))
            exit (WEXITSTATUS (status));
diff --git a/support/xclone.c b/support/xclone.c
new file mode 100644 (file)
index 0000000..243eee8
--- /dev/null
@@ -0,0 +1,49 @@
+/* Auxiliary functions to issue the clone syscall.
+   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
+   <https://www.gnu.org/licenses/>.  */
+
+#ifdef __linux__
+# include <support/check.h>
+# include <stackinfo.h>  /* For _STACK_GROWS_{UP,DOWN}.  */
+# include <xsched.h>
+
+pid_t
+xclone (int (*fn) (void *arg), void *arg, void *stack, size_t stack_size,
+       int flags)
+{
+  pid_t r = -1;
+
+# ifdef __ia64__
+  extern int __clone2 (int (*fn) (void *arg), void *stack, size_t stack_size,
+                      int flags, void *arg, ...);
+  r = __clone2 (fn, stack, stack_size, flags, arg, /* ptid */ NULL,
+               /* tls */ NULL, /* ctid  */ NULL);
+# else
+#  if _STACK_GROWS_DOWN
+  r = clone (fn, stack + stack_size, flags, arg, /* ptid */ NULL,
+            /* tls */ NULL, /* ctid */  NULL);
+#  elif _STACK_GROWS_UP
+  r = clone (fn, stack, flags, arg, /* ptid */ NULL, /* tls */ NULL, NULL);
+#  endif
+# endif
+
+  if (r < 0)
+    FAIL_EXIT1 ("clone: %m");
+
+  return r;
+}
+#endif
diff --git a/support/xpthread_kill.c b/support/xpthread_kill.c
new file mode 100644 (file)
index 0000000..111a75d
--- /dev/null
@@ -0,0 +1,26 @@
+/* pthread_kill with error checking.
+   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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <signal.h>
+#include <support/xthread.h>
+
+void
+xpthread_kill (pthread_t thr, int signo)
+{
+  xpthread_check_return ("pthread_kill", pthread_kill (thr, signo));
+}
diff --git a/support/xsched.h b/support/xsched.h
new file mode 100644 (file)
index 0000000..eefd731
--- /dev/null
@@ -0,0 +1,34 @@
+/* Wrapper for sched.h functions.
+   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
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef SUPPORT_XSCHED_H
+#define SUPPORT_XSCHED_H
+
+__BEGIN_DECLS
+
+#include <sched.h>
+#include <sys/types.h>
+
+#ifdef __linux__
+pid_t xclone (int (*fn) (void *arg), void *arg, void *stack,
+             size_t stack_size, int flags);
+#endif
+
+__END_DECLS
+
+#endif
index c2086db3475e120e686a607afaae15e47f0671fb..1ba3f133adbfd47946f2ca068781895c22a773a3 100644 (file)
@@ -75,6 +75,8 @@ void xpthread_attr_setstacksize (pthread_attr_t *attr,
 void xpthread_attr_setguardsize (pthread_attr_t *attr,
                                 size_t guardsize);
 
+void xpthread_kill (pthread_t thr, int signo);
+
 /* Return the stack size used on support_set_small_thread_stack_size.  */
 size_t support_small_thread_stack_size (void);
 /* Set the stack size in ATTR to a small value, but still large enough
index aab7245e9330a7829b4cc813c8d528c1a8c4c484..d552a7886ba8dacfd6a3b542e4a43244b8da30db 100644 (file)
@@ -893,6 +893,17 @@ extern int _dl_catch_error (const char **objname, const char **errstring,
                            void *args);
 libc_hidden_proto (_dl_catch_error)
 
+
+/* libdl in a secondary namespace (after dlopen) must use
+   _dl_catch_error from the main namespace, so it has to be exported
+   in some way.  Initialized to _rtld_catch_error in rtld.c.  Not in
+   _rtld_global_ro to preserve structure layout.  */
+extern __typeof (_dl_catch_error) *_dl_catch_error_ptr attribute_relro;
+rtld_hidden_proto (_dl_catch_error_ptr)
+
+/* Used for initializing _dl_catch_error_ptr.  */
+extern __typeof__ (_dl_catch_error) _rtld_catch_error attribute_hidden;
+
 /* Call OPERATE (ARGS).  If no error occurs, set *EXCEPTION to zero.
    Otherwise, store a copy of the raised exception in *EXCEPTION,
    which has to be freed by _dl_exception_free.  As a special case, if
index 8c3e9df547804b9da923c5b47fd44cd75386a7f0..9315ba82fab5bd5a5ec9431a23c80690f953b8b7 100644 (file)
@@ -12,7 +12,7 @@ Function: "asin":
 float: 1
 
 Function: "asinh":
-double: 1
+double: 2
 float: 2
 
 Function: "atan":
@@ -80,7 +80,7 @@ double: 1
 float: 1
 
 Function: "cbrt":
-double: 3
+double: 4
 float: 1
 
 Function: Real part of "ccos":
@@ -127,7 +127,7 @@ double: 1
 float: 1
 
 Function: "cosh":
-double: 1
+double: 2
 float: 2
 
 Function: Real part of "cpow":
@@ -177,10 +177,11 @@ double: 1
 float: 1
 
 Function: "erfc":
-double: 3
+double: 5
 float: 3
 
 Function: "exp":
+double: 1
 float: 1
 
 Function: "exp10":
@@ -256,7 +257,7 @@ double: 2
 float: 2
 
 Function: "tgamma":
-double: 5
+double: 9
 float: 8
 
 Function: "y0":
index ecb729da6b8387732e18f88752c1b5c35ed9d6ce..ca96397a4a925b8b21f9661d48253e3dd337a509 100644 (file)
 #define LLL_SHARED     FUTEX_PRIVATE_FLAG
 
 #ifndef __ASSEMBLER__
-
-# if IS_IN (libc) || IS_IN (rtld)
-/* In libc.so or ld.so all futexes are private.  */
-#  define __lll_private_flag(fl, private)                      \
-  ({                                                           \
-    /* Prevent warnings in callers of this macro.  */          \
-    int __lll_private_flag_priv __attribute__ ((unused));      \
-    __lll_private_flag_priv = (private);                       \
-    ((fl) | FUTEX_PRIVATE_FLAG);                               \
-  })
-# else
-#  define __lll_private_flag(fl, private) \
+# define __lll_private_flag(fl, private) \
   (((fl) | FUTEX_PRIVATE_FLAG) ^ (private))
-# endif
 
 # define lll_futex_syscall(nargs, futexp, op, ...)                      \
   ({                                                                    \
index f11644aae746835238c03fc4dd8fc614e5f95ea5..242e4dbe45a4794bf5bb59a45ff07433838a4c9c 100644 (file)
@@ -187,6 +187,13 @@ __getcwd_generic (char *buf, size_t size)
   size_t allocated = size;
   size_t used;
 
+  /* A size of 1 byte is never useful.  */
+  if (allocated == 1)
+    {
+      __set_errno (ERANGE);
+      return NULL;
+    }
+
 #if HAVE_MINIMALLY_WORKING_GETCWD
   /* If AT_FDCWD is not defined, the algorithm below is O(N**2) and
      this is much slower than the system getcwd (at least on
index d1c71a0ca4e83bcf8bbdd8c3bd3854de570bf246..06491b0ef6dba96296675ddd6c959998239e14fb 100644 (file)
@@ -62,11 +62,6 @@ ifeq ($(subdir),misc)
 sysdep_headers += sys/platform/ppc.h
 tests += test-gettimebase
 tests += tst-set_ppr
-
-# This test is expected to run and exit with EXIT_UNSUPPORTED on
-# processors that do not implement the Power ISA 2.06 or greater.
-# But the test makes use of instructions from Power ISA 2.06 and 2.07.
-CFLAGS-tst-set_ppr.c += -Wa,-many
 endif
 
 ifeq ($(subdir),wcsmbs)
index c57bb1c05d02f6636689532526fa11beaeaff5ae..83fdc8e83e94c9220ea85d9a3594c45616f20b8f 100644 (file)
@@ -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);
 
@@ -398,8 +400,9 @@ LT_LABELSUFFIX(name,_name_end): ; \
 #endif
 
 #define RET_SCV \
-    cmpdi r3,0; \
-    bgelr+; \
+    li r9,-4095; \
+    cmpld r3,r9; \
+    bltlr+; \
     neg r3,r3;
 
 #define RET_SC \
index 28c87fcef72bded6e518518f07410a91abfa18cb..d3fc4ab589f4752a71c56c790607e7ff352e9415 100644 (file)
@@ -50,6 +50,7 @@ do_test (void)
   /* Set SAT bit in VSCR register.  */
   asm volatile (".machine push;\n"
                ".machine \"power5\";\n"
+               ".machine altivec;\n"
                "vspltisb %0,0;\n"
                "vspltisb %1,-1;\n"
                "vpkuwus %0,%0,%1;\n"
index 7684f5d6ea905c6030e69fab507e490eeb9eecd2..e80da1532063558524bbe04b7f1c492da9eeaa0d 100644 (file)
@@ -44,7 +44,8 @@ get_thread_priority (void)
 {
   /* Read the PPR.  */
   ppr_t ppr;
-  asm volatile (MFPPR" %0" : "=r"(ppr));
+  asm volatile (".machine push; .machine power7; "MFPPR" %0; .machine pop"
+               : "=r"(ppr));
   /* Return the thread priority value.  */
   return EXTRACT_THREAD_PRIORITY (ppr);
 }
index eeb64f9fb0480ccc9919bb9a25a789278b6fc623..2df947cb0d0ea4917f776e2b18e3b601f43969ca 100644 (file)
@@ -108,6 +108,7 @@ 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 \
 
 
 # Files which must not be linked with libpthread.
@@ -231,7 +232,7 @@ generated += $(objpfx)tst-atfork2.mtrace \
 
 tests-internal += tst-cancel25 tst-robust8
 
-tests += tst-oncex3 tst-oncex4
+tests += tst-oncex3 tst-oncex4 tst-oncey3 tst-oncey4
 
 modules-names += tst-join7mod
 
@@ -242,6 +243,8 @@ endif
 
 CFLAGS-tst-oncex3.c += -fexceptions
 CFLAGS-tst-oncex4.c += -fexceptions
+CFLAGS-tst-oncey3.c += -fno-exceptions -fno-asynchronous-unwind-tables
+CFLAGS-tst-oncey4.c += -fno-exceptions -fno-asynchronous-unwind-tables
 
 $(objpfx)tst-join7: $(libdl) $(shared-thread-library)
 $(objpfx)tst-join7.out: $(objpfx)tst-join7mod.so
diff --git a/sysdeps/pthread/tst-oncey3.c b/sysdeps/pthread/tst-oncey3.c
new file mode 100644 (file)
index 0000000..08225b8
--- /dev/null
@@ -0,0 +1 @@
+#include "tst-once3.c"
diff --git a/sysdeps/pthread/tst-oncey4.c b/sysdeps/pthread/tst-oncey4.c
new file mode 100644 (file)
index 0000000..9b4d98f
--- /dev/null
@@ -0,0 +1 @@
+#include "tst-once4.c"
diff --git a/sysdeps/pthread/tst-pthread-exit-signal.c b/sysdeps/pthread/tst-pthread-exit-signal.c
new file mode 100644 (file)
index 0000000..b4526fe
--- /dev/null
@@ -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
+   <https://www.gnu.org/licenses/>.  */
+
+/* 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 <support/xthread.h>
+#include <support/xsignal.h>
+
+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 <support/test-driver.c>
index 5b6f121ac5d0530da5528d6cbd593b081b8e6426..a0085bcdbf1bf4e2a9e49fed2b38166a9974c9e9 100644 (file)
@@ -60,7 +60,7 @@ float: 1
 ldouble: 2
 
 Function: "asinh":
-double: 1
+double: 2
 float: 2
 ldouble: 3
 
@@ -413,7 +413,7 @@ float: 1
 ldouble: 2
 
 Function: "cbrt":
-double: 3
+double: 4
 float: 1
 ldouble: 1
 
@@ -652,17 +652,17 @@ float: 1
 ldouble: 2
 
 Function: "cosh":
-double: 1
+double: 2
 float: 2
 ldouble: 1
 
 Function: "cosh_downward":
-double: 2
+double: 3
 float: 1
 ldouble: 2
 
 Function: "cosh_towardzero":
-double: 2
+double: 3
 float: 1
 ldouble: 2
 
@@ -948,6 +948,7 @@ float: 4
 ldouble: 5
 
 Function: "exp":
+double: 1
 float: 1
 ldouble: 1
 
@@ -1068,7 +1069,7 @@ ldouble: 4
 Function: "j0_towardzero":
 double: 5
 float: 6
-ldouble: 2
+ldouble: 4
 
 Function: "j0_upward":
 double: 4
@@ -1136,6 +1137,7 @@ float: 5
 ldouble: 8
 
 Function: "log":
+double: 1
 ldouble: 1
 
 Function: "log10":
@@ -1274,7 +1276,7 @@ float: 3
 ldouble: 3
 
 Function: "sinh_towardzero":
-double: 2
+double: 3
 float: 2
 ldouble: 3
 
@@ -1323,22 +1325,22 @@ float: 3
 ldouble: 3
 
 Function: "tgamma":
-double: 5
+double: 9
 float: 8
 ldouble: 4
 
 Function: "tgamma_downward":
-double: 5
+double: 8
 float: 7
 ldouble: 5
 
 Function: "tgamma_towardzero":
-double: 5
+double: 9
 float: 7
 ldouble: 5
 
 Function: "tgamma_upward":
-double: 4
+double: 9
 float: 8
 ldouble: 4
 
index 5f98640d0fc542644e51c03f0e6bf2ce09c3b130..7eaefbabcfebdce772698bec5de45fbdce65ddc4 100644 (file)
@@ -123,7 +123,9 @@ void testinsn (char *buf)
     __asm__ (".machine \"arch13\" \n\t"
             ".machinemode \"zarch_nohighgprs\" \n\t"
             "lghi %%r0,16 \n\t"
-            "mvcrl 0(%0),32(%0)" : : "a" (buf) : "memory", "r0");
+            "mvcrl 0(%0),32(%0) \n\t"
+            "vstrs %%v20,%%v20,%%v20,%%v20,0,2"
+            : : "a" (buf) : "memory", "r0");
 }
 EOF
 if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS --shared conftest.c
@@ -271,7 +273,9 @@ else
 void testinsn (char *buf)
 {
     __asm__ ("lghi %%r0,16 \n\t"
-            "mvcrl 0(%0),32(%0)" : : "a" (buf) : "memory", "r0");
+            "mvcrl 0(%0),32(%0) \n\t"
+            "vstrs %%v20,%%v20,%%v20,%%v20,0,2"
+            : : "a" (buf) : "memory", "r0");
 }
 EOF
 if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS --shared conftest.c
index dfe007a774d7e1ed5fba267fc087e05707bbb7ba..e6df62491907c8b5562a0942ca7c9d533a4ec486 100644 (file)
@@ -88,7 +88,9 @@ void testinsn (char *buf)
     __asm__ (".machine \"arch13\" \n\t"
             ".machinemode \"zarch_nohighgprs\" \n\t"
             "lghi %%r0,16 \n\t"
-            "mvcrl 0(%0),32(%0)" : : "a" (buf) : "memory", "r0");
+            "mvcrl 0(%0),32(%0) \n\t"
+            "vstrs %%v20,%%v20,%%v20,%%v20,0,2"
+            : : "a" (buf) : "memory", "r0");
 }
 EOF
 dnl test, if assembler supports S390 arch13 instructions
@@ -195,7 +197,9 @@ cat > conftest.c <<\EOF
 void testinsn (char *buf)
 {
     __asm__ ("lghi %%r0,16 \n\t"
-            "mvcrl 0(%0),32(%0)" : : "a" (buf) : "memory", "r0");
+            "mvcrl 0(%0),32(%0) \n\t"
+            "vstrs %%v20,%%v20,%%v20,%%v20,0,2"
+            : : "a" (buf) : "memory", "r0");
 }
 EOF
 dnl test, if assembler supports S390 arch13 zarch instructions as default
index 0c334a2551c79be8a018e8360f9e3a286f35f6b7..155f0bd99eccb3f9b51abd4206956ca5d677b6de 100644 (file)
 #if !defined PROCINFO_DECL && defined SHARED
   ._dl_s390_cap_flags
 #else
-PROCINFO_CLASS const char _dl_s390_cap_flags[19][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"
+     "highgprs", "te", "vx", "vxd", "vxe", "gs", "vxe2", "vxp", "sort", "dflt",
+     "vxp2", "nnpa", "pcimio", "sie"
   }
 #endif
 #if !defined SHARED || defined PROCINFO_DECL
index 9e1a8c7ba9b8e01b62021df714510b9f5411f379..e4e3e334a5b3d47c01e2e5afdca46b5a8d0011a0 100644 (file)
@@ -21,7 +21,7 @@
 #define _DL_PROCINFO_H 1
 #include <ldsodefs.h>
 
-#define _DL_HWCAP_COUNT 19
+#define _DL_HWCAP_COUNT 23
 
 #define _DL_PLATFORMS_COUNT    10
 
@@ -61,6 +61,10 @@ enum
   HWCAP_S390_VXRS_PDE = 1 << 16,
   HWCAP_S390_SORT = 1 << 17,
   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 \
index c5c8d8c97efb3b9f0b0add13778144423d83dbd5..58df8cdb142a6b25577a19b3888355918c41a800 100644 (file)
@@ -41,7 +41,7 @@ ENTRY(MEMMEM_ARCH13)
 #  error The arch13 variant of memmem needs the z13 variant of memmem!
 # endif
        clgfi   %r5,9
-       j     MEMMEM_Z13
+       jgh     MEMMEM_Z13
 
        aghik   %r0,%r5,-1              /* vll needs highest index.  */
        bc      4,0(%r14)               /* cc==1: return if needle-len == 0.  */
index f88ea79d97a3b547a20aa2c3d33559f1af1cbf6b..1a7d3369f21e4a4e69fa250dc947e91f4d8b8488 100644 (file)
@@ -43,7 +43,7 @@ extern __typeof (__redirect_memmove) MEMMOVE_ARCH13 attribute_hidden;
 s390_libc_ifunc_expr (__redirect_memmove, memmove,
                      ({
                        s390_libc_ifunc_expr_stfle_init ();
-                       (HAVE_MEMMOVE_ARCH13
+                       (HAVE_MEMMOVE_ARCH13 && (hwcap & HWCAP_S390_VXRS_EXT2)
                         && S390_IS_ARCH13_MIE3 (stfle_bits))
                          ? MEMMOVE_ARCH13
                          : (HAVE_MEMMOVE_Z13 && (hwcap & HWCAP_S390_VX))
index 4b170e4459d917dc77d267958d074d630a7a07fd..2ef38b72ddac7c18d95e1e84fd5da326cc034b5d 100644 (file)
@@ -171,7 +171,8 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
     IFUNC_IMPL (i, name, memmove,
 # if HAVE_MEMMOVE_ARCH13
                IFUNC_IMPL_ADD (array, i, memmove,
-                               S390_IS_ARCH13_MIE3 (stfle_bits),
+                               ((dl_hwcap & HWCAP_S390_VXRS_EXT2)
+                                && S390_IS_ARCH13_MIE3 (stfle_bits)),
                                MEMMOVE_ARCH13)
 # endif
 # if HAVE_MEMMOVE_Z13
index c7183e627c9fa986be7ec116d9586da6a3cc5510..222a6de91abb3fc6348c1ab83ee4e9001b8c0bf2 100644 (file)
@@ -49,7 +49,7 @@ ENTRY(STRSTR_ARCH13)
 #  error The arch13 variant of strstr needs the z13 variant of strstr!
 # endif
        clgfi   %r4,9
-       j     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
index 472eab700d249f6db9034e8a7687a37fa9fdde6a..9531641f8222547c3eec956647fa6c86a1b7c295 100644 (file)
@@ -282,7 +282,12 @@ sysdep_routines += xstatconv internal_statvfs internal_statvfs64 \
 
 sysdep_headers += bits/fcntl-linux.h
 
-tests += tst-fallocate tst-fallocate64 tst-o_path-locks
+tests += \
+  tst-fallocate \
+  tst-fallocate64 \
+  tst-getcwd-smallbuff \
+  tst-o_path-locks \
+# tests
 endif
 
 ifeq ($(subdir),elf)
index c9e63bae48507896a9639f2fe3eb6f954b0a033f..fe04bce6b6747742ec03bd74d2771671f8dfe8ff 100644 (file)
@@ -47,6 +47,8 @@ ENTRY(__clone)
        /* Sanity check args.  */
        mov     x0, #-EINVAL
        cbz     x10, .Lsyscall_error
+       /* Align sp.  */
+       and     x1, x1, -16
        cbz     x1, .Lsyscall_error
 
        /* Do the system call.  */
index fe52b6308ee0ff720780aec0399ac823b2ebbc25..db6aa3516c1b5cb196dae53ac5cad6786b41834c 100644 (file)
@@ -104,7 +104,7 @@ init_cpu_features (struct cpu_features *cpu_features)
   cpu_features->mte_state = (GLRO (dl_hwcap2) & HWCAP2_MTE) ? mte_state : 0;
   /* If we lack the MTE feature, disable the tunable, since it will
      otherwise cause instructions that won't run on this CPU to be used.  */
-  TUNABLE_SET (glibc, mem, tagging, unsigned, cpu_features->mte_state);
+  TUNABLE_SET (glibc, mem, tagging, cpu_features->mte_state);
 # endif
 
   if (cpu_features->mte_state & 2)
diff --git a/sysdeps/unix/sysv/linux/dl-diagnostics-kernel.c b/sysdeps/unix/sysv/linux/dl-diagnostics-kernel.c
new file mode 100644 (file)
index 0000000..59f6402
--- /dev/null
@@ -0,0 +1,77 @@
+/* Print kernel diagnostics data in ld.so.  Linux 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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <dl-diagnostics.h>
+#include <ldsodefs.h>
+#include <sys/utsname.h>
+
+/* Dump the auxiliary vector to standard output.  */
+static void
+print_auxv (void)
+{
+  /* See _dl_show_auxv.  The code below follows the general output
+     format for diagnostic dumps.  */
+  unsigned int index = 0;
+  for (ElfW(auxv_t) *av = GLRO(dl_auxv); av->a_type != AT_NULL; ++av)
+    {
+      _dl_printf ("auxv[0x%x].a_type=0x%lx\n"
+                  "auxv[0x%x].a_val=",
+                  index, (unsigned long int) av->a_type, index);
+      if (av->a_type == AT_EXECFN
+          || av->a_type == AT_PLATFORM
+          || av->a_type == AT_BASE_PLATFORM)
+        /* The address of the strings is not useful at all, so print
+           the strings themselvs.  */
+        _dl_diagnostics_print_string ((const char *) av->a_un.a_val);
+      else
+        _dl_printf ("0x%lx", (unsigned long int) av->a_un.a_val);
+      _dl_printf ("\n");
+      ++index;
+    }
+}
+
+/* Print one uname entry.  */
+static void
+print_utsname_entry (const char *field, const char *value)
+{
+  _dl_printf ("uname.");
+  _dl_diagnostics_print_labeled_string (field, value);
+}
+
+/* Print information from uname, including the kernel version.  */
+static void
+print_uname (void)
+{
+  struct utsname uts;
+  if (__uname (&uts) == 0)
+    {
+      print_utsname_entry ("sysname", uts.sysname);
+      print_utsname_entry ("nodename", uts.nodename);
+      print_utsname_entry ("release", uts.release);
+      print_utsname_entry ("version", uts.version);
+      print_utsname_entry ("machine", uts.machine);
+      print_utsname_entry ("domainname", uts.domainname);
+    }
+}
+
+void
+_dl_diagnostics_kernel (void)
+{
+  print_auxv ();
+  print_uname ();
+}
index fd643622054fea2689e6a988a2262b8bd9eae66f..31a172dcc81163e79d1aa480677645bc3677e35c 100644 (file)
 #include <sys/stat.h>
 #include <kernel_stat.h>
 #include <fcntl.h>
+#include <errno.h>
 
 #if !XSTAT_IS_XSTAT64
 int
 __fstat (int fd, struct stat *buf)
 {
+  if (fd < 0)
+    {
+      __set_errno (EBADF);
+      return -1;
+    }
   return __fstatat (fd, "", buf, AT_EMPTY_PATH);
 }
 
index 993abcb4458fa3097411941891e6996d3a2977f9..46de80b663b9c1c402800d8f722dbbc2d0f24431 100644 (file)
 #include <fcntl.h>
 #include <kernel_stat.h>
 #include <stat_t64_cp.h>
+#include <errno.h>
 
 int
 __fstat64_time64 (int fd, struct __stat64_t64 *buf)
 {
+  if (fd < 0)
+    {
+      __set_errno (EBADF);
+      return -1;
+    }
   return __fstatat64_time64 (fd, "", buf, AT_EMPTY_PATH);
 }
 #if __TIMESIZE != 64
@@ -34,6 +40,12 @@ hidden_def (__fstat64_time64)
 int
 __fstat64 (int fd, struct stat64 *buf)
 {
+  if (fd < 0)
+    {
+      __set_errno (EBADF);
+      return -1;
+    }
+
   struct __stat64_t64 st_t64;
   return __fstat64_time64 (fd, &st_t64)
         ?: __cp_stat64_t64_stat64 (&st_t64, buf);
index 11511d30b38708ceabbc9b06abc2df55393961d7..4a6016ff123e8dd962dfbec926f595d40e9e2f9f 100644 (file)
@@ -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);
       }
     }
 }
index 871fb6c6c58866651a59617383e212d68dcf2258..54f990a250677091c2067d9118d57707c10d1342 100644 (file)
@@ -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);
       }
     }
 }
index 9d810b6f653b964bf91c8226942d10a48fe926bb..86f4dc31a82ff1bb27da22cf7a62e9ed3d5335a6 100644 (file)
@@ -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);
       }
     }
 }
index cc575a0cdd80c6a674556b14a09dbd8e2f0749ea..1714e1cc5f80156be0ee9021c4ac66610de3add4 100644 (file)
@@ -132,9 +132,12 @@ helper_thread (void *arg)
               to wait until it is done with it.  */
            (void) __pthread_barrier_wait (&notify_barrier);
        }
-      else if (data.raw[NOTIFY_COOKIE_LEN - 1] == NOTIFY_REMOVED)
-       /* The only state we keep is the copy of the thread attributes.  */
-       free (data.attr);
+      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);
+         free (data.attr);
+       }
     }
   return NULL;
 }
@@ -255,8 +258,14 @@ mq_notify (mqd_t mqdes, const struct sigevent *notification)
       if (data.attr == NULL)
        return -1;
 
-      memcpy (data.attr, notification->sigev_notify_attributes,
-             sizeof (pthread_attr_t));
+      int ret = __pthread_attr_copy (data.attr,
+                                    notification->sigev_notify_attributes);
+      if (ret != 0)
+       {
+         free (data.attr);
+         __set_errno (ret);
+         return -1;
+       }
     }
 
   /* Construct the new request.  */
@@ -269,8 +278,11 @@ mq_notify (mqd_t mqdes, const struct sigevent *notification)
   int retval = INLINE_SYSCALL (mq_notify, 2, mqdes, &se);
 
   /* If it failed, free the allocated memory.  */
-  if (__glibc_unlikely (retval != 0))
-    free (data.attr);
+  if (retval != 0 && data.attr != NULL)
+    {
+      pthread_attr_destroy (data.attr);
+      free (data.attr);
+    }
 
   return retval;
 }
index d6ec87f00655919e0dea7630ddf88ab8abcf92d2..d06e776ca438b3af21f426907ec673c43b50ac47 100644 (file)
@@ -27,7 +27,11 @@ ENTRY (syscall)
        mr   r8,r9
 #if !IS_IN(rtld) && (defined(__PPC64__) || defined(__powerpc64__))
        CHECK_SCV_SUPPORT r9 0f
+       stdu r1,-SCV_FRAME_SIZE(r1)
+       cfi_adjust_cfa_offset(SCV_FRAME_SIZE)
        DO_CALL_SCV
+       addi r1,r1,SCV_FRAME_SIZE
+       cfi_adjust_cfa_offset(-SCV_FRAME_SIZE)
        RET_SCV
        b 1f
 #endif
index 696616e77923f6542efcbb3494d382bc60cc5ffb..00e73a3e3bfdb711b6f743058c5a629869e4a12e 100644 (file)
 
 /*
  * 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
@@ -46,3 +51,7 @@
 #define HWCAP_S390_VXRS_PDE     65536
 #define HWCAP_S390_SORT         131072
 #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
index 415aa87d3c87d70c2ad8aeeb034f738a20420c7b..dc16a816ed9e5f9bb2d28a15020be4a9917122c1 100644 (file)
@@ -33,13 +33,35 @@ int
 __select64 (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
            struct __timeval64 *timeout)
 {
-  struct __timespec64 ts64, *pts64 = NULL;
-  if (timeout != NULL)
+  __time64_t s = timeout != NULL ? timeout->tv_sec : 0;
+  int32_t us = timeout != NULL ? timeout->tv_usec : 0;
+  int32_t ns;
+
+  if (s < 0 || us < 0)
+    return INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL);
+
+  /* Normalize the timeout, as legacy Linux __NR_select and __NR__newselect.
+     Different than syscall, it also handle possible overflow.  */
+  if (us / USEC_PER_SEC > INT64_MAX - s)
+    {
+      s = INT64_MAX;
+      ns = NSEC_PER_SEC - 1;
+    }
+  else
     {
-      ts64 = timeval64_to_timespec64 (*timeout);
-      pts64 = &ts64;
+      s += us / USEC_PER_SEC;
+      us = us % USEC_PER_SEC;
+      ns = us * NSEC_PER_USEC;
     }
 
+  struct __timespec64 ts64, *pts64 = NULL;
+   if (timeout != NULL)
+     {
+       ts64.tv_sec = s;
+       ts64.tv_nsec = ns;
+       pts64 = &ts64;
+     }
+
 #ifndef __NR_pselect6_time64
 # define __NR_pselect6_time64 __NR_pselect6
 #endif
@@ -52,10 +74,10 @@ __select64 (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
          (though the pselect() glibc call suppresses this behavior).
          Since select() on Linux has the same behavior as the pselect6
          syscall, we update the timeout here.  */
-      if (r == 0 || errno != ENOSYS)
+      if (r >= 0 || errno != ENOSYS)
        {
          if (timeout != NULL)
-           TIMEVAL_TO_TIMESPEC (timeout, &ts64);
+           TIMESPEC_TO_TIMEVAL (timeout, &ts64);
          return r;
        }
 
@@ -64,14 +86,15 @@ __select64 (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
 
 #ifndef __ASSUME_TIME64_SYSCALLS
   struct timespec ts32, *pts32 = NULL;
-  if (timeout != NULL)
+  if (pts64 != NULL)
     {
-      if (! in_time_t_range (timeout->tv_sec))
+      if (! in_time_t_range (pts64->tv_sec))
        {
          __set_errno (EINVAL);
          return -1;
        }
-      ts32 = valid_timespec64_to_timespec (ts64);
+      ts32.tv_sec = s;
+      ts32.tv_nsec = ns;
       pts32 = &ts32;
     }
 # ifndef __ASSUME_PSELECT
@@ -84,7 +107,7 @@ __select64 (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
   r = SYSCALL_CANCEL (pselect6, nfds, readfds, writefds, exceptfds, pts32,
                      NULL);
 # endif
-  if (r >= 0 && timeout != NULL)
+  if (timeout != NULL)
     *timeout = valid_timespec_to_timeval64 (ts32);
 #endif
 
@@ -105,7 +128,7 @@ __select (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
       ptv64 = &tv64;
     }
   int r = __select64 (nfds, readfds, writefds, exceptfds, ptv64);
-  if (r >= 0 && timeout != NULL)
+  if (timeout != NULL)
     /* The remanining timeout will be always less the input TIMEOUT.  */
     *timeout = valid_timeval64_to_timeval (tv64);
   return r;
index 00817ff0f14c617d5a62a2cbb6779ac3e95d8542..c9048c7cdb3e4d2654c74ec32599f6e4a8f8fee5 100644 (file)
    we're picking up...  */
 
 /* Memory tagging control operations (for AArch64).  */
-#ifndef PR_TAGGED_ADDR_ENABLE
-# define PR_TAGGED_ADDR_ENABLE (1UL << 8)
-#endif
-
 #ifndef PR_MTE_TCF_SHIFT
 # define PR_MTE_TCF_SHIFT      1
 # define PR_MTE_TCF_NONE       (0UL << PR_MTE_TCF_SHIFT)
diff --git a/sysdeps/unix/sysv/linux/tst-getcwd-smallbuff.c b/sysdeps/unix/sysv/linux/tst-getcwd-smallbuff.c
new file mode 100644 (file)
index 0000000..55362f6
--- /dev/null
@@ -0,0 +1,259 @@
+/* Verify that getcwd returns ERANGE for size 1 byte and does not underflow
+   buffer when the CWD is too long and is also a mount target of /.  See bug
+   #28769 or CVE-2021-3999 for more context.
+   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
+   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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <intprops.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <support/check.h>
+#include <support/temp_file.h>
+#include <support/test-driver.h>
+#include <support/xsched.h>
+#include <support/xunistd.h>
+
+static char *base;
+#define BASENAME "tst-getcwd-smallbuff"
+#define MOUNT_NAME "mpoint"
+static int sockfd[2];
+
+static void
+do_cleanup (void)
+{
+  support_chdir_toolong_temp_directory (base);
+  TEST_VERIFY_EXIT (rmdir (MOUNT_NAME) == 0);
+  free (base);
+}
+
+static void
+send_fd (const int sock, const int fd)
+{
+  struct msghdr msg = {0};
+  union
+    {
+      struct cmsghdr hdr;
+      char buf[CMSG_SPACE (sizeof (int))];
+    } cmsgbuf = {0};
+  struct cmsghdr *cmsg;
+  struct iovec vec;
+  char ch = 'A';
+  ssize_t n;
+
+  msg.msg_control = &cmsgbuf.buf;
+  msg.msg_controllen = sizeof (cmsgbuf.buf);
+
+  cmsg = CMSG_FIRSTHDR (&msg);
+  cmsg->cmsg_len = CMSG_LEN (sizeof (int));
+  cmsg->cmsg_level = SOL_SOCKET;
+  cmsg->cmsg_type = SCM_RIGHTS;
+  memcpy (CMSG_DATA (cmsg), &fd, sizeof (fd));
+
+  vec.iov_base = &ch;
+  vec.iov_len = 1;
+  msg.msg_iov = &vec;
+  msg.msg_iovlen = 1;
+
+  while ((n = sendmsg (sock, &msg, 0)) == -1 && errno == EINTR);
+
+  TEST_VERIFY_EXIT (n == 1);
+}
+
+static int
+recv_fd (const int sock)
+{
+  struct msghdr msg = {0};
+  union
+    {
+      struct cmsghdr hdr;
+      char buf[CMSG_SPACE(sizeof(int))];
+    } cmsgbuf = {0};
+  struct cmsghdr *cmsg;
+  struct iovec vec;
+  ssize_t n;
+  char ch = '\0';
+  int fd = -1;
+
+  vec.iov_base = &ch;
+  vec.iov_len = 1;
+  msg.msg_iov = &vec;
+  msg.msg_iovlen = 1;
+
+  msg.msg_control = &cmsgbuf.buf;
+  msg.msg_controllen = sizeof (cmsgbuf.buf);
+
+  while ((n = recvmsg (sock, &msg, 0)) == -1 && errno == EINTR);
+  if (n != 1 || ch != 'A')
+    return -1;
+
+  cmsg = CMSG_FIRSTHDR (&msg);
+  if (cmsg == NULL)
+    return -1;
+  if (cmsg->cmsg_type != SCM_RIGHTS)
+    return -1;
+  memcpy (&fd, CMSG_DATA (cmsg), sizeof (fd));
+  if (fd < 0)
+    return -1;
+  return fd;
+}
+
+static int
+child_func (void * const arg)
+{
+  xclose (sockfd[0]);
+  const int sock = sockfd[1];
+  char ch;
+
+  TEST_VERIFY_EXIT (read (sock, &ch, 1) == 1);
+  TEST_VERIFY_EXIT (ch == '1');
+
+  if (mount ("/", MOUNT_NAME, NULL, MS_BIND | MS_REC, NULL))
+    FAIL_EXIT1 ("mount failed: %m\n");
+  const int fd = xopen ("mpoint",
+                       O_RDONLY | O_PATH | O_DIRECTORY | O_NOFOLLOW, 0);
+
+  send_fd (sock, fd);
+  xclose (fd);
+
+  TEST_VERIFY_EXIT (read (sock, &ch, 1) == 1);
+  TEST_VERIFY_EXIT (ch == 'a');
+
+  xclose (sock);
+  return 0;
+}
+
+static void
+update_map (char * const mapping, const char * const map_file)
+{
+  const size_t map_len = strlen (mapping);
+
+  const int fd = xopen (map_file, O_WRONLY, 0);
+  xwrite (fd, mapping, map_len);
+  xclose (fd);
+}
+
+static void
+proc_setgroups_write (const long child_pid, const char * const str)
+{
+  const size_t str_len = strlen(str);
+
+  char setgroups_path[sizeof ("/proc//setgroups") + INT_STRLEN_BOUND (long)];
+
+  snprintf (setgroups_path, sizeof (setgroups_path),
+           "/proc/%ld/setgroups", child_pid);
+
+  const int fd = open (setgroups_path, O_WRONLY);
+
+  if (fd < 0)
+    {
+      TEST_VERIFY_EXIT (errno == ENOENT);
+      FAIL_UNSUPPORTED ("/proc/%ld/setgroups not found\n", child_pid);
+    }
+
+  xwrite (fd, str, str_len);
+  xclose(fd);
+}
+
+static char child_stack[1024 * 1024];
+
+int
+do_test (void)
+{
+  base = support_create_and_chdir_toolong_temp_directory (BASENAME);
+
+  xmkdir (MOUNT_NAME, S_IRWXU);
+  atexit (do_cleanup);
+
+  /* Check whether user namespaces are supported.  */
+  {
+    pid_t pid = xfork ();
+    if (pid == 0)
+      {
+       if (unshare (CLONE_NEWUSER | CLONE_NEWNS) != 0)
+         _exit (EXIT_UNSUPPORTED);
+       else
+         _exit (0);
+      }
+    int status;
+    xwaitpid (pid, &status, 0);
+    TEST_VERIFY_EXIT (WIFEXITED (status));
+    if (WEXITSTATUS (status) != 0)
+      return WEXITSTATUS (status);
+  }
+
+  TEST_VERIFY_EXIT (socketpair (AF_UNIX, SOCK_STREAM, 0, sockfd) == 0);
+  pid_t child_pid = xclone (child_func, NULL, child_stack,
+                           sizeof (child_stack),
+                           CLONE_NEWUSER | CLONE_NEWNS | SIGCHLD);
+
+  xclose (sockfd[1]);
+  const int sock = sockfd[0];
+
+  char map_path[sizeof ("/proc//uid_map") + INT_STRLEN_BOUND (long)];
+  char map_buf[sizeof ("0  1") + INT_STRLEN_BOUND (long)];
+
+  snprintf (map_path, sizeof (map_path), "/proc/%ld/uid_map",
+           (long) child_pid);
+  snprintf (map_buf, sizeof (map_buf), "0 %ld 1", (long) getuid());
+  update_map (map_buf, map_path);
+
+  proc_setgroups_write ((long) child_pid, "deny");
+  snprintf (map_path, sizeof (map_path), "/proc/%ld/gid_map",
+           (long) child_pid);
+  snprintf (map_buf, sizeof (map_buf), "0 %ld 1", (long) getgid());
+  update_map (map_buf, map_path);
+
+  TEST_VERIFY_EXIT (send (sock, "1", 1, MSG_NOSIGNAL) == 1);
+  const int fd = recv_fd (sock);
+  TEST_VERIFY_EXIT (fd >= 0);
+  TEST_VERIFY_EXIT (fchdir (fd) == 0);
+
+  static char buf[2 * 10 + 1];
+  memset (buf, 'A', sizeof (buf));
+
+  /* Finally, call getcwd and check if it resulted in a buffer underflow.  */
+  char * cwd = getcwd (buf + sizeof (buf) / 2, 1);
+  TEST_VERIFY (cwd == NULL);
+  TEST_VERIFY (errno == ERANGE);
+
+  for (int i = 0; i < sizeof (buf); i++)
+    if (buf[i] != 'A')
+      {
+       printf ("buf[%d] = %02x\n", i, (unsigned int) buf[i]);
+       support_record_failure ();
+      }
+
+  TEST_VERIFY_EXIT (send (sock, "a", 1, MSG_NOSIGNAL) == 1);
+  xclose (sock);
+  TEST_VERIFY_EXIT (xwaitpid (child_pid, NULL, 0) == child_pid);
+
+  return 0;
+}
+
+#define CLEANUP_HANDLER do_cleanup
+#include <support/test-driver.c>
index 2f05f21e4a3895699739833e93c2a9be6376accb..110a7c1437a0bdce4ca8efc10516f5534619360f 100644 (file)
@@ -122,18 +122,21 @@ do_test (void)
   if (shmid == -1)
     FAIL_EXIT1 ("shmget failed: %m");
 
+  /* It does not check shmmax because kernel clamp its value to INT_MAX for:
+
+     1. Compat symbols with IPC_64, i.e, 32-bit binaries running on 64-bit
+        kernels.
+
+     2. Default symbol without IPC_64 (defined as IPC_OLD within Linux) and
+        glibc always use IPC_64 for 32-bit ABIs (to support 64-bit time_t).
+        It means that 32-bit binaries running on 32-bit kernels will not see
+        shmmax being clamped.
+
+     And finding out whether the compat symbol is used would require checking
+     the underlying kernel against the current ABI.  The shmall and shmmni
+     already provided enough coverage.  */
+
   struct test_shminfo tipcinfo;
-  {
-    uint64_t v = read_proc_file ("/proc/sys/kernel/shmmax");
-#if LONG_MAX == INT_MAX
-    /* Kernel explicit clamp the value for shmmax on compat symbol (32-bit
-       binaries running on 64-bit kernels).  */
-    if (sizeof (__syscall_ulong_t) == sizeof (unsigned long int)
-        && v > INT_MAX)
-      v = INT_MAX;
-#endif
-    tipcinfo.shmmax = v;
-  }
   tipcinfo.shmall = read_proc_file ("/proc/sys/kernel/shmall");
   tipcinfo.shmmni = read_proc_file ("/proc/sys/kernel/shmmni");
 
@@ -152,7 +155,6 @@ do_test (void)
       FAIL_EXIT1 ("shmctl with IPC_INFO failed: %m");
 
     TEST_COMPARE (ipcinfo.shmall, tipcinfo.shmall);
-    TEST_COMPARE (ipcinfo.shmmax, tipcinfo.shmmax);
     TEST_COMPARE (ipcinfo.shmmni, tipcinfo.shmmni);
   }
 
index dd826743426ffc9c9bc3756f2c703724f0a454a6..d231263051f1c24235c6f2e540abc6ee9a4cc5fb 100644 (file)
@@ -208,3 +208,11 @@ $(objpfx)check-cet.out: $(..)sysdeps/x86/check-cet.awk \
 generated += check-cet.out
 endif
 endif
+
+ifeq ($(subdir),posix)
+tests += \
+  tst-sysconf-cache-linesize \
+  tst-sysconf-cache-linesize-static
+tests-static += \
+  tst-sysconf-cache-linesize-static
+endif
index 7b8df45e3bb6eaa1cd5d5d54501d7006c396ad8f..5ea4723ca69d7b624ac0a9da06105886fd4d78f7 100644 (file)
@@ -32,6 +32,9 @@ __cache_sysconf (int name)
     case _SC_LEVEL1_ICACHE_SIZE:
       return cpu_features->level1_icache_size;
 
+    case _SC_LEVEL1_ICACHE_LINESIZE:
+      return cpu_features->level1_icache_linesize;
+
     case _SC_LEVEL1_DCACHE_SIZE:
       return cpu_features->level1_dcache_size;
 
index 68c253542ff2e66c181fa97d7e0dbcd349f8eb18..0f850bdf12087e151c4232dbc0790fe062c262c7 100644 (file)
@@ -63,16 +63,22 @@ init_cacheinfo (void)
   __x86_raw_data_cache_size = data;
   /* Round data cache size to multiple of 256 bytes.  */
   data = data & ~255L;
-  __x86_data_cache_size_half = data / 2;
-  __x86_data_cache_size = data;
+  if (data > 0)
+    {
+      __x86_data_cache_size_half = data / 2;
+      __x86_data_cache_size = data;
+    }
 
   long int shared = cpu_features->shared_cache_size;
   __x86_raw_shared_cache_size_half = shared / 2;
   __x86_raw_shared_cache_size = shared;
   /* Round shared cache size to multiple of 256 bytes.  */
   shared = shared & ~255L;
-  __x86_shared_cache_size_half = shared / 2;
-  __x86_shared_cache_size = shared;
+  if (shared > 0)
+    {
+      __x86_shared_cache_size_half = shared / 2;
+      __x86_shared_cache_size = shared;
+    }
 
   __x86_shared_non_temporal_threshold
     = cpu_features->non_temporal_threshold;
index 5e32dc62b334b27f87b2f02cde17e544d9b5d9c2..ead1295c38cf5f4ead901d4dfbf8816a55e35326 100644 (file)
@@ -126,6 +126,8 @@ cat > conftest2.S <<EOF
 4:
 EOF
 libc_cv_include_x86_isa_level=no
+libc_cv_have_x86_lahf_sahf=no
+libc_cv_have_x86_movbe=no
 if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS -nostartfiles -nostdlib -r -o conftest conftest1.S conftest2.S'
   { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
   (eval $ac_try) 2>&5
@@ -135,6 +137,24 @@ if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS -nostartfiles -nostdlib -r -o conftest c
   count=`LC_ALL=C $READELF -n conftest | grep NT_GNU_PROPERTY_TYPE_0 | wc -l`
   if test "$count" = 1; then
     libc_cv_include_x86_isa_level=yes
+    cat > conftest.c <<EOF
+EOF
+    if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS -fverbose-asm -S -o - conftest.c'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; } | grep -q "\-msahf"; then
+      libc_cv_have_x86_lahf_sahf=yes
+    fi
+    if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS -fverbose-asm -S -o - conftest.c'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; } | grep -q "\-mmovbe"; then
+      libc_cv_have_x86_movbe=yes
+    fi
   fi
 fi
 rm -f conftest*
@@ -144,6 +164,14 @@ $as_echo "$libc_cv_include_x86_isa_level" >&6; }
 if test $libc_cv_include_x86_isa_level = yes; then
   $as_echo "#define INCLUDE_X86_ISA_LEVEL 1" >>confdefs.h
 
+fi
+if test $libc_cv_have_x86_lahf_sahf = yes; then
+  $as_echo "#define HAVE_X86_LAHF_SAHF 1" >>confdefs.h
+
+fi
+if test $libc_cv_have_x86_movbe = yes; then
+  $as_echo "#define HAVE_X86_MOVBE 1" >>confdefs.h
+
 fi
 config_vars="$config_vars
 enable-x86-isa-level = $libc_cv_include_x86_isa_level"
index f94088f377ec95ab4364c8f7debaa14dd582af30..bca97fdc2f1ac1a72a631272b888470b6e038e03 100644 (file)
@@ -98,14 +98,30 @@ cat > conftest2.S <<EOF
 4:
 EOF
 libc_cv_include_x86_isa_level=no
+libc_cv_have_x86_lahf_sahf=no
+libc_cv_have_x86_movbe=no
 if AC_TRY_COMMAND(${CC-cc} $CFLAGS $CPPFLAGS -nostartfiles -nostdlib -r -o conftest conftest1.S conftest2.S); then
   count=`LC_ALL=C $READELF -n conftest | grep NT_GNU_PROPERTY_TYPE_0 | wc -l`
   if test "$count" = 1; then
     libc_cv_include_x86_isa_level=yes
+    cat > conftest.c <<EOF
+EOF
+    if AC_TRY_COMMAND(${CC-cc} $CFLAGS $CPPFLAGS -fverbose-asm -S -o - conftest.c) | grep -q "\-msahf"; then
+      libc_cv_have_x86_lahf_sahf=yes
+    fi
+    if AC_TRY_COMMAND(${CC-cc} $CFLAGS $CPPFLAGS -fverbose-asm -S -o - conftest.c) | grep -q "\-mmovbe"; then
+      libc_cv_have_x86_movbe=yes
+    fi
   fi
 fi
 rm -f conftest*])
 if test $libc_cv_include_x86_isa_level = yes; then
   AC_DEFINE(INCLUDE_X86_ISA_LEVEL)
 fi
+if test $libc_cv_have_x86_lahf_sahf = yes; then
+  AC_DEFINE(HAVE_X86_LAHF_SAHF)
+fi
+if test $libc_cv_have_x86_movbe = yes; then
+  AC_DEFINE(HAVE_X86_MOVBE)
+fi
 LIBC_CONFIG_VAR([enable-x86-isa-level], [$libc_cv_include_x86_isa_level])
index a31fa0783a23a9d83da746ed964dd2f2d372b858..2ab3acd83e1cfd97251bb13415303c693299f9f1 100644 (file)
@@ -707,6 +707,7 @@ dl_init_cacheinfo (struct cpu_features *cpu_features)
   long int core;
   unsigned int threads = 0;
   unsigned long int level1_icache_size = -1;
+  unsigned long int level1_icache_linesize = -1;
   unsigned long int level1_dcache_size = -1;
   unsigned long int level1_dcache_assoc = -1;
   unsigned long int level1_dcache_linesize = -1;
@@ -726,6 +727,8 @@ dl_init_cacheinfo (struct cpu_features *cpu_features)
 
       level1_icache_size
        = handle_intel (_SC_LEVEL1_ICACHE_SIZE, cpu_features);
+      level1_icache_linesize
+       = handle_intel (_SC_LEVEL1_ICACHE_LINESIZE, cpu_features);
       level1_dcache_size = data;
       level1_dcache_assoc
        = handle_intel (_SC_LEVEL1_DCACHE_ASSOC, cpu_features);
@@ -753,6 +756,7 @@ dl_init_cacheinfo (struct cpu_features *cpu_features)
       shared = handle_zhaoxin (_SC_LEVEL3_CACHE_SIZE);
 
       level1_icache_size = handle_zhaoxin (_SC_LEVEL1_ICACHE_SIZE);
+      level1_icache_linesize = handle_zhaoxin (_SC_LEVEL1_ICACHE_LINESIZE);
       level1_dcache_size = data;
       level1_dcache_assoc = handle_zhaoxin (_SC_LEVEL1_DCACHE_ASSOC);
       level1_dcache_linesize = handle_zhaoxin (_SC_LEVEL1_DCACHE_LINESIZE);
@@ -772,6 +776,7 @@ dl_init_cacheinfo (struct cpu_features *cpu_features)
       shared = handle_amd (_SC_LEVEL3_CACHE_SIZE);
 
       level1_icache_size = handle_amd (_SC_LEVEL1_ICACHE_SIZE);
+      level1_icache_linesize = handle_amd (_SC_LEVEL1_ICACHE_LINESIZE);
       level1_dcache_size = data;
       level1_dcache_assoc = handle_amd (_SC_LEVEL1_DCACHE_ASSOC);
       level1_dcache_linesize = handle_amd (_SC_LEVEL1_DCACHE_LINESIZE);
@@ -833,6 +838,7 @@ dl_init_cacheinfo (struct cpu_features *cpu_features)
     }
 
   cpu_features->level1_icache_size = level1_icache_size;
+  cpu_features->level1_icache_linesize = level1_icache_linesize;
   cpu_features->level1_dcache_size = level1_dcache_size;
   cpu_features->level1_dcache_assoc = level1_dcache_assoc;
   cpu_features->level1_dcache_linesize = level1_dcache_linesize;
@@ -917,17 +923,14 @@ dl_init_cacheinfo (struct cpu_features *cpu_features)
   rep_stosb_threshold = TUNABLE_GET (x86_rep_stosb_threshold,
                                     long int, NULL);
 
-  TUNABLE_SET_WITH_BOUNDS (x86_data_cache_size, long int, data,
-                          0, (long int) -1);
-  TUNABLE_SET_WITH_BOUNDS (x86_shared_cache_size, long int, shared,
-                          0, (long int) -1);
-  TUNABLE_SET_WITH_BOUNDS (x86_non_temporal_threshold, long int,
-                          non_temporal_threshold, 0, (long int) -1);
-  TUNABLE_SET_WITH_BOUNDS (x86_rep_movsb_threshold, long int,
-                          rep_movsb_threshold,
-                          minimum_rep_movsb_threshold, (long int) -1);
-  TUNABLE_SET_WITH_BOUNDS (x86_rep_stosb_threshold, long int,
-                          rep_stosb_threshold, 1, (long int) -1);
+  TUNABLE_SET_WITH_BOUNDS (x86_data_cache_size, data, 0, SIZE_MAX);
+  TUNABLE_SET_WITH_BOUNDS (x86_shared_cache_size, shared, 0, SIZE_MAX);
+  TUNABLE_SET_WITH_BOUNDS (x86_non_temporal_threshold, non_temporal_threshold,
+                          0, SIZE_MAX);
+  TUNABLE_SET_WITH_BOUNDS (x86_rep_movsb_threshold, rep_movsb_threshold,
+                          minimum_rep_movsb_threshold, SIZE_MAX);
+  TUNABLE_SET_WITH_BOUNDS (x86_rep_stosb_threshold, rep_stosb_threshold, 1,
+                          SIZE_MAX);
 #endif
 
   cpu_features->data_cache_size = data;
diff --git a/sysdeps/x86/dl-diagnostics-cpu.c b/sysdeps/x86/dl-diagnostics-cpu.c
new file mode 100644 (file)
index 0000000..af84864
--- /dev/null
@@ -0,0 +1,118 @@
+/* Print CPU diagnostics data in ld.so.  x86 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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <dl-diagnostics.h>
+#include <ldsodefs.h>
+
+static void
+print_cpu_features_value (const char *label, uint64_t value)
+{
+  _dl_printf ("x86.cpu_features.");
+  _dl_diagnostics_print_labeled_value (label, value);
+}
+
+static void
+print_cpu_feature_internal (unsigned int index, const char *kind,
+                            unsigned int reg, uint32_t value)
+{
+  _dl_printf ("x86.cpu_features.features[0x%x].%s[0x%x]=0x%x\n",
+              index, kind, reg, value);
+}
+
+static void
+print_cpu_feature_preferred (const char *label, unsigned int flag)
+{
+  _dl_printf("x86.cpu_features.preferred.%s=0x%x\n", label, flag);
+}
+
+void
+_dl_diagnostics_cpu (void)
+{
+  const struct cpu_features *cpu_features = __get_cpu_features ();
+
+  print_cpu_features_value ("basic.kind", cpu_features->basic.kind);
+  print_cpu_features_value ("basic.max_cpuid", cpu_features->basic.max_cpuid);
+  print_cpu_features_value ("basic.family", cpu_features->basic.family);
+  print_cpu_features_value ("basic.model", cpu_features->basic.model);
+  print_cpu_features_value ("basic.stepping", cpu_features->basic.stepping);
+
+  for (unsigned int index = 0; index < CPUID_INDEX_MAX; ++index)
+    {
+      /* The index values are part of the ABI via
+         <sys/platform/x86.h>, so translating them to strings is not
+         necessary.  */
+      for (unsigned int reg = 0; reg < 4; ++reg)
+        print_cpu_feature_internal
+          (index, "cpuid", reg,
+           cpu_features->features[index].cpuid_array[reg]);
+      for (unsigned int reg = 0; reg < 4; ++reg)
+        print_cpu_feature_internal
+          (index, "usable", reg,
+           cpu_features->features[index].usable_array[reg]);
+    }
+
+  /* The preferred indicators are not part of the ABI and need to be
+     translated.  */
+#define BIT(x) \
+  print_cpu_feature_preferred (#x, CPU_FEATURE_PREFERRED_P (cpu_features, x));
+#include "cpu-features-preferred_feature_index_1.def"
+#undef BIT
+
+  print_cpu_features_value ("isa_1", cpu_features->isa_1);
+  print_cpu_features_value ("xsave_state_size",
+                            cpu_features->xsave_state_size);
+  print_cpu_features_value ("xsave_state_full_size",
+                            cpu_features->xsave_state_full_size);
+  print_cpu_features_value ("data_cache_size", cpu_features->data_cache_size);
+  print_cpu_features_value ("shared_cache_size",
+                            cpu_features->shared_cache_size);
+  print_cpu_features_value ("non_temporal_threshold",
+                            cpu_features->non_temporal_threshold);
+  print_cpu_features_value ("rep_movsb_threshold",
+                            cpu_features->rep_movsb_threshold);
+  print_cpu_features_value ("rep_stosb_threshold",
+                            cpu_features->rep_stosb_threshold);
+  print_cpu_features_value ("level1_icache_size",
+                            cpu_features->level1_icache_size);
+  print_cpu_features_value ("level1_icache_linesize",
+                            cpu_features->level1_icache_linesize);
+  print_cpu_features_value ("level1_dcache_size",
+                            cpu_features->level1_dcache_size);
+  print_cpu_features_value ("level1_dcache_assoc",
+                            cpu_features->level1_dcache_assoc);
+  print_cpu_features_value ("level1_dcache_linesize",
+                            cpu_features->level1_dcache_linesize);
+  print_cpu_features_value ("level2_cache_size",
+                            cpu_features->level2_cache_size);
+  print_cpu_features_value ("level2_cache_assoc",
+                            cpu_features->level2_cache_assoc);
+  print_cpu_features_value ("level2_cache_linesize",
+                            cpu_features->level2_cache_linesize);
+  print_cpu_features_value ("level3_cache_size",
+                            cpu_features->level3_cache_size);
+  print_cpu_features_value ("level3_cache_assoc",
+                            cpu_features->level3_cache_assoc);
+  print_cpu_features_value ("level3_cache_linesize",
+                            cpu_features->level3_cache_linesize);
+  print_cpu_features_value ("level4_cache_size",
+                            cpu_features->level4_cache_size);
+  _Static_assert (offsetof (struct cpu_features, level4_cache_size)
+                  + sizeof (cpu_features->level4_cache_size)
+                  == sizeof (*cpu_features),
+                  "last cpu_features field has been printed");
+}
diff --git a/sysdeps/x86/include/cpu-features-preferred_feature_index_1.def b/sysdeps/x86/include/cpu-features-preferred_feature_index_1.def
new file mode 100644 (file)
index 0000000..06af1a8
--- /dev/null
@@ -0,0 +1,34 @@
+/* Bits in the PREFERRED_FEATURE_INDEX_1 bitfield of <cpu-features.h>.
+   Copyright (C) 2020-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
+   <https://www.gnu.org/licenses/>.  */
+
+BIT (Fast_Rep_String)
+BIT (Fast_Copy_Backward)
+BIT (Slow_BSF)
+BIT (Fast_Unaligned_Load)
+BIT (Prefer_PMINUB_for_stringop)
+BIT (Fast_Unaligned_Copy)
+BIT (I586)
+BIT (I686)
+BIT (Slow_SSE4_2)
+BIT (AVX_Fast_Unaligned_Load)
+BIT (Prefer_MAP_32BIT_EXEC)
+BIT (Prefer_No_VZEROUPPER)
+BIT (Prefer_ERMS)
+BIT (Prefer_No_AVX512)
+BIT (MathVec_Prefer_No_AVX512)
+BIT (Prefer_FSRM)
index 624736b40ebb2cd6650c8ecee5908167c7e91e53..04d8e5734eb53e2b6a9084bc2bf03d196b47efc4 100644 (file)
@@ -757,40 +757,23 @@ enum
 #define reg_AESKLE             ebx
 #define reg_WIDE_KL            ebx
 
-/* PREFERRED_FEATURE_INDEX_1.  */
-#define bit_arch_I586                          (1u << 0)
-#define bit_arch_I686                          (1u << 1)
-#define bit_arch_Fast_Rep_String               (1u << 2)
-#define bit_arch_Fast_Copy_Backward            (1u << 3)
-#define bit_arch_Fast_Unaligned_Load           (1u << 4)
-#define bit_arch_Fast_Unaligned_Copy           (1u << 5)
-#define bit_arch_Slow_BSF                      (1u << 6)
-#define bit_arch_Slow_SSE4_2                   (1u << 7)
-#define bit_arch_AVX_Fast_Unaligned_Load       (1u << 8)
-#define bit_arch_Prefer_MAP_32BIT_EXEC         (1u << 9)
-#define bit_arch_Prefer_PMINUB_for_stringop    (1u << 10)
-#define bit_arch_Prefer_No_VZEROUPPER          (1u << 11)
-#define bit_arch_Prefer_ERMS                   (1u << 12)
-#define bit_arch_Prefer_FSRM                   (1u << 13)
-#define bit_arch_Prefer_No_AVX512              (1u << 14)
-#define bit_arch_MathVec_Prefer_No_AVX512      (1u << 15)
-
-#define index_arch_Fast_Rep_String             PREFERRED_FEATURE_INDEX_1
-#define index_arch_Fast_Copy_Backward          PREFERRED_FEATURE_INDEX_1
-#define index_arch_Slow_BSF                    PREFERRED_FEATURE_INDEX_1
-#define index_arch_Fast_Unaligned_Load         PREFERRED_FEATURE_INDEX_1
-#define index_arch_Prefer_PMINUB_for_stringop  PREFERRED_FEATURE_INDEX_1
-#define index_arch_Fast_Unaligned_Copy         PREFERRED_FEATURE_INDEX_1
-#define index_arch_I586                                PREFERRED_FEATURE_INDEX_1
-#define index_arch_I686                                PREFERRED_FEATURE_INDEX_1
-#define index_arch_Slow_SSE4_2                 PREFERRED_FEATURE_INDEX_1
-#define index_arch_AVX_Fast_Unaligned_Load     PREFERRED_FEATURE_INDEX_1
-#define index_arch_Prefer_MAP_32BIT_EXEC       PREFERRED_FEATURE_INDEX_1
-#define index_arch_Prefer_No_VZEROUPPER                PREFERRED_FEATURE_INDEX_1
-#define index_arch_Prefer_ERMS                 PREFERRED_FEATURE_INDEX_1
-#define index_arch_Prefer_No_AVX512            PREFERRED_FEATURE_INDEX_1
-#define index_arch_MathVec_Prefer_No_AVX512    PREFERRED_FEATURE_INDEX_1
-#define index_arch_Prefer_FSRM                 PREFERRED_FEATURE_INDEX_1
+/* PREFERRED_FEATURE_INDEX_1.  First define the bitindex values
+   sequentially, then define the bit_arch* and index_arch_* lookup
+   constants.  */
+enum
+  {
+#define BIT(x) _bitindex_arch_##x ,
+#include "cpu-features-preferred_feature_index_1.def"
+#undef BIT
+  };
+enum
+  {
+#define BIT(x)                                 \
+    bit_arch_##x = 1u << _bitindex_arch_##x ,  \
+    index_arch_##x = PREFERRED_FEATURE_INDEX_1,
+#include "cpu-features-preferred_feature_index_1.def"
+#undef BIT
+  };
 
 /* XCR0 Feature flags.  */
 #define bit_XMM_state          (1u << 1)
@@ -841,6 +824,8 @@ struct cpuid_feature_internal
     };
 };
 
+/* NB: When adding new fields, update sysdeps/x86/dl-diagnostics-cpu.c
+   to print them.  */
 struct cpu_features
 {
   struct cpu_features_basic basic;
@@ -874,6 +859,8 @@ struct cpu_features
   unsigned long int rep_stosb_threshold;
   /* _SC_LEVEL1_ICACHE_SIZE.  */
   unsigned long int level1_icache_size;
+  /* _SC_LEVEL1_ICACHE_LINESIZE.  */
+  unsigned long int level1_icache_linesize;
   /* _SC_LEVEL1_DCACHE_SIZE.  */
   unsigned long int level1_dcache_size;
   /* _SC_LEVEL1_DCACHE_ASSOC.  */
index aaf524cb56c99cb43044fef3cac5b54f8d7dff9f..49ef4aa6122072cf4fddced81c23048633f25099 100644 (file)
 
 /* ELF program property for x86 ISA level.  */
 #ifdef INCLUDE_X86_ISA_LEVEL
-# if defined __x86_64__ || defined __FXSR__ || !defined _SOFT_FLOAT \
-     || defined  __MMX__ || defined __SSE__ || defined __SSE2__
+# if defined __SSE__ && defined __SSE2__
+/* NB: ISAs, excluding MMX, in x86-64 ISA level baseline are used.  */
 #  define ISA_BASELINE GNU_PROPERTY_X86_ISA_1_BASELINE
 # else
 #  define ISA_BASELINE 0
 # endif
 
-# if defined __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16 \
-     || (defined __x86_64__ && defined __LAHF_SAHF__) \
-     || defined __POPCNT__ || defined __SSE3__ \
-     || defined __SSSE3__ || defined __SSE4_1__ || defined __SSE4_2__
+# if ISA_BASELINE && defined __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16 \
+     && defined HAVE_X86_LAHF_SAHF && defined __POPCNT__ \
+     && defined __SSE3__ && defined __SSSE3__ && defined __SSE4_1__ \
+     && defined __SSE4_2__
+/* NB: ISAs in x86-64 ISA level v2 are used.  */
 #  define ISA_V2       GNU_PROPERTY_X86_ISA_1_V2
 # else
 #  define ISA_V2       0
 # endif
 
-# if defined __AVX__ || defined __AVX2__ || defined __F16C__ \
-     || defined __FMA__ || defined __LZCNT__ || defined __MOVBE__ \
-     || defined __XSAVE__
+# if ISA_V2 && defined __AVX__ && defined __AVX2__ && defined __F16C__ \
+     && defined __FMA__ && defined __LZCNT__ && defined HAVE_X86_MOVBE
+/* NB: ISAs in x86-64 ISA level v3 are used.  */
 #  define ISA_V3       GNU_PROPERTY_X86_ISA_1_V3
 # else
 #  define ISA_V3       0
 # endif
 
-# if defined __AVX512F__ || defined __AVX512BW__ || defined __AVX512CD__ \
-     || defined __AVX512DQ__ || defined __AVX512VL__
+# if ISA_V3 && defined __AVX512F__ && defined __AVX512BW__ \
+     && defined __AVX512CD__ && defined __AVX512DQ__ \
+     && defined __AVX512VL__
+/* NB: ISAs in x86-64 ISA level v4 are used.  */
 #  define ISA_V4       GNU_PROPERTY_X86_ISA_1_V4
 # else
 #  define ISA_V4       0
index 79d803eb291c188af8e9afe7dbee70cf69628490..cc0d2b2d569a376be1771e6e096c67c34d19921b 100644 (file)
@@ -59,9 +59,9 @@ do_test (int argc, char **argv)
   fails += CHECK_SUPPORTS (aes, AES);
 #endif
 #if __GNUC_PREREQ (11, 1)
-  fails += CHECK_SUPPORTS (amx_bf16, AMX_BF16);
-  fails += CHECK_SUPPORTS (amx_int8, AMX_INT8);
-  fails += CHECK_SUPPORTS (amx_tile, AMX_TILE);
+  fails += CHECK_SUPPORTS (amx-bf16, AMX_BF16);
+  fails += CHECK_SUPPORTS (amx-int8, AMX_INT8);
+  fails += CHECK_SUPPORTS (amx-tile, AMX_TILE);
 #endif
   fails += CHECK_SUPPORTS (avx, AVX);
   fails += CHECK_SUPPORTS (avx2, AVX2);
diff --git a/sysdeps/x86/tst-sysconf-cache-linesize-static.c b/sysdeps/x86/tst-sysconf-cache-linesize-static.c
new file mode 100644 (file)
index 0000000..152ae68
--- /dev/null
@@ -0,0 +1 @@
+#include "tst-sysconf-cache-linesize.c"
diff --git a/sysdeps/x86/tst-sysconf-cache-linesize.c b/sysdeps/x86/tst-sysconf-cache-linesize.c
new file mode 100644 (file)
index 0000000..642dbde
--- /dev/null
@@ -0,0 +1,57 @@
+/* Test system cache line sizes.
+   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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <array_length.h>
+
+static struct
+{
+  const char *name;
+  int _SC_val;
+} sc_options[] =
+  {
+#define N(name) { "_SC_"#name, _SC_##name }
+    N (LEVEL1_ICACHE_LINESIZE),
+    N (LEVEL1_DCACHE_LINESIZE),
+    N (LEVEL2_CACHE_LINESIZE)
+  };
+
+static int
+do_test (void)
+{
+  int result = EXIT_SUCCESS;
+
+  for (int i = 0; i < array_length (sc_options); ++i)
+    {
+      long int scret = sysconf (sc_options[i]._SC_val);
+      if (scret < 0)
+       {
+         printf ("sysconf (%s) returned < 0 (%ld)\n",
+                 sc_options[i].name, scret);
+         result = EXIT_FAILURE;
+       }
+      else
+       printf ("sysconf (%s): %ld\n", sc_options[i].name, scret);
+    }
+
+  return result;
+}
+
+#include <support/test-driver.c>
old mode 100644 (file)
new mode 100755 (executable)
index 198554d..75c96d6
@@ -107,39 +107,6 @@ if test x"$build_mathvec" = xnotset; then
   build_mathvec=yes
 fi
 
-if test "$static_pie" = yes; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for linker static PIE support" >&5
-$as_echo_n "checking for linker static PIE support... " >&6; }
-if ${libc_cv_ld_static_pie+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  cat > conftest.s <<\EOF
-       .text
-       .global _start
-       .weak foo
-_start:
-       leaq    foo(%rip), %rax
-EOF
-  libc_cv_pie_option="-Wl,-pie"
-  if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS -nostartfiles -nostdlib $no_ssp $libc_cv_pie_option -o conftest conftest.s 1>&5'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then
-    libc_cv_ld_static_pie=yes
-  else
-    libc_cv_ld_static_pie=no
-  fi
-rm -f conftest*
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_ld_static_pie" >&5
-$as_echo "$libc_cv_ld_static_pie" >&6; }
-  if test "$libc_cv_ld_static_pie" != yes; then
-    as_fn_error $? "linker support for static PIE needed" "$LINENO" 5
-  fi
-fi
-
 $as_echo "#define PI_STATIC_AND_HIDDEN 1" >>confdefs.h
 
 
index ec776274af5c258d5c9bdffee16d1d0f77eca3cd..66219e7ce5e190ae0bc349cfc5f4f3b3f0589fd0 100644 (file)
@@ -53,31 +53,6 @@ if test x"$build_mathvec" = xnotset; then
   build_mathvec=yes
 fi
 
-dnl Check if linker supports static PIE with the fix for
-dnl
-dnl https://sourceware.org/bugzilla/show_bug.cgi?id=21782
-dnl
-if test "$static_pie" = yes; then
-  AC_CACHE_CHECK(for linker static PIE support, libc_cv_ld_static_pie, [dnl
-cat > conftest.s <<\EOF
-       .text
-       .global _start
-       .weak foo
-_start:
-       leaq    foo(%rip), %rax
-EOF
-  libc_cv_pie_option="-Wl,-pie"
-  if AC_TRY_COMMAND(${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS -nostartfiles -nostdlib $no_ssp $libc_cv_pie_option -o conftest conftest.s 1>&AS_MESSAGE_LOG_FD); then
-    libc_cv_ld_static_pie=yes
-  else
-    libc_cv_ld_static_pie=no
-  fi
-rm -f conftest*])
-  if test "$libc_cv_ld_static_pie" != yes; then
-    AC_MSG_ERROR([linker support for static PIE needed])
-  fi
-fi
-
 dnl It is always possible to access static and hidden symbols in an
 dnl position independent way.
 AC_DEFINE(PI_STATIC_AND_HIDDEN)