diff options
author | Tulio Magno Quites Machado Filho <tuliom@linux.ibm.com> | 2019-01-11 14:20:21 -0200 |
---|---|---|
committer | Tulio Magno Quites Machado Filho <tuliom@linux.ibm.com> | 2019-01-11 14:20:21 -0200 |
commit | c49ad9bdc9ecc49a4e9811448697ae3773d472a0 (patch) | |
tree | ae07322318314bea786c66e33f65aad57e0b6f22 | |
parent | 400747ec4ff4c0b8bc094437c2e8cc8da42ee452 (diff) | |
parent | 7ab39c6a3cd4a61a2be3d2e6a2a56f4dccca9750 (diff) | |
download | glibc-c49ad9bdc9ecc49a4e9811448697ae3773d472a0.tar.gz glibc-c49ad9bdc9ecc49a4e9811448697ae3773d472a0.tar.xz glibc-c49ad9bdc9ecc49a4e9811448697ae3773d472a0.zip |
Merge branch 'release/2.26/master' into ibm/2.26/master
99 files changed, 3000 insertions, 345 deletions
diff --git a/ChangeLog b/ChangeLog index e6add48bf5..60b0364037 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,372 @@ +2019-01-11 Gabriel F. T. Gomes <gabriel@inconstante.eti.br> + + * sysdeps/powerpc/fpu/libm-test-ulps: Regenerate. + +2019-01-11 Tulio Magno Quites Machado Filho <tuliom@linux.vnet.ibm.com> + + [BZ #21745] + * sysdeps/powerpc/powerpc64/fpu/multiarch/Makefile: + [$(subdir) = math] (sysdep_calls): New variable. Has the + previous contents of sysdep_routines, but re-sorted.. + [$(subdir) = math] (sysdep_routines): Re-use the contents from + sysdep_calls. + [$(subdir) = math] (libm-sysdep_routines): Remove the functions + defined in sysdep_calls and replace by the respective m_* names. + * sysdeps/powerpc/powerpc64/fpu/multiarch/s_isnan-ppc64.S: + (compat_symbol): Undefine to avoid duplicated compat symbols in + libc. + +2019-01-02 Florian Weimer <fweimer@redhat.com> + + [BZ #24018] + * intl/dcigettext.c (DCIGETTEXT): Do not return NULL on asprintf + failure. + +2018-12-31 Florian Weimer <fw@deneb.enyo.de> + + [BZ #24027] + * malloc/malloc.c (_int_realloc): Always call memcpy for the + copying operation. (ncopies had the wrong type, resulting in an + integer wraparound and too few elements being copied.) + +2018-11-27 Florian Weimer <fweimer@redhat.com> + + [BZ #23927] + CVE-2018-19591 + * sysdeps/unix/sysv/linux/if_index.c (__if_nametoindex): Avoid + descriptor leak in case of ENODEV error. + +2018-11-08 Alexandra Hájková <ahajkova@redhat.com> + + [BZ #17630] + * resolv/tst-resolv-network.c: Add test for getnetbyname. + +2018-11-05 Andreas Schwab <schwab@suse.de> + + [BZ #22927] + * resolv/gai_misc.c (__gai_enqueue_request): Don't crash if + creating the first helper thread failed. + +2018-10-23 Adhemerval Zanella <adhemerval.zanella@linaro.org> + + [BZ #23709] + * sysdeps/x86/cpu-features.c (init_cpu_features): Set TSX bits + independently of other flags. + +2017-12-18 Joseph Myers <joseph@codesourcery.com> + + * nptl/tst-attr3.c: Include <libc-diag.h>. + (do_test) [__GNUC_PREREQ (7, 0)]: Ignore -Wrestrict for two tests. + +2017-11-14 Joseph Myers <joseph@codesourcery.com> + + * string/bug-strncat1.c: Include <libc-diag.h>. + (main): Disable -Wstringop-truncation for strncat call for GCC 8. + +2018-06-14 Joseph Myers <joseph@codesourcery.com> + + * string/tester.c (test_strncat) [__GNUC_PREREQ (7, 0)]: Also + ignore -Wrestrict for one test. + +2017-12-18 Joseph Myers <joseph@codesourcery.com> + + * string/tester.c (test_strncat): Also disable -Warray-bounds + warnings for two tests. + +2017-11-14 Joseph Myers <joseph@codesourcery.com> + + * string/tester.c (test_stpncpy): Disable -Wstringop-truncation + for stpncpy calls for GCC 8. + (test_strncat): Disable -Wstringop-truncation warning for strncat + calls for GCC 8. Disable -Wstringop-overflow= warning for one + strncat call for GCC 7. + (test_strncpy): Disable -Wstringop-truncation warning for strncpy + calls for GCC 8. + (test_memcmp): Use memcpy instead of strncpy for calls not copying + trailing NUL. + +2017-12-18 Joseph Myers <joseph@codesourcery.com> + + [BZ #22446] + * nscd/connections.c (handle_request) [SO_PEERCRED]: Use separate + buffers for readlink input and output. + +2017-12-15 Steve Ellcey <sellcey@cavium.com> + + * nscd/dbg_log.c (dbg_log): Increase msg buffer size. + +2017-11-22 Joseph Myers <joseph@codesourcery.com> + + [BZ #22463] + * resolv/res_debug.c: Include <libc-diag.h>. + (p_secstodate): Assert time_t at least as wide as u_long. On + overflow, use integer seconds since the epoch as output, or use + "<overflow>" as output and set errno to EOVERFLOW if integer + seconds since the epoch would be 14 or more characters. + (p_secstodate) [__GNUC_PREREQ (7, 0)]: Disable -Wformat-overflow= + for sprintf call. + * resolv/tst-p_secstodate.c: New file. + * resolv/Makefile (tests): Add tst-p_secstodate. + ($(objpfx)tst-p_secstodate): Depend on $(objpfx)libresolv.so. + +2017-11-12 Paul Eggert <eggert@cs.ucla.edu> + + timezone: pacify GCC -Wstringop-truncation + Problem reported by Martin Sebor in: + https://sourceware.org/ml/libc-alpha/2017-11/msg00336.html + * timezone/zic.c (writezone): Use memcpy, not strncpy. + +2017-11-15 Martin Sebor <msebor@redhat.com> + + * misc/sys/cdefs.h (__attribute_nonstring__): New macro. + * sysdeps/gnu/bits/utmp.h (struct utmp): Use it. + * sysdeps/unix/sysv/linux/s390/bits/utmp.h (struct utmp): Same. + +2017-11-22 Joseph Myers <joseph@codesourcery.com> + + [BZ #22447] + * sysdeps/unix/getlogin_r.c (__getlogin_r): Use __strnlen not + strlen to compute length of ut_user and set trailing NUL byte of + result explicitly. + +2018-10-19 Ilya Yu. Malakhov <malakhov@mcst.ru> + + [BZ #23562] + * sysdeps/unix/sysv/linux/bits/types/siginfo_t.h + (struct siginfo_t): Use correct type for si_band. + +2018-09-28 Adhemerval Zanella <adhemerval.zanella@linaro.org> + + [BZ #23579] + * misc/tst-preadvwritev2-common.c (do_test_with_invalid_fd, + do_test_with_invalid_iov): New tests. + * misc/tst-preadvwritev2.c, misc/tst-preadvwritev64v2.c (do_test): + Call do_test_with_invalid_fd and do_test_with_invalid_iov. + * sysdeps/unix/sysv/linux/preadv2.c (preadv2): Use fallback code iff + errno is ENOSYS. + * sysdeps/unix/sysv/linux/preadv64v2.c (preadv64v2): Likewise. + * sysdeps/unix/sysv/linux/pwritev2.c (pwritev2): Likewise. + * sysdeps/unix/sysv/linux/pwritev64v2.c (pwritev64v2): Likewise. + * NEWS: Add bug fixed. + +2018-09-28 Florian Weimer <fweimer@redhat.com> + + [BZ #22753] + * sysdeps/posix/preadv2.c (preadv2): Handle offset == -1. + * sysdeps/posix/preadv64v2.c (preadv64v2): Likewise. + * sysdeps/posix/pwritev2.c (pwritev2): Likewise. + * sysdeps/posix/pwritev64v2.c (pwritev64v2): Likweise. + * sysdeps/unix/sysv/linux/preadv2.c (preadv2): Likewise. + * sysdeps/unix/sysv/linux/preadv64v2.c (preadv64v2): Likewise. + * sysdeps/unix/sysv/linux/pwritev2.c (pwritev2): Likewise. + * sysdeps/unix/sysv/linux/pwritev64v2.c (pwritev64v2): Likweise. + * manual/llio.texi (Scatter-Gather): Mention offset -1. + * misc/tst-preadvwritev-common.c (do_test_without_offset): New. + * misc/tst-preadvwritev2.c (do_test): Call it. + * misc/tst-preadvwritev64v2.c (do_test): Likewise. + * NEWS: Add bug fixed. + +2018-09-06 Stefan Liebler <stli@linux.ibm.com> + + * sysdeps/unix/sysv/linux/spawni.c (maybe_script_execute): + Increment size of new_argv by one. + +2018-08-27 Martin Kuchta <martin.kuchta@netapp.com> + Torvald Riegel <triegel@redhat.com> + + [BZ #23538] + * nptl/pthread_cond_common.c (__condvar_quiesce_and_switch_g1): + Update r to include the set wake-request flag if waiters are + remaining after spinning. + +2018-07-29 H.J. Lu <hongjiu.lu@intel.com> + + [BZ #23459] + * sysdeps/x86/cpu-features.c (get_extended_indices): New + function. + (init_cpu_features): Call get_extended_indices for both Intel + and AMD CPUs. + * sysdeps/x86/cpu-features.h (COMMON_CPUID_INDEX_80000001): + Remove "for AMD" comment. + +2018-07-29 H.J. Lu <hongjiu.lu@intel.com> + + [BZ #23456] + * sysdeps/x86/cpu-features.h (index_cpu_LZCNT): Set to + COMMON_CPUID_INDEX_80000001. + +2018-07-06 Florian Weimer <fweimer@redhat.com> + + * conform/conformtest.pl (checknamespace): Escape literal braces + in regular expressions. + +2018-07-03 Florian Weimer <fweimer@redhat.com> + + [BZ #23363] + * stdio-common/tst-printf.c (DEC, INT, UNS, fp_test): Remove. + * stdio-common/tst-printf.sh: Adjust expected output. + * LICENSES: Update. + +2018-06-26 Florian Weimer <fweimer@redhat.com> + + * libio/Makefile (tests-internal): Add tst-vtables, + tst-vtables-interposed. + * libio/tst-vtables.c: New file. + * libio/tst-vtables-common.c: Likewise. + * libio/tst-vtables-interposed.c: Likewise. + +2018-06-26 Florian Weimer <fweimer@redhat.com> + + [BZ #23313] + * libio/vtables.c (check_stdfiles_vtables): New ELF constructor. + +2017-11-15 Steve Ellcey <sellcey@cavium.com> + + [BZ #22442] + * sysdeps/unix/sysv/linux/if_index.c (__if_nametoindex): + Check if ifname is too long. + +2018-06-29 Daniel Alvarez <dalvarez@redhat.com> + Jakub Sitnicki <jkbs@redhat.com> + + [BZ #21812] + * sysdeps/unix/sysv/linux/ifaddrs.c (getifaddrs_internal): Retry + on NLM_F_DUMP_INTR. + +2018-06-28 Florian Weimer <fweimer@redhat.com> + + [BZ #23349] + * time/bits/types/struct_timespec.h: Change header inclusion guard to + _STRUCT_TIMESPEC. + +2018-05-24 Gabriel F. T. Gomes <gabriel@inconstante.eti.br> + + [BZ #23171] + * math/math.h [C++] (iseqsig): Fix parameter type for the long + double version. + +2018-06-01 Florian Weimer <fweimer@redhat.com> + + [BZ #23236] + * libio/strfile.h (struct _IO_str_fields): Rename members to + discourage their use and add comment. + (_IO_STR_DYNAMIC): Remove unused macro. + * libio/strops.c (_IO_str_init_static_internal): Do not use + callback pointers. Call malloc and free. + (_IO_str_overflow): Do not use callback pointers. Call malloc + and free. + (enlarge_userbuf): Likewise. + (_IO_str_finish): Call free. + * libio/wstrops.c (_IO_wstr_init_static): Initialize + _allocate_buffer_unused. + (_IO_wstr_overflow): Do not use callback pointers. Call malloc + and free. + (enlarge_userbuf): Likewise. + (_IO_wstr_finish): Call free. + * debug/vasprintf_chk.c (__vasprintf_chk): Initialize + _allocate_buffer_unused, _free_buffer_unused. + * libio/memstream.c (__open_memstream): Likewise. + * libio/vasprintf.c (_IO_vasprintf): Likewise. + * libio/wmemstream.c (open_wmemstream): Likewise. + +2018-05-23 H.J. Lu <hongjiu.lu@intel.com> + + [BZ #23196] + * string/test-memcpy.c (do_test1): New function. + (test_main): Call it. + +2018-05-23 Andreas Schwab <schwab@suse.de> + + [BZ #23196] + CVE-2018-11237 + * sysdeps/x86_64/multiarch/memmove-avx512-no-vzeroupper.S + (L(preloop_large)): Save initial destination pointer in %r11 and + use it instead of %rax after the loop. + * string/test-mempcpy.c (MIN_PAGE_SIZE): Define. + +2018-05-09 Paul Pluzhnikov <ppluzhnikov@google.com> + + [BZ #22786] + CVE-2018-11236 + * stdlib/canonicalize.c (__realpath): Fix overflow in path length + computation. + * stdlib/Makefile (test-bz22786): New test. + * stdlib/test-bz22786.c: New test. + +2018-05-05 Paul Pluzhnikov <ppluzhnikov@google.com> + + [BZ #20419] + * elf/dl-load.c (open_verify): Fix stack overflow. + * elf/Makefile (tst-big-note): New test. + * elf/tst-big-note-lib.S: New. + * elf/tst-big-note.c: New. + +2018-05-04 Stefan Liebler <stli@linux.vnet.ibm.com> + + [BZ #23137] + * sysdeps/nptl/lowlevellock.h (lll_wait_tid): + Use atomic_load_acquire to load __tid. + +2018-03-20 Joseph Myers <joseph@codesourcery.com> + + [BZ #17343] + * stdlib/random_r.c (__random_r): Use unsigned arithmetic for + possibly overflowing computations. + +2018-03-03 Adhemerval Zanella <adhemerval.zanella@linaro.org> + + [BZ #21269] + * sysdeps/unix/sysv/linux/i386/Makefile (tests): Add tst-bz21269. + * sysdeps/unix/sysv/linux/i386/sigaction.c (SET_SA_RESTORER): Clear + sa_restorer for vDSO case. + * sysdeps/unix/sysv/linux/i386/tst-bz21269.c: New file. + +2018-03-01 DJ Delorie <dj@delorie.com> + + [BZ #22342] + * nscd/netgroupcache.c (addinnetgrX): Include trailing NUL in + key value. + +2018-03-23 Andrew Senkevich <andrew.senkevich@intel.com> + Max Horn <max@quendi.de> + + [BZ #22644] + CVE-2017-18269 + * sysdeps/i386/i686/multiarch/memcpy-sse2-unaligned.S: Fixed + branch conditions. + * string/test-memmove.c (do_test2): New testcase. + +2018-03-27 Andreas Schwab <schwab@suse.de> + + [BZ #23005] + * resolv/res_send.c (__res_context_send): Return ENOMEM if + allocation of private copy of nsaddr_list fails. + +2018-03-27 Jesse Hathaway <jesse@mbuki-mvuki.org> + + [BZ #23024] + * sysdeps/unix/sysv/linux/getlogin_r.c (__getlogin_r_loginuid): Return + early when linux sentinel value is set. + +2018-04-09 Florian Weimer <fweimer@redhat.com> + + [BZ #23037] + * resolv/res_send.c (send_dg): Use designated initializers instead + of assignment to zero-initialize other fields of struct mmsghdr. + +2018-01-18 Arjun Shankar <arjun@redhat.com> + + [BZ #22343] + [BZ #22774] + CVE-2018-6485 + CVE-2018-6551 + * malloc/malloc.c (checked_request2size): call REQUEST_OUT_OF_RANGE + after padding. + (_int_memalign): check for integer overflow before calling + _int_malloc. + * malloc/tst-malloc-too-large.c: New test. + * malloc/Makefile: Add tst-malloc-too-large. + 2018-01-19 Tulio Magno Quites Machado Filho <tuliom@linux.vnet.ibm.com> [BZ #22685] diff --git a/LICENSES b/LICENSES index 80f7f14879..858076d9d3 100644 --- a/LICENSES +++ b/LICENSES @@ -441,15 +441,6 @@ Permission to use, copy, modify, and distribute this software is freely granted, provided that this notice is preserved. -Part of stdio-common/tst-printf.c is copyright C E Chew: - -(C) Copyright C E Chew - -Feel free to copy, use and distribute this software provided: - - 1. you do not pretend that you wrote it - 2. you leave this copyright notice intact. - Various long double libm functions are copyright Stephen L. Moshier: Copyright 2001 by Stephen L. Moshier <moshier@na-net.ornl.gov> diff --git a/NEWS b/NEWS index 3f2cb5915f..49895f81bd 100644 --- a/NEWS +++ b/NEWS @@ -59,18 +59,45 @@ Security related changes: for AT_SECURE or SUID binaries could be used to load libraries from the current directory. + CVE-2017-18269: An SSE2-based memmove implementation for the i386 + architecture could corrupt memory. Reported by Max Horn. + CVE-2018-1000001: Buffer underflow in realpath function when getcwd function succeeds without returning an absolute path due to unexpected behaviour of the Linux kernel getcwd syscall. Reported by halfdog. + CVE-2018-6485: The posix_memalign and memalign functions, when called with + an object size near the value of SIZE_MAX, would return a pointer to a + buffer which is too small, instead of NULL. Reported by Jakub Wilk. + + CVE-2018-6551: The malloc function, when called with an object size near + the value of SIZE_MAX, would return a pointer to a buffer which is too + small, instead of NULL. + + CVE-2018-11236: Very long pathname arguments to realpath function could + result in an integer overflow and buffer overflow. Reported by Alexey + Izbyshev. + + CVE-2018-11237: The mempcpy implementation for the Intel Xeon Phi + architecture could write beyond the target buffer, resulting in a buffer + overflow. Reported by Andreas Schwab. + + CVE-2018-19591: A file descriptor leak in if_nametoindex can lead to a + denial of service due to resource exhaustion when processing getaddrinfo + calls with crafted host names. Reported by Guido Vranken. + The following bugs are resolved with this release: [16750] ldd: Never run file directly. + [17343] Fix signed integer overflow in random_r [17956] crypt: Use NSPR header files in addition to NSS header files + [20419] elf: Fix stack overflow with huge PT_NOTE segment [20532] getaddrinfo: More robust handling of dlopen failures [21242] assert: Suppress pedantic warning caused by statement expression [21265] x86-64: Use fxsave/xsave/xsavec in _dl_runtime_resolve + [21269] i386 sigaction sa_restorer handling is wrong [21780] posix: Set p{read,write}v2 to return ENOTSUP + [21812] getifaddrs: Don't return ifa entries with NULL names [21871] x86-64: Use _dl_runtime_resolve_opt only with AVX512F [21885] getaddrinfo: Release resolver context on error in gethosts [21915] getaddrinfo: incorrect result handling for NSS service modules @@ -99,15 +126,45 @@ The following bugs are resolved with this release: [22321] sysconf: Fix missing definition of UIO_MAXIOV on Linux [22322] libc: [mips64] wrong bits/long-double.h installed [22325] glibc: Memory leak in glob with GLOB_TILDE (CVE-2017-15671) + [22342] NSCD not properly caching netgroup + [22343] malloc: Integer overflow in posix_memalign (CVE-2018-6485) [22375] malloc returns pointer from tcache instead of NULL (CVE-2017-17426) [22377] Provide a C++ version of iseqsig - [22636] PTHREAD_STACK_MIN is too small on x86-64 + [22442] if_nametoindex: Check length of ifname before copying it + [22446] Fix nscd readlink argument aliasing + [22447] Avoid use of strlen in getlogin_r + [22463] Fix p_secstodate overflow handling [22627] $ORIGIN in $LD_LIBRARY_PATH is substituted twice + [22636] PTHREAD_STACK_MIN is too small on x86-64 [22637] nptl: Fix stack guard size accounting + [22644] Fix i386 memmove issue [22679] getcwd(3) can succeed without returning an absolute path (CVE-2018-1000001) [22685] powerpc: Fix syscalls during early process initialization [22715] x86-64: Properly align La_x86_64_retval to VEC_SIZE + [22753] libc: preadv2/pwritev2 fallback code should handle offset=-1 + [22774] malloc: Integer overflow in malloc (CVE-2018-6551) + [22786] Fix path length overflow in realpath + [22927] libanl: properly cleanup if first helper thread creation failed + [23005] resolv: Fix crash in resolver on memory allocation failure + [23024] getlogin_r: return early when linux sentinel value is set + [23037] resolv: Fully initialize struct mmsghdr in send_dg + [23137] s390: Fix blocking pthread_join + [23171] Fix parameter type in C++ version of iseqsig + [23196] __mempcpy_avx512_no_vzeroupper mishandles large copies + [23236] Harden function pointers in _IO_str_fields + [23313] libio: Disable vtable validation in case of interposition + [23349] Various glibc headers no longer compatible with <linux/time.h> + [23538] pthread_cond_broadcast: Fix waiters-after-spinning case + [23363] stdio-common/tst-printf.c has non-free license + [23456] Wrong index_cpu_LZCNT + [23459] COMMON_CPUID_INDEX_80000001 isn't populated for Intel processors + [23562] signal: Use correct type for si_band in siginfo_t + [23579] libc: Errors misreported in preadv2 + [23709] Fix CPU string flags for Haswell-type CPUs + [23927] Linux if_nametoindex() does not close descriptor (CVE-2018-19591) + [24018] gettext may return NULL + [24027] malloc: Integer overflow in realloc Version 2.26 diff --git a/conform/conformtest.pl b/conform/conformtest.pl index cb500f0e76..a4ef756105 100644 --- a/conform/conformtest.pl +++ b/conform/conformtest.pl @@ -367,7 +367,7 @@ while ($#headers >= 0) { s/^optional-//; $optional = 1; } - if (/^element *({([^}]*)}|([^{ ]*)) *({([^}]*)}|([^{ ]*)) *([A-Za-z0-9_]*) *(.*)/) { + if (/^element *(\{([^}]*)\}|([^{ ]*)) *(\{([^}]*)\}|([^{ ]*)) *([A-Za-z0-9_]*) *(.*)/) { my($struct) = "$2$3"; my($type) = "$5$6"; my($member) = "$7"; @@ -556,7 +556,7 @@ while ($#headers >= 0) { "Symbol \"$symbol\" has not the right value.", $res, $xfail); } - } elsif (/^type *({([^}]*)|([a-zA-Z0-9_]*))/) { + } elsif (/^type *(\{([^}]*)|([a-zA-Z0-9_]*))/) { my($type) = "$2$3"; my($maybe_opaque) = 0; @@ -586,7 +586,7 @@ while ($#headers >= 0) { ? "NOT AVAILABLE" : "Type \"$type\" not available."), $missing, $optional, $xfail); - } elsif (/^tag *({([^}]*)|([a-zA-Z0-9_]*))/) { + } elsif (/^tag *(\{([^}]*)|([a-zA-Z0-9_]*))/) { my($type) = "$2$3"; # Remember that this name is allowed. @@ -607,7 +607,7 @@ while ($#headers >= 0) { compiletest ($fnamebase, "Testing for type $type", "Type \"$type\" not available.", $missing, 0, $xfail); - } elsif (/^function *({([^}]*)}|([a-zA-Z0-9_]*)) [(][*]([a-zA-Z0-9_]*) ([(].*[)])/) { + } elsif (/^function *(\{([^}]*)\}|([a-zA-Z0-9_]*)) [(][*]([a-zA-Z0-9_]*) ([(].*[)])/) { my($rettype) = "$2$3"; my($fname) = "$4"; my($args) = "$5"; @@ -644,7 +644,7 @@ while ($#headers >= 0) { "Function \"$fname\" has incorrect type.", $res, 0, $xfail); } - } elsif (/^function *({([^}]*)}|([a-zA-Z0-9_]*)) ([a-zA-Z0-9_]*) ([(].*[)])/) { + } elsif (/^function *(\{([^}]*)\}|([a-zA-Z0-9_]*)) ([a-zA-Z0-9_]*) ([(].*[)])/) { my($rettype) = "$2$3"; my($fname) = "$4"; my($args) = "$5"; @@ -681,7 +681,7 @@ while ($#headers >= 0) { "Function \"$fname\" has incorrect type.", $res, 0, $xfail); } - } elsif (/^variable *({([^}]*)}|([a-zA-Z0-9_]*)) ([a-zA-Z0-9_]*) *(.*)/) { + } elsif (/^variable *(\{([^}]*)\}|([a-zA-Z0-9_]*)) ([a-zA-Z0-9_]*) *(.*)/) { my($type) = "$2$3"; my($vname) = "$4"; my($rest) = "$5"; @@ -713,7 +713,7 @@ while ($#headers >= 0) { compiletest ($fnamebase, "Test for type of variable $fname", "Variable \"$vname\" has incorrect type.", $res, 0, $xfail); - } elsif (/^macro-function *({([^}]*)}|([a-zA-Z0-9_]*)) ([a-zA-Z0-9_]*) ([(].*[)])/) { + } elsif (/^macro-function *(\{([^}]*)\}|([a-zA-Z0-9_]*)) ([a-zA-Z0-9_]*) ([(].*[)])/) { my($rettype) = "$2$3"; my($fname) = "$4"; my($args) = "$5"; @@ -812,11 +812,11 @@ while ($#headers >= 0) { s/^xfail(\[([^\]]*)\])?-//; s/^optional-//; - if (/^element *({([^}]*)}|([^ ]*)) *({([^}]*)}|([^ ]*)) *([A-Za-z0-9_]*) *(.*)/) { + if (/^element *(\{([^}]*)\}|([^ ]*)) *(\{([^}]*)\}|([^ ]*)) *([A-Za-z0-9_]*) *(.*)/) { push @allow, $7; } elsif (/^(macro|constant|macro-constant|macro-int-constant) +([a-zA-Z0-9_]*) *(?:{([^}]*)} *)?(?:([>=<!]+) ([A-Za-z0-9_-]*))?/) { push @allow, $2; - } elsif (/^(type|tag) *({([^}]*)|([a-zA-Z0-9_]*))/) { + } elsif (/^(type|tag) *(\{([^}]*)|([a-zA-Z0-9_]*))/) { my($type) = "$3$4"; # Remember that this name is allowed. @@ -827,13 +827,13 @@ while ($#headers >= 0) { } else { push @allow, $type; } - } elsif (/^function *({([^}]*)}|([a-zA-Z0-9_]*)) [(][*]([a-zA-Z0-9_]*) ([(].*[)])/) { + } elsif (/^function *(\{([^}]*)\}|([a-zA-Z0-9_]*)) [(][*]([a-zA-Z0-9_]*) ([(].*[)])/) { push @allow, $4; - } elsif (/^function *({([^}]*)}|([a-zA-Z0-9_]*)) ([a-zA-Z0-9_]*) ([(].*[)])/) { + } elsif (/^function *(\{([^}]*)\}|([a-zA-Z0-9_]*)) ([a-zA-Z0-9_]*) ([(].*[)])/) { push @allow, $4; - } elsif (/^variable *({([^}]*)}|([a-zA-Z0-9_]*)) ([a-zA-Z0-9_]*)/) { + } elsif (/^variable *(\{([^}]*)\}|([a-zA-Z0-9_]*)) ([a-zA-Z0-9_]*)/) { push @allow, $4; - } elsif (/^macro-function *({([^}]*)}|([a-zA-Z0-9_]*)) ([a-zA-Z0-9_]*) ([(].*[)])/) { + } elsif (/^macro-function *(\{([^}]*)\}|([a-zA-Z0-9_]*)) ([a-zA-Z0-9_]*) ([(].*[)])/) { push @allow, $4; } elsif (/^symbol *([a-zA-Z0-9_]*) *([A-Za-z0-9_-]*)?/) { push @allow, $1; diff --git a/debug/vasprintf_chk.c b/debug/vasprintf_chk.c index 5ebfeed239..1d989dd707 100644 --- a/debug/vasprintf_chk.c +++ b/debug/vasprintf_chk.c @@ -55,8 +55,8 @@ __vasprintf_chk (char **result_ptr, int flags, const char *format, _IO_JUMPS (&sf._sbf) = &_IO_str_jumps; _IO_str_init_static_internal (&sf, string, init_string_size, string); sf._sbf._f._flags &= ~_IO_USER_BUF; - sf._s._allocate_buffer = (_IO_alloc_type) malloc; - sf._s._free_buffer = (_IO_free_type) free; + sf._s._allocate_buffer_unused = (_IO_alloc_type) malloc; + sf._s._free_buffer_unused = (_IO_free_type) free; /* For flags > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n can only come from read-only format strings. */ diff --git a/elf/Makefile b/elf/Makefile index e758a4c960..c2d5269d80 100644 --- a/elf/Makefile +++ b/elf/Makefile @@ -179,7 +179,8 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \ tst-initorder tst-initorder2 tst-relsort1 tst-null-argv \ tst-tlsalign tst-tlsalign-extern tst-nodelete-opened \ tst-nodelete2 tst-audit11 tst-audit12 tst-dlsym-error tst-noload \ - tst-latepthread tst-tls-manydynamic tst-nodelete-dlclose + tst-latepthread tst-tls-manydynamic tst-nodelete-dlclose \ + tst-big-note # reldep9 tests-internal += loadtest unload unload2 circleload1 \ neededtest neededtest2 neededtest3 neededtest4 \ @@ -263,7 +264,9 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \ tst-audit11mod1 tst-audit11mod2 tst-auditmod11 \ tst-audit12mod1 tst-audit12mod2 tst-audit12mod3 tst-auditmod12 \ tst-latepthreadmod $(tst-tls-many-dynamic-modules) \ - tst-nodelete-dlclose-dso tst-nodelete-dlclose-plugin + tst-nodelete-dlclose-dso tst-nodelete-dlclose-plugin \ + tst-big-note-lib + ifeq (yes,$(have-mtls-dialect-gnu2)) tests += tst-gnu2-tls1 modules-names += tst-gnu2-tls1mod @@ -1410,3 +1413,5 @@ 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-big-note: $(objpfx)tst-big-note-lib.so diff --git a/elf/dl-load.c b/elf/dl-load.c index 7397c1882c..127be5beca 100644 --- a/elf/dl-load.c +++ b/elf/dl-load.c @@ -1520,6 +1520,7 @@ open_verify (const char *name, int fd, ElfW(Ehdr) *ehdr; ElfW(Phdr) *phdr, *ph; ElfW(Word) *abi_note; + ElfW(Word) *abi_note_malloced = NULL; unsigned int osversion; size_t maplength; @@ -1679,10 +1680,25 @@ open_verify (const char *name, int fd, abi_note = (void *) (fbp->buf + ph->p_offset); else { - abi_note = alloca (size); + /* Note: __libc_use_alloca is not usable here, because + thread info may not have been set up yet. */ + if (size < __MAX_ALLOCA_CUTOFF) + abi_note = alloca (size); + else + { + /* There could be multiple PT_NOTEs. */ + abi_note_malloced = realloc (abi_note_malloced, size); + if (abi_note_malloced == NULL) + goto read_error; + + abi_note = abi_note_malloced; + } __lseek (fd, ph->p_offset, SEEK_SET); if (__libc_read (fd, (void *) abi_note, size) != size) - goto read_error; + { + free (abi_note_malloced); + goto read_error; + } } while (memcmp (abi_note, &expected_note, sizeof (expected_note))) @@ -1718,6 +1734,7 @@ open_verify (const char *name, int fd, break; } + free (abi_note_malloced); } return fd; diff --git a/elf/tst-big-note-lib.S b/elf/tst-big-note-lib.S new file mode 100644 index 0000000000..6b514a03cc --- /dev/null +++ b/elf/tst-big-note-lib.S @@ -0,0 +1,26 @@ +/* Bug 20419: test for stack overflow in elf/dl-load.c open_verify() + Copyright (C) 2018 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/>. */ + +/* This creates a .so with 8MiB PT_NOTE segment. + On a typical Linux system with 8MiB "ulimit -s", that was enough + to trigger stack overflow in open_verify. */ + +.pushsection .note.big,"a" +.balign 4 +.fill 8*1024*1024, 1, 0 +.popsection diff --git a/elf/tst-big-note.c b/elf/tst-big-note.c new file mode 100644 index 0000000000..fcd2b0ed82 --- /dev/null +++ b/elf/tst-big-note.c @@ -0,0 +1,26 @@ +/* Bug 20419: test for stack overflow in elf/dl-load.c open_verify() + Copyright (C) 2018 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/>. */ + +/* This file must be run from within a directory called "elf". */ + +int main (int argc, char *argv[]) +{ + /* Nothing to do here: merely linking against tst-big-note-lib.so triggers + the bug. */ + return 0; +} diff --git a/intl/dcigettext.c b/intl/dcigettext.c index f63b34b0f5..cfcdd304b4 100644 --- a/intl/dcigettext.c +++ b/intl/dcigettext.c @@ -635,7 +635,7 @@ DCIGETTEXT (const char *domainname, const char *msgid1, const char *msgid2, int ret = __asprintf (&xdirname, "%s/%s", cwd, dirname); free (cwd); if (ret < 0) - return NULL; + goto return_untranslated; dirname = xdirname; } #ifndef IN_LIBGLOCALE diff --git a/libio/Makefile b/libio/Makefile index a002a3365c..74bf5279f1 100644 --- a/libio/Makefile +++ b/libio/Makefile @@ -63,6 +63,9 @@ tests = tst_swprintf tst_wprintf tst_swscanf tst_wscanf tst_getwc tst_putwc \ tst-setvbuf1 tst-popen1 tst-fgetwc bug-wsetpos tst-fseek \ tst-fwrite-error tst-ftell-partial-wide tst-ftell-active-handler \ tst-ftell-append tst-fputws + +tests-internal = tst-vtables tst-vtables-interposed + ifeq (yes,$(build-shared)) # Add test-fopenloc only if shared library is enabled since it depends on # shared localedata objects. diff --git a/libio/memstream.c b/libio/memstream.c index e391efd48a..c26239968d 100644 --- a/libio/memstream.c +++ b/libio/memstream.c @@ -90,8 +90,8 @@ __open_memstream (char **bufloc, _IO_size_t *sizeloc) _IO_JUMPS_FILE_plus (&new_f->fp._sf._sbf) = &_IO_mem_jumps; _IO_str_init_static_internal (&new_f->fp._sf, buf, _IO_BUFSIZ, buf); new_f->fp._sf._sbf._f._flags &= ~_IO_USER_BUF; - new_f->fp._sf._s._allocate_buffer = (_IO_alloc_type) malloc; - new_f->fp._sf._s._free_buffer = (_IO_free_type) free; + new_f->fp._sf._s._allocate_buffer_unused = (_IO_alloc_type) malloc; + new_f->fp._sf._s._free_buffer_unused = (_IO_free_type) free; new_f->fp.bufloc = bufloc; new_f->fp.sizeloc = sizeloc; diff --git a/libio/strfile.h b/libio/strfile.h index 74bd4eb269..7ce1008516 100644 --- a/libio/strfile.h +++ b/libio/strfile.h @@ -34,8 +34,11 @@ typedef void (*_IO_free_type) (void*); struct _IO_str_fields { - _IO_alloc_type _allocate_buffer; - _IO_free_type _free_buffer; + /* These members are preserved for ABI compatibility. The glibc + implementation always calls malloc/free for user buffers if + _IO_USER_BUF or _IO_FLAGS2_USER_WBUF are not set. */ + _IO_alloc_type _allocate_buffer_unused; + _IO_free_type _free_buffer_unused; }; /* This is needed for the Irix6 N32 ABI, which has a 64 bit off_t type, @@ -55,10 +58,6 @@ typedef struct _IO_strfile_ struct _IO_str_fields _s; } _IO_strfile; -/* dynamic: set when the array object is allocated (or reallocated) as - necessary to hold a character sequence that can change in length. */ -#define _IO_STR_DYNAMIC(FP) ((FP)->_s._allocate_buffer != (_IO_alloc_type)0) - /* frozen: set when the program has requested that the array object not be altered, reallocated, or freed. */ #define _IO_STR_FROZEN(FP) ((FP)->_f._IO_file_flags & _IO_USER_BUF) diff --git a/libio/strops.c b/libio/strops.c index d72a47c649..625c09416c 100644 --- a/libio/strops.c +++ b/libio/strops.c @@ -61,7 +61,7 @@ _IO_str_init_static_internal (_IO_strfile *sf, char *ptr, _IO_size_t size, fp->_IO_read_end = end; } /* A null _allocate_buffer function flags the strfile as being static. */ - sf->_s._allocate_buffer = (_IO_alloc_type) 0; + sf->_s._allocate_buffer_unused = (_IO_alloc_type) 0; } void @@ -103,8 +103,7 @@ _IO_str_overflow (_IO_FILE *fp, int c) _IO_size_t new_size = 2 * old_blen + 100; if (new_size < old_blen) return EOF; - new_buf - = (char *) (*((_IO_strfile *) fp)->_s._allocate_buffer) (new_size); + new_buf = malloc (new_size); if (new_buf == NULL) { /* __ferror(fp) = 1; */ @@ -113,7 +112,7 @@ _IO_str_overflow (_IO_FILE *fp, int c) if (old_buf) { memcpy (new_buf, old_buf, old_blen); - (*((_IO_strfile *) fp)->_s._free_buffer) (old_buf); + free (old_buf); /* Make sure _IO_setb won't try to delete _IO_buf_base. */ fp->_IO_buf_base = NULL; } @@ -182,15 +181,14 @@ enlarge_userbuf (_IO_FILE *fp, _IO_off64_t offset, int reading) _IO_size_t newsize = offset + 100; char *oldbuf = fp->_IO_buf_base; - char *newbuf - = (char *) (*((_IO_strfile *) fp)->_s._allocate_buffer) (newsize); + char *newbuf = malloc (newsize); if (newbuf == NULL) return 1; if (oldbuf != NULL) { memcpy (newbuf, oldbuf, _IO_blen (fp)); - (*((_IO_strfile *) fp)->_s._free_buffer) (oldbuf); + free (oldbuf); /* Make sure _IO_setb won't try to delete _IO_buf_base. */ fp->_IO_buf_base = NULL; @@ -346,7 +344,7 @@ void _IO_str_finish (_IO_FILE *fp, int dummy) { if (fp->_IO_buf_base && !(fp->_flags & _IO_USER_BUF)) - (((_IO_strfile *) fp)->_s._free_buffer) (fp->_IO_buf_base); + free (fp->_IO_buf_base); fp->_IO_buf_base = NULL; _IO_default_finish (fp, 0); diff --git a/libio/tst-vtables-common.c b/libio/tst-vtables-common.c new file mode 100644 index 0000000000..dc8d89c195 --- /dev/null +++ b/libio/tst-vtables-common.c @@ -0,0 +1,511 @@ +/* Test for libio vtables and their validation. Common code. + Copyright (C) 2018 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/>. */ + +/* This test provides some coverage for how various stdio functions + use the vtables in FILE * objects. The focus is mostly on which + functions call which methods, not so much on validating data + processing. An initial series of tests check that custom vtables + do not work without activation through _IO_init. + + Note: libio vtables are deprecated feature. Do not use this test + as a documentation source for writing custom vtables. See + fopencookie for a different way of creating custom stdio + streams. */ + +#include <stdbool.h> +#include <string.h> +#include <support/capture_subprocess.h> +#include <support/check.h> +#include <support/namespace.h> +#include <support/support.h> +#include <support/test-driver.h> +#include <support/xunistd.h> + +/* Data shared between the test subprocess and the test driver in the + parent. Note that *shared is reset at the start of the check_call + function. */ +struct shared +{ + /* Expected file pointer for method calls. */ + FILE *fp; + + /* If true, assume that a call to _IO_init is needed to enable + custom vtables. */ + bool initially_disabled; + + /* Requested return value for the methods which have one. */ + int return_value; + + /* A value (usually a character) recorded by some of the methods + below. */ + int value; + + /* Likewise, for some data. */ + char buffer[16]; + size_t buffer_length; + + /* Total number of method calls. */ + unsigned int calls; + + /* Individual method call counts. */ + unsigned int calls_finish; + unsigned int calls_overflow; + unsigned int calls_underflow; + unsigned int calls_uflow; + unsigned int calls_pbackfail; + unsigned int calls_xsputn; + unsigned int calls_xsgetn; + unsigned int calls_seekoff; + unsigned int calls_seekpos; + unsigned int calls_setbuf; + unsigned int calls_sync; + unsigned int calls_doallocate; + unsigned int calls_read; + unsigned int calls_write; + unsigned int calls_seek; + unsigned int calls_close; + unsigned int calls_stat; + unsigned int calls_showmanyc; + unsigned int calls_imbue; +} *shared; + +/* Method implementations which increment the counters in *shared. */ + +static void +log_method (FILE *fp, const char *name) +{ + if (test_verbose > 0) + printf ("info: %s (%p) called\n", name, fp); +} + +static void +method_finish (FILE *fp, int dummy) +{ + log_method (fp, __func__); + TEST_VERIFY (fp == shared->fp); + ++shared->calls; + ++shared->calls_finish; +} + +static int +method_overflow (FILE *fp, int ch) +{ + log_method (fp, __func__); + TEST_VERIFY (fp == shared->fp); + ++shared->calls; + ++shared->calls_overflow; + shared->value = ch; + return shared->return_value; +} + +static int +method_underflow (FILE *fp) +{ + log_method (fp, __func__); + TEST_VERIFY (fp == shared->fp); + ++shared->calls; + ++shared->calls_underflow; + return shared->return_value; +} + +static int +method_uflow (FILE *fp) +{ + log_method (fp, __func__); + TEST_VERIFY (fp == shared->fp); + ++shared->calls; + ++shared->calls_uflow; + return shared->return_value; +} + +static int +method_pbackfail (FILE *fp, int ch) +{ + log_method (fp, __func__); + TEST_VERIFY (fp == shared->fp); + ++shared->calls; + ++shared->calls_pbackfail; + shared->value = ch; + return shared->return_value; +} + +static size_t +method_xsputn (FILE *fp, const void *data, size_t n) +{ + log_method (fp, __func__); + TEST_VERIFY (fp == shared->fp); + ++shared->calls; + ++shared->calls_xsputn; + + size_t to_copy = n; + if (n > sizeof (shared->buffer)) + to_copy = sizeof (shared->buffer); + memcpy (shared->buffer, data, to_copy); + shared->buffer_length = to_copy; + return to_copy; +} + +static size_t +method_xsgetn (FILE *fp, void *data, size_t n) +{ + log_method (fp, __func__); + TEST_VERIFY (fp == shared->fp); + ++shared->calls; + ++shared->calls_xsgetn; + return 0; +} + +static off64_t +method_seekoff (FILE *fp, off64_t offset, int dir, int mode) +{ + log_method (fp, __func__); + TEST_VERIFY (fp == shared->fp); + ++shared->calls; + ++shared->calls_seekoff; + return shared->return_value; +} + +static off64_t +method_seekpos (FILE *fp, off64_t offset, int mode) +{ + log_method (fp, __func__); + TEST_VERIFY (fp == shared->fp); + ++shared->calls; + ++shared->calls_seekpos; + return shared->return_value; +} + +static FILE * +method_setbuf (FILE *fp, char *buffer, ssize_t length) +{ + log_method (fp, __func__); + TEST_VERIFY (fp == shared->fp); + ++shared->calls; + ++shared->calls_setbuf; + return fp; +} + +static int +method_sync (FILE *fp) +{ + log_method (fp, __func__); + TEST_VERIFY (fp == shared->fp); + ++shared->calls; + ++shared->calls_sync; + return shared->return_value; +} + +static int +method_doallocate (FILE *fp) +{ + log_method (fp, __func__); + TEST_VERIFY (fp == shared->fp); + ++shared->calls; + ++shared->calls_doallocate; + return shared->return_value; +} + +static ssize_t +method_read (FILE *fp, void *data, ssize_t length) +{ + log_method (fp, __func__); + TEST_VERIFY (fp == shared->fp); + ++shared->calls; + ++shared->calls_read; + return shared->return_value; +} + +static ssize_t +method_write (FILE *fp, const void *data, ssize_t length) +{ + log_method (fp, __func__); + TEST_VERIFY (fp == shared->fp); + ++shared->calls; + ++shared->calls_write; + return shared->return_value; +} + +static off64_t +method_seek (FILE *fp, off64_t offset, int mode) +{ + log_method (fp, __func__); + TEST_VERIFY (fp == shared->fp); + ++shared->calls; + ++shared->calls_seek; + return shared->return_value; +} + +static int +method_close (FILE *fp) +{ + log_method (fp, __func__); + TEST_VERIFY (fp == shared->fp); + ++shared->calls; + ++shared->calls_close; + return shared->return_value; +} + +static int +method_stat (FILE *fp, void *buffer) +{ + log_method (fp, __func__); + TEST_VERIFY (fp == shared->fp); + ++shared->calls; + ++shared->calls_stat; + return shared->return_value; +} + +static int +method_showmanyc (FILE *fp) +{ + log_method (fp, __func__); + TEST_VERIFY (fp == shared->fp); + ++shared->calls; + ++shared->calls_showmanyc; + return shared->return_value; +} + +static void +method_imbue (FILE *fp, void *locale) +{ + log_method (fp, __func__); + TEST_VERIFY (fp == shared->fp); + ++shared->calls; + ++shared->calls_imbue; +} + +/* Our custom vtable. */ + +static const struct _IO_jump_t jumps = +{ + JUMP_INIT_DUMMY, + JUMP_INIT (finish, method_finish), + JUMP_INIT (overflow, method_overflow), + JUMP_INIT (underflow, method_underflow), + JUMP_INIT (uflow, method_uflow), + JUMP_INIT (pbackfail, method_pbackfail), + JUMP_INIT (xsputn, method_xsputn), + JUMP_INIT (xsgetn, method_xsgetn), + JUMP_INIT (seekoff, method_seekoff), + JUMP_INIT (seekpos, method_seekpos), + JUMP_INIT (setbuf, method_setbuf), + JUMP_INIT (sync, method_sync), + JUMP_INIT (doallocate, method_doallocate), + JUMP_INIT (read, method_read), + JUMP_INIT (write, method_write), + JUMP_INIT (seek, method_seek), + JUMP_INIT (close, method_close), + JUMP_INIT (stat, method_stat), + JUMP_INIT (showmanyc, method_showmanyc), + JUMP_INIT (imbue, method_imbue) +}; + +/* Our file implementation. */ + +struct my_file +{ + FILE f; + const struct _IO_jump_t *vtable; +}; + +struct my_file +my_file_create (void) +{ + return (struct my_file) + { + /* Disable locking, so that we do not have to set up a lock + pointer. */ + .f._flags = _IO_USER_LOCK, + + /* Copy the offset from the an initialized handle, instead of + figuring it out from scratch. */ + .f._vtable_offset = stdin->_vtable_offset, + + .vtable = &jumps, + }; +} + +/* Initial tests which do not enable vtable compatibility. */ + +/* Inhibit GCC optimization of fprintf. */ +typedef int (*fprintf_type) (FILE *, const char *, ...); +static const volatile fprintf_type fprintf_ptr = &fprintf; + +static void +without_compatibility_fprintf (void *closure) +{ + /* This call should abort. */ + fprintf_ptr (shared->fp, " "); + _exit (1); +} + +static void +without_compatibility_fputc (void *closure) +{ + /* This call should abort. */ + fputc (' ', shared->fp); + _exit (1); +} + +static void +without_compatibility_fgetc (void *closure) +{ + /* This call should abort. */ + fgetc (shared->fp); + _exit (1); +} + +static void +without_compatibility_fflush (void *closure) +{ + /* This call should abort. */ + fflush (shared->fp); + _exit (1); +} + +/* Exit status after abnormal termination. */ +static int termination_status; + +static void +init_termination_status (void) +{ + pid_t pid = xfork (); + if (pid == 0) + abort (); + xwaitpid (pid, &termination_status, 0); + + TEST_VERIFY (WIFSIGNALED (termination_status)); + TEST_COMPARE (WTERMSIG (termination_status), SIGABRT); +} + +static void +check_for_termination (const char *name, void (*callback) (void *)) +{ + struct my_file file = my_file_create (); + shared->fp = &file.f; + shared->return_value = -1; + shared->calls = 0; + struct support_capture_subprocess proc + = support_capture_subprocess (callback, NULL); + support_capture_subprocess_check (&proc, name, termination_status, + sc_allow_stderr); + const char *message + = "Fatal error: glibc detected an invalid stdio handle\n"; + TEST_COMPARE_BLOB (proc.err.buffer, proc.err.length, + message, strlen (message)); + TEST_COMPARE (shared->calls, 0); + support_capture_subprocess_free (&proc); +} + +/* The test with vtable validation disabled. */ + +/* This function does not have a prototype in libioP.h to prevent + accidental use from within the library (which would disable vtable + verification). */ +void _IO_init (FILE *fp, int flags); + +static void +with_compatibility_fprintf (void *closure) +{ + TEST_COMPARE (fprintf_ptr (shared->fp, "A%sCD", "B"), 4); + TEST_COMPARE (shared->calls, 3); + TEST_COMPARE (shared->calls_xsputn, 3); + TEST_COMPARE_BLOB (shared->buffer, shared->buffer_length, + "CD", 2); +} + +static void +with_compatibility_fputc (void *closure) +{ + shared->return_value = '@'; + TEST_COMPARE (fputc ('@', shared->fp), '@'); + TEST_COMPARE (shared->calls, 1); + TEST_COMPARE (shared->calls_overflow, 1); + TEST_COMPARE (shared->value, '@'); +} + +static void +with_compatibility_fgetc (void *closure) +{ + shared->return_value = 'X'; + TEST_COMPARE (fgetc (shared->fp), 'X'); + TEST_COMPARE (shared->calls, 1); + TEST_COMPARE (shared->calls_uflow, 1); +} + +static void +with_compatibility_fflush (void *closure) +{ + TEST_COMPARE (fflush (shared->fp), 0); + TEST_COMPARE (shared->calls, 1); + TEST_COMPARE (shared->calls_sync, 1); +} + +/* Call CALLBACK in a subprocess, after setting up a custom file + object and updating shared->fp. */ +static void +check_call (const char *name, void (*callback) (void *), + bool initially_disabled) +{ + *shared = (struct shared) + { + .initially_disabled = initially_disabled, + }; + + /* Set up a custom file object. */ + struct my_file file = my_file_create (); + shared->fp = &file.f; + if (shared->initially_disabled) + _IO_init (shared->fp, file.f._flags); + + if (test_verbose > 0) + printf ("info: calling test %s\n", name); + support_isolate_in_subprocess (callback, NULL); +} + +/* Run the tests. INITIALLY_DISABLED indicates whether custom vtables + are disabled when the test starts. */ +static int +run_tests (bool initially_disabled) +{ + /* The test relies on fatal error messages being printed to standard + error. */ + setenv ("LIBC_FATAL_STDERR_", "1", 1); + + shared = support_shared_allocate (sizeof (*shared)); + shared->initially_disabled = initially_disabled; + init_termination_status (); + + if (initially_disabled) + { + check_for_termination ("fprintf", without_compatibility_fprintf); + check_for_termination ("fputc", without_compatibility_fputc); + check_for_termination ("fgetc", without_compatibility_fgetc); + check_for_termination ("fflush", without_compatibility_fflush); + } + + check_call ("fprintf", with_compatibility_fprintf, initially_disabled); + check_call ("fputc", with_compatibility_fputc, initially_disabled); + check_call ("fgetc", with_compatibility_fgetc, initially_disabled); + check_call ("fflush", with_compatibility_fflush, initially_disabled); + + support_shared_free (shared); + shared = NULL; + + return 0; +} diff --git a/libio/tst-vtables-interposed.c b/libio/tst-vtables-interposed.c new file mode 100644 index 0000000000..c8f4e8c7c3 --- /dev/null +++ b/libio/tst-vtables-interposed.c @@ -0,0 +1,37 @@ +/* Test for libio vtables and their validation. Enabled through interposition. + Copyright (C) 2018 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/>. */ + +/* Provide an interposed definition of the standard file handles with + our own vtable. stdout/stdin/stderr will not work as a result, but + a succesful test does not print anything, so this is fine. */ +static const struct _IO_jump_t jumps; +#define _IO_file_jumps jumps +#include "stdfiles.c" + +#include "tst-vtables-common.c" + +static int +do_test (void) +{ + return run_tests (false); +} + +/* Calling setvbuf in the test driver is not supported with our + interposed file handles. */ +#define TEST_NO_SETVBUF +#include <support/test-driver.c> diff --git a/libio/tst-vtables.c b/libio/tst-vtables.c new file mode 100644 index 0000000000..f16acf5d23 --- /dev/null +++ b/libio/tst-vtables.c @@ -0,0 +1,29 @@ +/* Test for libio vtables and their validation. Initially disabled case. + Copyright (C) 2018 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 "libioP.h" + +#include "tst-vtables-common.c" + +static int +do_test (void) +{ + return run_tests (true); +} + +#include <support/test-driver.c> diff --git a/libio/vasprintf.c b/libio/vasprintf.c index a9a21545a2..50e3559ab8 100644 --- a/libio/vasprintf.c +++ b/libio/vasprintf.c @@ -54,8 +54,8 @@ _IO_vasprintf (char **result_ptr, const char *format, _IO_va_list args) _IO_JUMPS (&sf._sbf) = &_IO_str_jumps; _IO_str_init_static_internal (&sf, string, init_string_size, string); sf._sbf._f._flags &= ~_IO_USER_BUF; - sf._s._allocate_buffer = (_IO_alloc_type) malloc; - sf._s._free_buffer = (_IO_free_type) free; + sf._s._allocate_buffer_unused = (_IO_alloc_type) malloc; + sf._s._free_buffer_unused = (_IO_free_type) free; ret = _IO_vfprintf (&sf._sbf._f, format, args); if (ret < 0) { diff --git a/libio/vtables.c b/libio/vtables.c index 41b48db98c..a11226ab17 100644 --- a/libio/vtables.c +++ b/libio/vtables.c @@ -70,3 +70,19 @@ _IO_vtable_check (void) __libc_fatal ("Fatal error: glibc detected an invalid stdio handle\n"); } + +/* Some variants of libstdc++ interpose _IO_2_1_stdin_ etc. and + install their own vtables directly, without calling _IO_init or + other functions. Detect this by looking at the vtables values + during startup, and disable vtable validation in this case. */ +#ifdef SHARED +__attribute__ ((constructor)) +static void +check_stdfiles_vtables (void) +{ + if (_IO_2_1_stdin_.vtable != &_IO_file_jumps + || _IO_2_1_stdout_.vtable != &_IO_file_jumps + || _IO_2_1_stderr_.vtable != &_IO_file_jumps) + IO_set_accept_foreign_vtables (&_IO_vtable_check); +} +#endif diff --git a/libio/wmemstream.c b/libio/wmemstream.c index 103a760bf5..fdabaae6a9 100644 --- a/libio/wmemstream.c +++ b/libio/wmemstream.c @@ -92,8 +92,8 @@ open_wmemstream (wchar_t **bufloc, _IO_size_t *sizeloc) _IO_wstr_init_static (&new_f->fp._sf._sbf._f, buf, _IO_BUFSIZ / sizeof (wchar_t), buf); new_f->fp._sf._sbf._f._flags2 &= ~_IO_FLAGS2_USER_WBUF; - new_f->fp._sf._s._allocate_buffer = (_IO_alloc_type) malloc; - new_f->fp._sf._s._free_buffer = (_IO_free_type) free; + new_f->fp._sf._s._allocate_buffer_unused = (_IO_alloc_type) malloc; + new_f->fp._sf._s._free_buffer_unused = (_IO_free_type) free; new_f->fp.bufloc = bufloc; new_f->fp.sizeloc = sizeloc; diff --git a/libio/wstrops.c b/libio/wstrops.c index bb62fd6702..8f5d45a9d1 100644 --- a/libio/wstrops.c +++ b/libio/wstrops.c @@ -63,7 +63,7 @@ _IO_wstr_init_static (_IO_FILE *fp, wchar_t *ptr, _IO_size_t size, fp->_wide_data->_IO_read_end = end; } /* A null _allocate_buffer function flags the strfile as being static. */ - (((_IO_strfile *) fp)->_s._allocate_buffer) = (_IO_alloc_type)0; + (((_IO_strfile *) fp)->_s._allocate_buffer_unused) = (_IO_alloc_type)0; } _IO_wint_t @@ -95,9 +95,7 @@ _IO_wstr_overflow (_IO_FILE *fp, _IO_wint_t c) || __glibc_unlikely (new_size > SIZE_MAX / sizeof (wchar_t))) return EOF; - new_buf - = (wchar_t *) (*((_IO_strfile *) fp)->_s._allocate_buffer) (new_size - * sizeof (wchar_t)); + new_buf = malloc (new_size * sizeof (wchar_t)); if (new_buf == NULL) { /* __ferror(fp) = 1; */ @@ -106,7 +104,7 @@ _IO_wstr_overflow (_IO_FILE *fp, _IO_wint_t c) if (old_buf) { __wmemcpy (new_buf, old_buf, old_wblen); - (*((_IO_strfile *) fp)->_s._free_buffer) (old_buf); + free (old_buf); /* Make sure _IO_setb won't try to delete _IO_buf_base. */ fp->_wide_data->_IO_buf_base = NULL; } @@ -186,16 +184,14 @@ enlarge_userbuf (_IO_FILE *fp, _IO_off64_t offset, int reading) return 1; wchar_t *oldbuf = wd->_IO_buf_base; - wchar_t *newbuf - = (wchar_t *) (*((_IO_strfile *) fp)->_s._allocate_buffer) (newsize - * sizeof (wchar_t)); + wchar_t *newbuf = malloc (newsize * sizeof (wchar_t)); if (newbuf == NULL) return 1; if (oldbuf != NULL) { __wmemcpy (newbuf, oldbuf, _IO_wblen (fp)); - (*((_IO_strfile *) fp)->_s._free_buffer) (oldbuf); + free (oldbuf); /* Make sure _IO_setb won't try to delete _IO_buf_base. */ wd->_IO_buf_base = NULL; @@ -357,7 +353,7 @@ void _IO_wstr_finish (_IO_FILE *fp, int dummy) { if (fp->_wide_data->_IO_buf_base && !(fp->_flags2 & _IO_FLAGS2_USER_WBUF)) - (((_IO_strfile *) fp)->_s._free_buffer) (fp->_wide_data->_IO_buf_base); + free (fp->_wide_data->_IO_buf_base); fp->_wide_data->_IO_buf_base = NULL; _IO_wdefault_finish (fp, 0); diff --git a/malloc/Makefile b/malloc/Makefile index 9e23db9343..a50a93b252 100644 --- a/malloc/Makefile +++ b/malloc/Makefile @@ -35,6 +35,7 @@ tests := mallocbug tst-malloc tst-valloc tst-calloc tst-obstack \ tst-interpose-thread \ tst-alloc_buffer \ tst-malloc-tcache-leak \ + tst-malloc-too-large \ tests-static := \ tst-interpose-static-nothread \ diff --git a/malloc/malloc.c b/malloc/malloc.c index 6a52c288de..49e8ed69c2 100644 --- a/malloc/malloc.c +++ b/malloc/malloc.c @@ -1231,14 +1231,21 @@ nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ MINSIZE : \ ((req) + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK) -/* Same, except also perform argument check */ - -#define checked_request2size(req, sz) \ - if (REQUEST_OUT_OF_RANGE (req)) { \ - __set_errno (ENOMEM); \ - return 0; \ - } \ - (sz) = request2size (req); +/* Same, except also perform an argument and result check. First, we check + that the padding done by request2size didn't result in an integer + overflow. Then we check (using REQUEST_OUT_OF_RANGE) that the resulting + size isn't so large that a later alignment would lead to another integer + overflow. */ +#define checked_request2size(req, sz) \ +({ \ + (sz) = request2size (req); \ + if (((sz) < (req)) \ + || REQUEST_OUT_OF_RANGE (sz)) \ + { \ + __set_errno (ENOMEM); \ + return 0; \ + } \ +}) /* --------------- Physical chunk operations --------------- @@ -4521,11 +4528,6 @@ _int_realloc(mstate av, mchunkptr oldp, INTERNAL_SIZE_T oldsize, mchunkptr bck; /* misc temp for linking */ mchunkptr fwd; /* misc temp for linking */ - unsigned long copysize; /* bytes to copy */ - unsigned int ncopies; /* INTERNAL_SIZE_T words to copy */ - INTERNAL_SIZE_T* s; /* copy source */ - INTERNAL_SIZE_T* d; /* copy destination */ - /* oldmem size */ if (__builtin_expect (chunksize_nomask (oldp) <= 2 * SIZE_SZ, 0) || __builtin_expect (oldsize >= av->system_mem, 0)) @@ -4593,43 +4595,7 @@ _int_realloc(mstate av, mchunkptr oldp, INTERNAL_SIZE_T oldsize, } else { - /* - Unroll copy of <= 36 bytes (72 if 8byte sizes) - We know that contents have an odd number of - INTERNAL_SIZE_T-sized words; minimally 3. - */ - - copysize = oldsize - SIZE_SZ; - s = (INTERNAL_SIZE_T *) (chunk2mem (oldp)); - d = (INTERNAL_SIZE_T *) (newmem); - ncopies = copysize / sizeof (INTERNAL_SIZE_T); - assert (ncopies >= 3); - - if (ncopies > 9) - memcpy (d, s, copysize); - - else - { - *(d + 0) = *(s + 0); - *(d + 1) = *(s + 1); - *(d + 2) = *(s + 2); - if (ncopies > 4) - { - *(d + 3) = *(s + 3); - *(d + 4) = *(s + 4); - if (ncopies > 6) - { - *(d + 5) = *(s + 5); - *(d + 6) = *(s + 6); - if (ncopies > 8) - { - *(d + 7) = *(s + 7); - *(d + 8) = *(s + 8); - } - } - } - } - + memcpy (newmem, chunk2mem (oldp), oldsize - SIZE_SZ); _int_free (av, oldp, 1); check_inuse_chunk (av, newp); return chunk2mem (newp); @@ -4691,6 +4657,13 @@ _int_memalign (mstate av, size_t alignment, size_t bytes) */ + /* Check for overflow. */ + if (nb > SIZE_MAX - alignment - MINSIZE) + { + __set_errno (ENOMEM); + return 0; + } + /* Call malloc with worst case padding to hit alignment. */ m = (char *) (_int_malloc (av, nb + alignment + MINSIZE)); diff --git a/malloc/tst-malloc-too-large.c b/malloc/tst-malloc-too-large.c new file mode 100644 index 0000000000..10fb136528 --- /dev/null +++ b/malloc/tst-malloc-too-large.c @@ -0,0 +1,253 @@ +/* Test and verify that too-large memory allocations fail with ENOMEM. + Copyright (C) 2018 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/>. */ + +/* Bug 22375 reported a regression in malloc where if after malloc'ing then + free'ing a small block of memory, malloc is then called with a really + large size argument (close to SIZE_MAX): instead of returning NULL and + setting errno to ENOMEM, malloc incorrectly returns the previously + allocated block instead. Bug 22343 reported a similar case where + posix_memalign incorrectly returns successfully when called with an with + a really large size argument. + + Both of these were caused by integer overflows in the allocator when it + was trying to pad the requested size to allow for book-keeping or + alignment. This test guards against such bugs by repeatedly allocating + and freeing small blocks of memory then trying to allocate various block + sizes larger than the memory bus width of 64-bit targets, or almost + as large as SIZE_MAX on 32-bit targets supported by glibc. In each case, + it verifies that such impossibly large allocations correctly fail. */ + + +#include <stdlib.h> +#include <malloc.h> +#include <errno.h> +#include <stdint.h> +#include <sys/resource.h> +#include <libc-diag.h> +#include <support/check.h> +#include <unistd.h> +#include <sys/param.h> + + +/* This function prepares for each 'too-large memory allocation' test by + performing a small successful malloc/free and resetting errno prior to + the actual test. */ +static void +test_setup (void) +{ + void *volatile ptr = malloc (16); + TEST_VERIFY_EXIT (ptr != NULL); + free (ptr); + errno = 0; +} + + +/* This function tests each of: + - malloc (SIZE) + - realloc (PTR_FOR_REALLOC, SIZE) + - for various values of NMEMB: + - calloc (NMEMB, SIZE/NMEMB) + - calloc (SIZE/NMEMB, NMEMB) + - reallocarray (PTR_FOR_REALLOC, NMEMB, SIZE/NMEMB) + - reallocarray (PTR_FOR_REALLOC, SIZE/NMEMB, NMEMB) + and precedes each of these tests with a small malloc/free before it. */ +static void +test_large_allocations (size_t size) +{ + void * ptr_to_realloc; + + test_setup (); + TEST_VERIFY (malloc (size) == NULL); + TEST_VERIFY (errno == ENOMEM); + + ptr_to_realloc = malloc (16); + TEST_VERIFY_EXIT (ptr_to_realloc != NULL); + test_setup (); + TEST_VERIFY (realloc (ptr_to_realloc, size) == NULL); + TEST_VERIFY (errno == ENOMEM); + free (ptr_to_realloc); + + for (size_t nmemb = 1; nmemb <= 8; nmemb *= 2) + if ((size % nmemb) == 0) + { + test_setup (); + TEST_VERIFY (calloc (nmemb, size / nmemb) == NULL); + TEST_VERIFY (errno == ENOMEM); + + test_setup (); + TEST_VERIFY (calloc (size / nmemb, nmemb) == NULL); + TEST_VERIFY (errno == ENOMEM); + + ptr_to_realloc = malloc (16); + TEST_VERIFY_EXIT (ptr_to_realloc != NULL); + test_setup (); + TEST_VERIFY (reallocarray (ptr_to_realloc, nmemb, size / nmemb) == NULL); + TEST_VERIFY (errno == ENOMEM); + free (ptr_to_realloc); + + ptr_to_realloc = malloc (16); + TEST_VERIFY_EXIT (ptr_to_realloc != NULL); + test_setup (); + TEST_VERIFY (reallocarray (ptr_to_realloc, size / nmemb, nmemb) == NULL); + TEST_VERIFY (errno == ENOMEM); + free (ptr_to_realloc); + } + else + break; +} + + +static long pagesize; + +/* This function tests the following aligned memory allocation functions + using several valid alignments and precedes each allocation test with a + small malloc/free before it: + memalign, posix_memalign, aligned_alloc, valloc, pvalloc. */ +static void +test_large_aligned_allocations (size_t size) +{ + /* ptr stores the result of posix_memalign but since all those calls + should fail, posix_memalign should never change ptr. We set it to + NULL here and later on we check that it remains NULL after each + posix_memalign call. */ + void * ptr = NULL; + + size_t align; + + /* All aligned memory allocation functions expect an alignment that is a + power of 2. Given this, we test each of them with every valid + alignment from 1 thru PAGESIZE. */ + for (align = 1; align <= pagesize; align *= 2) + { + test_setup (); + TEST_VERIFY (memalign (align, size) == NULL); + TEST_VERIFY (errno == ENOMEM); + + /* posix_memalign expects an alignment that is a power of 2 *and* a + multiple of sizeof (void *). */ + if ((align % sizeof (void *)) == 0) + { + test_setup (); + TEST_VERIFY (posix_memalign (&ptr, align, size) == ENOMEM); + TEST_VERIFY (ptr == NULL); + } + + /* aligned_alloc expects a size that is a multiple of alignment. */ + if ((size % align) == 0) + { + test_setup (); + TEST_VERIFY (aligned_alloc (align, size) == NULL); + TEST_VERIFY (errno == ENOMEM); + } + } + + /* Both valloc and pvalloc return page-aligned memory. */ + + test_setup (); + TEST_VERIFY (valloc (size) == NULL); + TEST_VERIFY (errno == ENOMEM); + + test_setup (); + TEST_VERIFY (pvalloc (size) == NULL); + TEST_VERIFY (errno == ENOMEM); +} + + +#define FOURTEEN_ON_BITS ((1UL << 14) - 1) +#define FIFTY_ON_BITS ((1UL << 50) - 1) + + +static int +do_test (void) +{ + +#if __WORDSIZE >= 64 + + /* This test assumes that none of the supported targets have an address + bus wider than 50 bits, and that therefore allocations for sizes wider + than 50 bits will fail. Here, we ensure that the assumption continues + to be true in the future when we might have address buses wider than 50 + bits. */ + + struct rlimit alloc_size_limit + = { + .rlim_cur = FIFTY_ON_BITS, + .rlim_max = FIFTY_ON_BITS + }; + + setrlimit (RLIMIT_AS, &alloc_size_limit); + +#endif /* __WORDSIZE >= 64 */ + + DIAG_PUSH_NEEDS_COMMENT; +#if __GNUC_PREREQ (7, 0) + /* GCC 7 warns about too-large allocations; here we want to test + that they fail. */ + DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than="); +#endif + + /* Aligned memory allocation functions need to be tested up to alignment + size equivalent to page size, which should be a power of 2. */ + pagesize = sysconf (_SC_PAGESIZE); + TEST_VERIFY_EXIT (powerof2 (pagesize)); + + /* Loop 1: Ensure that all allocations with SIZE close to SIZE_MAX, i.e. + in the range (SIZE_MAX - 2^14, SIZE_MAX], fail. + + We can expect that this range of allocation sizes will always lead to + an allocation failure on both 64 and 32 bit targets, because: + + 1. no currently supported 64-bit target has an address bus wider than + 50 bits -- and (2^64 - 2^14) is much wider than that; + + 2. on 32-bit targets, even though 2^32 is only 4 GB and potentially + addressable, glibc itself is more than 2^14 bytes in size, and + therefore once glibc is loaded, less than (2^32 - 2^14) bytes remain + available. */ + + for (size_t i = 0; i <= FOURTEEN_ON_BITS; i++) + { + test_large_allocations (SIZE_MAX - i); + test_large_aligned_allocations (SIZE_MAX - i); + } + +#if __WORDSIZE >= 64 + /* On 64-bit targets, we need to test a much wider range of too-large + sizes, so we test at intervals of (1 << 50) that allocation sizes + ranging from SIZE_MAX down to (1 << 50) fail: + The 14 MSBs are decremented starting from "all ON" going down to 1, + the 50 LSBs are "all ON" and then "all OFF" during every iteration. */ + for (size_t msbs = FOURTEEN_ON_BITS; msbs >= 1; msbs--) + { + size_t size = (msbs << 50) | FIFTY_ON_BITS; + test_large_allocations (size); + test_large_aligned_allocations (size); + + size = msbs << 50; + test_large_allocations (size); + test_large_aligned_allocations (size); + } +#endif /* __WORDSIZE >= 64 */ + + DIAG_POP_NEEDS_COMMENT; + + return 0; +} + + +#include <support/test-driver.c> diff --git a/manual/llio.texi b/manual/llio.texi index e72c53c785..4ce9ee360e 100644 --- a/manual/llio.texi +++ b/manual/llio.texi @@ -754,9 +754,13 @@ When the source file is compiled using @code{_FILE_OFFSET_BITS == 64} on a @c This is a syscall for Linux v4.6. The sysdeps/posix fallback emulation @c is also MT-Safe since it calls preadv. -This function is similar to the @code{preadv} function, with the difference -it adds an extra @var{flags} parameter of type @code{int}. The supported -@var{flags} are dependent of the underlying system. For Linux it supports: +This function is similar to the @code{preadv} function, with the +difference it adds an extra @var{flags} parameter of type @code{int}. +Additionally, if @var{offset} is @math{-1}, the current file position +is used and updated (like the @code{readv} function). + +The supported @var{flags} are dependent of the underlying system. For +Linux it supports: @vtable @code @item RWF_HIPRI @@ -823,10 +827,13 @@ When the source file is compiled using @code{_FILE_OFFSET_BITS == 64} on a @c This is a syscall for Linux v4.6. The sysdeps/posix fallback emulation @c is also MT-Safe since it calls pwritev. -This function is similar to the @code{pwritev} function, with the difference -it adds an extra @var{flags} parameter of type @code{int}. The supported -@var{flags} are dependent of the underlying system and for Linux it supports -the same ones as for @code{preadv2}. +This function is similar to the @code{pwritev} function, with the +difference it adds an extra @var{flags} parameter of type @code{int}. +Additionally, if @var{offset} is @math{-1}, the current file position +should is used and updated (like the @code{writev} function). + +The supported @var{flags} are dependent of the underlying system. For +Linux, the supported flags are the same as those for @code{preadv2}. When the source file is compiled with @code{_FILE_OFFSET_BITS == 64} the @code{pwritev2} function is in fact @code{pwritev64v2} and the type diff --git a/math/math.h b/math/math.h index 5a282b8c6b..4c30306d58 100644 --- a/math/math.h +++ b/math/math.h @@ -880,7 +880,7 @@ template<> struct __iseqsig_type<double> template<> struct __iseqsig_type<long double> { - static int __call (double __x, double __y) throw () + static int __call (long double __x, long double __y) throw () { # ifndef __NO_LONG_DOUBLE_MATH return __iseqsigl (__x, __y); diff --git a/misc/sys/cdefs.h b/misc/sys/cdefs.h index 0c808216a4..41261fea39 100644 --- a/misc/sys/cdefs.h +++ b/misc/sys/cdefs.h @@ -408,6 +408,15 @@ # endif #endif +#if __GNUC_PREREQ (8, 0) +/* Describes a char array whose address can safely be passed as the first + argument to strncpy and strncat, as the char array is not necessarily + a NUL-terminated string. */ +# define __attribute_nonstring__ __attribute__ ((__nonstring__)) +#else +# define __attribute_nonstring__ +#endif + #if (!defined _Static_assert && !defined __cplusplus \ && (defined __STDC_VERSION__ ? __STDC_VERSION__ : 0) < 201112 \ && (!__GNUC_PREREQ (4, 6) || defined __STRICT_ANSI__)) diff --git a/misc/tst-preadvwritev-common.c b/misc/tst-preadvwritev-common.c index 676d4953ac..7f9a63f1f5 100644 --- a/misc/tst-preadvwritev-common.c +++ b/misc/tst-preadvwritev-common.c @@ -16,6 +16,7 @@ License along with the GNU C Library; if not, see <http://www.gnu.org/licenses/>. */ +#include <array_length.h> #include <stdio.h> #include <stdint.h> #include <errno.h> @@ -25,6 +26,7 @@ #include <support/check.h> #include <support/temp_file.h> +#include <support/xunistd.h> static char *temp_filename; static int temp_fd; @@ -50,6 +52,42 @@ do_prepare (int argc, char **argv) pwritev (__fd, __iov, __iovcnt, __offset) #endif +static __attribute__ ((unused)) void +do_test_without_offset (void) +{ + xftruncate (temp_fd, 0); + + xwrite (temp_fd, "123", 3); + xlseek (temp_fd, 2, SEEK_SET); + { + struct iovec iov[] = + { + { (void *) "abc", 3 }, + { (void *) "xyzt", 4 }, + }; + TEST_COMPARE (PWRITEV (temp_fd, iov, array_length (iov), -1), 7); + } + TEST_COMPARE (xlseek (temp_fd, 0, SEEK_CUR), 9); + + xlseek (temp_fd, 1, SEEK_SET); + char buf1[3]; + char buf2[2]; + { + struct iovec iov[] = + { + { buf1, sizeof (buf1) }, + { buf2, sizeof (buf2) }, + }; + TEST_COMPARE (PREADV (temp_fd, iov, array_length (iov), -1), + sizeof (buf1) + sizeof (buf2)); + TEST_COMPARE (memcmp ("2ab", buf1, sizeof (buf1)), 0); + TEST_COMPARE (memcmp ("cx", buf2, sizeof (buf2)), 0); + TEST_COMPARE (xlseek (temp_fd, 0, SEEK_CUR), 6); + } + + xftruncate (temp_fd, 0); +} + static int do_test_with_offset (off_t offset) { diff --git a/misc/tst-preadvwritev2-common.c b/misc/tst-preadvwritev2-common.c index 8abedc14d0..9570882fa6 100644 --- a/misc/tst-preadvwritev2-common.c +++ b/misc/tst-preadvwritev2-common.c @@ -19,10 +19,85 @@ #include <limits.h> #include <support/check.h> +#ifndef RWF_HIPRI +# define RWF_HIPRI 0 +#endif +#ifndef RWF_DSYNC +# define RWF_DSYNC 0 +#endif +#ifndef RWF_SYNC +# define RWF_SYNC 0 +#endif +#ifndef RWF_NOWAIT +# define RWF_NOWAIT 0 +#endif +#ifndef RWF_APPEND +# define RWF_APPEND 0 +#endif +#define RWF_SUPPORTED (RWF_HIPRI | RWF_DSYNC | RWF_SYNC | RWF_NOWAIT \ + | RWF_APPEND) + +static void +do_test_with_invalid_fd (void) +{ + char buf[256]; + struct iovec iov = { buf, sizeof buf }; + + /* Check with flag being 0 to use the fallback code which calls pwritev + or writev. */ + TEST_VERIFY (preadv2 (-1, &iov, 1, -1, 0) == -1); + TEST_COMPARE (errno, EBADF); + TEST_VERIFY (pwritev2 (-1, &iov, 1, -1, 0) == -1); + TEST_COMPARE (errno, EBADF); + + /* Same tests as before but with flags being different than 0. Since + there is no emulation for any flag value, fallback code returns + ENOTSUP. This is different running on a kernel with preadv2/pwritev2 + support, where EBADF is returned). */ + TEST_VERIFY (preadv2 (-1, &iov, 1, 0, RWF_HIPRI) == -1); + TEST_VERIFY (errno == EBADF || errno == ENOTSUP); + TEST_VERIFY (pwritev2 (-1, &iov, 1, 0, RWF_HIPRI) == -1); + TEST_VERIFY (errno == EBADF || errno == ENOTSUP); +} + +static void +do_test_with_invalid_iov (void) +{ + { + char buf[256]; + struct iovec iov; + + iov.iov_base = buf; + iov.iov_len = (size_t)SSIZE_MAX + 1; + + TEST_VERIFY (preadv2 (temp_fd, &iov, 1, 0, 0) == -1); + TEST_COMPARE (errno, EINVAL); + TEST_VERIFY (pwritev2 (temp_fd, &iov, 1, 0, 0) == -1); + TEST_COMPARE (errno, EINVAL); + + /* Same as for invalid file descriptor tests, emulation fallback + first checks for flag value and return ENOTSUP. */ + TEST_VERIFY (preadv2 (temp_fd, &iov, 1, 0, RWF_HIPRI) == -1); + TEST_VERIFY (errno == EINVAL || errno == ENOTSUP); + TEST_VERIFY (pwritev2 (temp_fd, &iov, 1, 0, RWF_HIPRI) == -1); + TEST_VERIFY (errno == EINVAL || errno == ENOTSUP); + } + + { + /* An invalid iovec buffer should trigger an invalid memory access + or an error (Linux for instance returns EFAULT). */ + struct iovec iov[IOV_MAX+1] = { 0 }; + + TEST_VERIFY (preadv2 (temp_fd, iov, IOV_MAX + 1, 0, RWF_HIPRI) == -1); + TEST_VERIFY (errno == EINVAL || errno == ENOTSUP); + TEST_VERIFY (pwritev2 (temp_fd, iov, IOV_MAX + 1, 0, RWF_HIPRI) == -1); + TEST_VERIFY (errno == EINVAL || errno == ENOTSUP); + } +} + static void do_test_with_invalid_flags (void) { -#define RWF_SUPPORTED (RWF_HIPRI | RWF_DSYNC | RWF_SYNC | RWF_NOWAIT) /* Set the next bit from the mask of all supported flags. */ int invalid_flag = __builtin_clz (RWF_SUPPORTED); invalid_flag = 0x1 << ((sizeof (int) * CHAR_BIT) - invalid_flag); diff --git a/misc/tst-preadvwritev2.c b/misc/tst-preadvwritev2.c index 682c7579da..bebd2e56d6 100644 --- a/misc/tst-preadvwritev2.c +++ b/misc/tst-preadvwritev2.c @@ -29,6 +29,9 @@ static int do_test (void) { do_test_with_invalid_flags (); + do_test_without_offset (); + do_test_with_invalid_fd (); + do_test_with_invalid_iov (); return do_test_with_offset (0); } diff --git a/misc/tst-preadvwritev64v2.c b/misc/tst-preadvwritev64v2.c index 9ddc7625f0..3d03e32484 100644 --- a/misc/tst-preadvwritev64v2.c +++ b/misc/tst-preadvwritev64v2.c @@ -31,6 +31,9 @@ static int do_test (void) { do_test_with_invalid_flags (); + do_test_without_offset (); + do_test_with_invalid_fd (); + do_test_with_invalid_iov (); return do_test_with_offset (0); } diff --git a/nptl/pthread_cond_common.c b/nptl/pthread_cond_common.c index ffbbde4106..c99435e439 100644 --- a/nptl/pthread_cond_common.c +++ b/nptl/pthread_cond_common.c @@ -405,8 +405,12 @@ __condvar_quiesce_and_switch_g1 (pthread_cond_t *cond, uint64_t wseq, { /* There is still a waiter after spinning. Set the wake-request flag and block. Relaxed MO is fine because this is just about - this futex word. */ - r = atomic_fetch_or_relaxed (cond->__data.__g_refs + g1, 1); + this futex word. + + Update r to include the set wake-request flag so that the upcoming + futex_wait only blocks if the flag is still set (otherwise, we'd + violate the basic client-side futex protocol). */ + r = atomic_fetch_or_relaxed (cond->__data.__g_refs + g1, 1) | 1; if ((r >> 1) > 0) futex_wait_simple (cond->__data.__g_refs + g1, r, private); diff --git a/nptl/tst-attr3.c b/nptl/tst-attr3.c index bc23386daf..420a7dba8b 100644 --- a/nptl/tst-attr3.c +++ b/nptl/tst-attr3.c @@ -26,6 +26,7 @@ #include <unistd.h> #include <stackinfo.h> +#include <libc-diag.h> static void * tf (void *arg) @@ -362,7 +363,16 @@ do_test (void) result = 1; } + DIAG_PUSH_NEEDS_COMMENT; +#if __GNUC_PREREQ (7, 0) + /* GCC 8 warns about aliasing of the restrict-qualified arguments + passed &a. Since pthread_create does not dereference its fourth + argument, this aliasing, which is deliberate in this test, cannot + in fact cause problems. */ + DIAG_IGNORE_NEEDS_COMMENT (8, "-Wrestrict"); +#endif err = pthread_create (&th, &a, tf, &a); + DIAG_POP_NEEDS_COMMENT; if (err) { error (0, err, "pthread_create #2 failed"); @@ -388,7 +398,16 @@ do_test (void) result = 1; } + DIAG_PUSH_NEEDS_COMMENT; +#if __GNUC_PREREQ (7, 0) + /* GCC 8 warns about aliasing of the restrict-qualified arguments + passed &a. Since pthread_create does not dereference its fourth + argument, this aliasing, which is deliberate in this test, cannot + in fact cause problems. */ + DIAG_IGNORE_NEEDS_COMMENT (8, "-Wrestrict"); +#endif err = pthread_create (&th, &a, tf, &a); + DIAG_POP_NEEDS_COMMENT; if (err) { error (0, err, "pthread_create #3 failed"); diff --git a/nscd/connections.c b/nscd/connections.c index cc1ed72077..dab722dcb2 100644 --- a/nscd/connections.c +++ b/nscd/connections.c @@ -1077,14 +1077,15 @@ cannot handle old request version %d; current version is %d"), if (debug_level > 0) { #ifdef SO_PEERCRED + char pbuf[sizeof ("/proc//exe") + 3 * sizeof (long int)]; # ifdef PATH_MAX char buf[PATH_MAX]; # else char buf[4096]; # endif - snprintf (buf, sizeof (buf), "/proc/%ld/exe", (long int) pid); - ssize_t n = readlink (buf, buf, sizeof (buf) - 1); + snprintf (pbuf, sizeof (pbuf), "/proc/%ld/exe", (long int) pid); + ssize_t n = readlink (pbuf, buf, sizeof (buf) - 1); if (n <= 0) dbg_log (_("\ diff --git a/nscd/dbg_log.c b/nscd/dbg_log.c index d4b19acc0c..2190c16ce5 100644 --- a/nscd/dbg_log.c +++ b/nscd/dbg_log.c @@ -67,7 +67,7 @@ dbg_log (const char *fmt,...) char buf[256]; strftime (buf, sizeof (buf), "%c", &now); - char msg[512]; + char msg[1024]; snprintf (msg, sizeof (msg), "%s - %d: %s%s", buf, getpid (), msg2, msg2[strlen (msg2) - 1] == '\n' ? "" : "\n"); if (dbgout) diff --git a/nscd/netgroupcache.c b/nscd/netgroupcache.c index cd0c3ea19b..741c3bba2b 100644 --- a/nscd/netgroupcache.c +++ b/nscd/netgroupcache.c @@ -480,7 +480,7 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req, { const char *group = key; key = (char *) rawmemchr (key, '\0') + 1; - size_t group_len = key - group - 1; + size_t group_len = key - group; const char *host = *key++ ? key : NULL; if (host != NULL) key = (char *) rawmemchr (key, '\0') + 1; diff --git a/resolv/Makefile b/resolv/Makefile index ec7e4fd146..8eb405a741 100644 --- a/resolv/Makefile +++ b/resolv/Makefile @@ -53,6 +53,7 @@ tests += \ tst-resolv-network \ tst-resolv-res_init-multi \ tst-resolv-search \ + tst-p_secstodate \ # These tests need libdl. ifeq (yes,$(build-shared)) @@ -178,7 +179,7 @@ $(objpfx)tst-resolv-canonname: \ $(objpfx)tst-ns_name: $(objpfx)libresolv.so $(objpfx)tst-ns_name.out: tst-ns_name.data $(objpfx)tst-ns_name_compress: $(objpfx)libresolv.so - +$(objpfx)tst-p_secstodate: $(objpfx)libresolv.so # This test case uses the deprecated RES_USE_INET6 resolver option. CFLAGS-tst-res_use_inet6.c += -Wno-error diff --git a/resolv/gai_misc.c b/resolv/gai_misc.c index fd9aa356be..5e5e4b82fe 100644 --- a/resolv/gai_misc.c +++ b/resolv/gai_misc.c @@ -264,8 +264,11 @@ __gai_enqueue_request (struct gaicb *gaicbp) /* We cannot create a thread in the moment and there is also no thread running. This is a problem. `errno' is set to EAGAIN if this is only a temporary problem. */ - assert (lastp->next == newp); - lastp->next = NULL; + assert (requests == newp || lastp->next == newp); + if (lastp != NULL) + lastp->next = NULL; + else + requests = NULL; requests_tail = lastp; newp->next = freelist; diff --git a/resolv/res_debug.c b/resolv/res_debug.c index 919b86e2b3..154a4f8e24 100644 --- a/resolv/res_debug.c +++ b/resolv/res_debug.c @@ -107,6 +107,7 @@ #include <string.h> #include <time.h> #include <shlib-compat.h> +#include <libc-diag.h> #ifdef SPRINTF_CHAR # define SPRINTF(x) strlen(sprintf/**/x) @@ -1054,6 +1055,8 @@ libresolv_hidden_def (__dn_count_labels) /* * Make dates expressed in seconds-since-Jan-1-1970 easy to read. * SIG records are required to be printed like this, by the Secure DNS RFC. + * This is an obsolescent function and does not handle dates outside the + * signed 32-bit range. */ char * p_secstodate (u_long secs) { @@ -1063,12 +1066,31 @@ p_secstodate (u_long secs) { struct tm *time; struct tm timebuf; - time = __gmtime_r(&clock, &timebuf); + /* The call to __gmtime_r can never produce a year overflowing + the range of int, given the check on SECS, but check for a + NULL return anyway to avoid a null pointer dereference in + case there are any other unspecified errors. */ + if (secs > 0x7fffffff + || (time = __gmtime_r (&clock, &timebuf)) == NULL) { + strcpy (output, "<overflow>"); + __set_errno (EOVERFLOW); + return output; + } time->tm_year += 1900; time->tm_mon += 1; + /* The struct tm fields, given the above range check, + must have values that mean this sprintf exactly fills the + buffer. But as of GCC 8 of 2017-11-21, GCC cannot tell + that, even given range checks on all fields with + __builtin_unreachable called for out-of-range values. */ + DIAG_PUSH_NEEDS_COMMENT; +#if __GNUC_PREREQ (7, 0) + DIAG_IGNORE_NEEDS_COMMENT (8, "-Wformat-overflow="); +#endif sprintf(output, "%04d%02d%02d%02d%02d%02d", time->tm_year, time->tm_mon, time->tm_mday, time->tm_hour, time->tm_min, time->tm_sec); + DIAG_POP_NEEDS_COMMENT; return (output); } libresolv_hidden_def (__p_secstodate) diff --git a/resolv/res_send.c b/resolv/res_send.c index b396aae03c..83f35f60da 100644 --- a/resolv/res_send.c +++ b/resolv/res_send.c @@ -471,6 +471,11 @@ __res_context_send (struct resolv_context *ctx, '\0', sizeof (struct sockaddr_in6) - sizeof (struct sockaddr_in)); + else + { + __set_errno (ENOMEM); + return -1; + } } EXT(statp).nscount = statp->nscount; } @@ -1152,25 +1157,27 @@ send_dg(res_state statp, if (have_sendmmsg >= 0 && nwritten == 0 && buf2 != NULL && !single_request) { - struct iovec iov[2]; - struct mmsghdr reqs[2]; - reqs[0].msg_hdr.msg_name = NULL; - reqs[0].msg_hdr.msg_namelen = 0; - reqs[0].msg_hdr.msg_iov = &iov[0]; - reqs[0].msg_hdr.msg_iovlen = 1; - iov[0].iov_base = (void *) buf; - iov[0].iov_len = buflen; - reqs[0].msg_hdr.msg_control = NULL; - reqs[0].msg_hdr.msg_controllen = 0; - - reqs[1].msg_hdr.msg_name = NULL; - reqs[1].msg_hdr.msg_namelen = 0; - reqs[1].msg_hdr.msg_iov = &iov[1]; - reqs[1].msg_hdr.msg_iovlen = 1; - iov[1].iov_base = (void *) buf2; - iov[1].iov_len = buflen2; - reqs[1].msg_hdr.msg_control = NULL; - reqs[1].msg_hdr.msg_controllen = 0; + struct iovec iov = + { .iov_base = (void *) buf, .iov_len = buflen }; + struct iovec iov2 = + { .iov_base = (void *) buf2, .iov_len = buflen2 }; + struct mmsghdr reqs[2] = + { + { + .msg_hdr = + { + .msg_iov = &iov, + .msg_iovlen = 1, + }, + }, + { + .msg_hdr = + { + .msg_iov = &iov2, + .msg_iovlen = 1, + } + }, + }; int ndg = __sendmmsg (pfd[0].fd, reqs, 2, MSG_NOSIGNAL); if (__glibc_likely (ndg == 2)) diff --git a/resolv/tst-p_secstodate.c b/resolv/tst-p_secstodate.c new file mode 100644 index 0000000000..9dac1ad819 --- /dev/null +++ b/resolv/tst-p_secstodate.c @@ -0,0 +1,67 @@ +/* Test p_secstodate. + Copyright (C) 2017 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 <array_length.h> +#include <limits.h> +#include <resolv.h> +#include <stdbool.h> +#include <stdio.h> +#include <string.h> + +struct test +{ + /* Argument to p_secstodate. */ + unsigned long int in; + /* Expected output. */ + const char *out; +}; + +static const struct test tests[] = + { + { 0UL, "19700101000000" }, + { 12345UL, "19700101032545" }, + { 999999999UL, "20010909014639" }, + { 2147483647UL, "20380119031407" }, + { 2147483648UL, "<overflow>" }, + { 4294967295UL, "<overflow>" }, +#if ULONG_MAX > 0xffffffffUL + { 4294967296UL, "<overflow>" }, + { 9999999999UL, "<overflow>" }, + { LONG_MAX, "<overflow>" }, + { ULONG_MAX, "<overflow>" }, +#endif + }; + +static int +do_test (void) +{ + int ret = 0; + for (size_t i = 0; i < array_length (tests); i++) + { + char *p = p_secstodate (tests[i].in); + printf ("Test %zu: %lu -> %s\n", i, tests[i].in, p); + if (strcmp (p, tests[i].out) != 0) + { + printf ("test %zu failed", i); + ret = 1; + } + } + return ret; +} + +#include <support/test-driver.c> diff --git a/resolv/tst-resolv-network.c b/resolv/tst-resolv-network.c index df9daf8d58..65ce9634cc 100644 --- a/resolv/tst-resolv-network.c +++ b/resolv/tst-resolv-network.c @@ -149,6 +149,9 @@ handle_code (const struct resolv_response_context *ctx, resolv_response_add_data (b, &rrtype, sizeof (rrtype)); } break; + case 104: + send_ptr (b, qname, qclass, qtype, "host.example"); + break; default: FAIL_EXIT1 ("invalid QNAME: %s (code %d)", qname, code); } @@ -257,6 +260,9 @@ main (void) "error: TRY_AGAIN\n"); check_netent ("code103.example", getnetbyname ("code103.example"), "error: NO_RECOVERY\n"); + /* Test bug #17630. */ + check_netent ("code104.example", getnetbyname ("code104.example"), + "error: TRY_AGAIN\n"); /* Lookup by address, success cases. */ check_reverse (1, diff --git a/stdio-common/tst-printf.c b/stdio-common/tst-printf.c index b6d62a5a2f..9829e3ec6a 100644 --- a/stdio-common/tst-printf.c +++ b/stdio-common/tst-printf.c @@ -69,75 +69,7 @@ fmtst2chk (const char *fmt) (void) printf(fmt, 4, 4, 0x12); (void) printf("'\n"); } - -/* This page is covered by the following copyright: */ - -/* (C) Copyright C E Chew - * - * Feel free to copy, use and distribute this software provided: - * - * 1. you do not pretend that you wrote it - * 2. you leave this copyright notice intact. - */ - -/* - * Extracted from exercise.c for glibc-1.05 bug report by Bruce Evans. - */ -#define DEC -123 -#define INT 255 -#define UNS (~0) - -/* Formatted Output Test - * - * This exercises the output formatting code. - */ - -static void -fp_test (void) -{ - int i, j, k, l; - char buf[7]; - char *prefix = buf; - char tp[20]; - - puts("\nFormatted output test"); - printf("prefix 6d 6o 6x 6X 6u\n"); - strcpy(prefix, "%"); - for (i = 0; i < 2; i++) { - for (j = 0; j < 2; j++) { - for (k = 0; k < 2; k++) { - for (l = 0; l < 2; l++) { - strcpy(prefix, "%"); - if (i == 0) strcat(prefix, "-"); - if (j == 0) strcat(prefix, "+"); - if (k == 0) strcat(prefix, "#"); - if (l == 0) strcat(prefix, "0"); - printf("%5s |", prefix); - strcpy(tp, prefix); - strcat(tp, "6d |"); - printf(tp, DEC); - strcpy(tp, prefix); - strcat(tp, "6o |"); - printf(tp, INT); - strcpy(tp, prefix); - strcat(tp, "6x |"); - printf(tp, INT); - strcpy(tp, prefix); - strcat(tp, "6X |"); - printf(tp, INT); - strcpy(tp, prefix); - strcat(tp, "6u |"); - printf(tp, UNS); - printf("\n"); - } - } - } - } - printf("%10s\n", (char *) NULL); - printf("%-10s\n", (char *) NULL); -} - static int do_test (void) { @@ -235,8 +167,6 @@ I am ready for my first lesson today."; snprintf(buf2, sizeof(buf2), "%.999999u", 10)); } - fp_test (); - printf ("%e should be 1.234568e+06\n", 1234567.8); printf ("%f should be 1234567.800000\n", 1234567.8); printf ("%g should be 1.23457e+06\n", 1234567.8); diff --git a/stdio-common/tst-printf.sh b/stdio-common/tst-printf.sh index c413980dd3..5948ca2ca3 100644 --- a/stdio-common/tst-printf.sh +++ b/stdio-common/tst-printf.sh @@ -103,27 +103,6 @@ something really insane: 1.00000000000000000000000000000000000000000000000000000 | 123456.0000| 1.2346e+05| 1.235e+05| snprintf ("%30s", "foo") == 30, " " snprintf ("%.999999u", 10) == 999999 - -Formatted output test -prefix 6d 6o 6x 6X 6u -%-+#0 |-123 |0377 |0xff |0XFF |4294967295 | - %-+# |-123 |0377 |0xff |0XFF |4294967295 | - %-+0 |-123 |377 |ff |FF |4294967295 | - %-+ |-123 |377 |ff |FF |4294967295 | - %-#0 |-123 |0377 |0xff |0XFF |4294967295 | - %-# |-123 |0377 |0xff |0XFF |4294967295 | - %-0 |-123 |377 |ff |FF |4294967295 | - %- |-123 |377 |ff |FF |4294967295 | - %+#0 |-00123 |000377 |0x00ff |0X00FF |4294967295 | - %+# | -123 | 0377 | 0xff | 0XFF |4294967295 | - %+0 |-00123 |000377 |0000ff |0000FF |4294967295 | - %+ | -123 | 377 | ff | FF |4294967295 | - %#0 |-00123 |000377 |0x00ff |0X00FF |4294967295 | - %# | -123 | 0377 | 0xff | 0XFF |4294967295 | - %0 |-00123 |000377 |0000ff |0000FF |4294967295 | - % | -123 | 377 | ff | FF |4294967295 | - (null) -(null) 1.234568e+06 should be 1.234568e+06 1234567.800000 should be 1234567.800000 1.23457e+06 should be 1.23457e+06 @@ -219,27 +198,6 @@ something really insane: 1.00000000000000000000000000000000000000000000000000000 | 123456.0000| 1.2346e+05| 1.235e+05| snprintf ("%30s", "foo") == 30, " " snprintf ("%.999999u", 10) == 999999 - -Formatted output test -prefix 6d 6o 6x 6X 6u -%-+#0 |-123 |0377 |0xff |0XFF |4294967295 | - %-+# |-123 |0377 |0xff |0XFF |4294967295 | - %-+0 |-123 |377 |ff |FF |4294967295 | - %-+ |-123 |377 |ff |FF |4294967295 | - %-#0 |-123 |0377 |0xff |0XFF |4294967295 | - %-# |-123 |0377 |0xff |0XFF |4294967295 | - %-0 |-123 |377 |ff |FF |4294967295 | - %- |-123 |377 |ff |FF |4294967295 | - %+#0 |-00123 |000377 |0x00ff |0X00FF |4294967295 | - %+# | -123 | 0377 | 0xff | 0XFF |4294967295 | - %+0 |-00123 |000377 |0000ff |0000FF |4294967295 | - %+ | -123 | 377 | ff | FF |4294967295 | - %#0 |-00123 |000377 |0x00ff |0X00FF |4294967295 | - %# | -123 | 0377 | 0xff | 0XFF |4294967295 | - %0 |-00123 |000377 |0000ff |0000FF |4294967295 | - % | -123 | 377 | ff | FF |4294967295 | - (null) -(null) 1.234568e+06 should be 1.234568e+06 1234567.800000 should be 1234567.800000 1.23457e+06 should be 1.23457e+06 diff --git a/stdlib/Makefile b/stdlib/Makefile index 0314d5926b..5cdc91050c 100644 --- a/stdlib/Makefile +++ b/stdlib/Makefile @@ -80,7 +80,7 @@ tests := tst-strtol tst-strtod testmb testrand testsort testdiv \ tst-strtol-locale tst-strtod-nan-locale tst-strfmon_l \ tst-quick_exit tst-thread-quick_exit tst-width \ tst-width-stdint tst-strfrom tst-strfrom-locale \ - tst-getrandom + tst-getrandom test-bz22786 tests-internal := tst-strtod1i tst-strtod3 tst-strtod4 tst-strtod5i \ tst-tls-atexit tst-tls-atexit-nodelete tests-static := tst-secure-getenv diff --git a/stdlib/canonicalize.c b/stdlib/canonicalize.c index c3d892c862..a497d06454 100644 --- a/stdlib/canonicalize.c +++ b/stdlib/canonicalize.c @@ -181,7 +181,7 @@ __realpath (const char *name, char *resolved) extra_buf = __alloca (path_max); len = strlen (end); - if ((long int) (n + len) >= path_max) + if (path_max - n <= len) { __set_errno (ENAMETOOLONG); goto error; diff --git a/stdlib/random_r.c b/stdlib/random_r.c index c3f6f9aede..150fa9bb34 100644 --- a/stdlib/random_r.c +++ b/stdlib/random_r.c @@ -361,8 +361,7 @@ __random_r (struct random_data *buf, int32_t *result) if (buf->rand_type == TYPE_0) { - int32_t val = state[0]; - val = ((state[0] * 1103515245) + 12345) & 0x7fffffff; + int32_t val = ((state[0] * 1103515245U) + 12345U) & 0x7fffffff; state[0] = val; *result = val; } @@ -371,11 +370,11 @@ __random_r (struct random_data *buf, int32_t *result) int32_t *fptr = buf->fptr; int32_t *rptr = buf->rptr; int32_t *end_ptr = buf->end_ptr; - int32_t val; + uint32_t val; - val = *fptr += *rptr; + val = *fptr += (uint32_t) *rptr; /* Chucking least random bit. */ - *result = (val >> 1) & 0x7fffffff; + *result = val >> 1; ++fptr; if (fptr >= end_ptr) { diff --git a/stdlib/test-bz22786.c b/stdlib/test-bz22786.c new file mode 100644 index 0000000000..e7837f98c1 --- /dev/null +++ b/stdlib/test-bz22786.c @@ -0,0 +1,90 @@ +/* Bug 22786: test for buffer overflow in realpath. + Copyright (C) 2018 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/>. */ + +/* This file must be run from within a directory called "stdlib". */ + +#include <errno.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <support/test-driver.h> +#include <libc-diag.h> + +static int +do_test (void) +{ + const char dir[] = "bz22786"; + const char lnk[] = "bz22786/symlink"; + + rmdir (dir); + if (mkdir (dir, 0755) != 0 && errno != EEXIST) + { + printf ("mkdir %s: %m\n", dir); + return EXIT_FAILURE; + } + if (symlink (".", lnk) != 0 && errno != EEXIST) + { + printf ("symlink (%s, %s): %m\n", dir, lnk); + return EXIT_FAILURE; + } + + const size_t path_len = (size_t) INT_MAX + 1; + + DIAG_PUSH_NEEDS_COMMENT; +#if __GNUC_PREREQ (7, 0) + /* GCC 7 warns about too-large allocations; here we need such + allocation to succeed for the test to work. */ + DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than="); +#endif + char *path = malloc (path_len); + DIAG_POP_NEEDS_COMMENT; + + if (path == NULL) + { + printf ("malloc (%zu): %m\n", path_len); + return EXIT_UNSUPPORTED; + } + + /* Construct very long path = "bz22786/symlink/aaaa....." */ + char *p = mempcpy (path, lnk, sizeof (lnk) - 1); + *(p++) = '/'; + memset (p, 'a', path_len - (path - p) - 2); + p[path_len - (path - p) - 1] = '\0'; + + /* This call crashes before the fix for bz22786 on 32-bit platforms. */ + p = realpath (path, NULL); + + if (p != NULL || errno != ENAMETOOLONG) + { + printf ("realpath: %s (%m)", p); + return EXIT_FAILURE; + } + + /* Cleanup. */ + unlink (lnk); + rmdir (dir); + + return 0; +} + +#define TEST_FUNCTION do_test +#include <support/test-driver.c> diff --git a/string/bug-strncat1.c b/string/bug-strncat1.c index f1b5c37c5c..b22beba4d3 100644 --- a/string/bug-strncat1.c +++ b/string/bug-strncat1.c @@ -4,13 +4,21 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <libc-diag.h> char d[3] = "\0\1\2"; int main (void) { + DIAG_PUSH_NEEDS_COMMENT; +#if __GNUC_PREREQ (8, 0) + /* GCC 8 warns about strncat truncating output; this is deliberately + tested here. */ + DIAG_IGNORE_NEEDS_COMMENT (8, "-Wstringop-truncation"); +#endif strncat (d, "\5\6", 1); + DIAG_POP_NEEDS_COMMENT; if (d[0] != '\5') { puts ("d[0] != '\\5'"); diff --git a/string/test-memcpy.c b/string/test-memcpy.c index 49f0a76047..dfc94b2e92 100644 --- a/string/test-memcpy.c +++ b/string/test-memcpy.c @@ -212,6 +212,50 @@ do_random_tests (void) } } +static void +do_test1 (void) +{ + size_t size = 0x100000; + void *large_buf; + + large_buf = mmap (NULL, size * 2 + page_size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON, -1, 0); + if (large_buf == MAP_FAILED) + { + puts ("Failed to allocat large_buf, skipping do_test1"); + return; + } + + if (mprotect (large_buf + size, page_size, PROT_NONE)) + error (EXIT_FAILURE, errno, "mprotect failed"); + + size_t arrary_size = size / sizeof (uint32_t); + uint32_t *dest = large_buf; + uint32_t *src = large_buf + size + page_size; + size_t i; + + for (i = 0; i < arrary_size; i++) + src[i] = (uint32_t) i; + + FOR_EACH_IMPL (impl, 0) + { + memset (dest, -1, size); + CALL (impl, (char *) dest, (char *) src, size); + for (i = 0; i < arrary_size; i++) + if (dest[i] != src[i]) + { + error (0, 0, + "Wrong result in function %s dst \"%p\" src \"%p\" offset \"%zd\"", + impl->name, dest, src, i); + ret = 1; + break; + } + } + + munmap ((void *) dest, size); + munmap ((void *) src, size); +} + int test_main (void) { @@ -253,6 +297,9 @@ test_main (void) do_test (0, 0, getpagesize ()); do_random_tests (); + + do_test1 (); + return ret; } diff --git a/string/test-memmove.c b/string/test-memmove.c index 51f79f6eb4..60f77f825b 100644 --- a/string/test-memmove.c +++ b/string/test-memmove.c @@ -24,6 +24,7 @@ # define TEST_NAME "memmove" #endif #include "test-string.h" +#include <support/test-driver.h> char *simple_memmove (char *, const char *, size_t); @@ -245,6 +246,60 @@ do_random_tests (void) } } +static void +do_test2 (void) +{ + size_t size = 0x20000000; + uint32_t * large_buf; + + large_buf = mmap ((void*) 0x70000000, size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON, -1, 0); + + if (large_buf == MAP_FAILED) + error (EXIT_UNSUPPORTED, errno, "Large mmap failed"); + + if ((uintptr_t) large_buf > 0x80000000 - 128 + || 0x80000000 - (uintptr_t) large_buf > 0x20000000) + { + error (0, 0, "Large mmap allocated improperly"); + ret = EXIT_UNSUPPORTED; + munmap ((void *) large_buf, size); + return; + } + + size_t bytes_move = 0x80000000 - (uintptr_t) large_buf; + size_t arr_size = bytes_move / sizeof (uint32_t); + size_t i; + + FOR_EACH_IMPL (impl, 0) + { + for (i = 0; i < arr_size; i++) + large_buf[i] = (uint32_t) i; + + uint32_t * dst = &large_buf[33]; + +#ifdef TEST_BCOPY + CALL (impl, (char *) large_buf, (char *) dst, bytes_move); +#else + CALL (impl, (char *) dst, (char *) large_buf, bytes_move); +#endif + + for (i = 0; i < arr_size; i++) + { + if (dst[i] != (uint32_t) i) + { + error (0, 0, + "Wrong result in function %s dst \"%p\" src \"%p\" offset \"%zd\"", + impl->name, dst, large_buf, i); + ret = 1; + break; + } + } + } + + munmap ((void *) large_buf, size); +} + int test_main (void) { @@ -284,6 +339,9 @@ test_main (void) } do_random_tests (); + + do_test2 (); + return ret; } diff --git a/string/test-mempcpy.c b/string/test-mempcpy.c index 364a811c62..ec11c9f6e6 100644 --- a/string/test-mempcpy.c +++ b/string/test-mempcpy.c @@ -18,6 +18,7 @@ <http://www.gnu.org/licenses/>. */ #define MEMCPY_RESULT(dst, len) (dst) + (len) +#define MIN_PAGE_SIZE 131072 #define TEST_MAIN #define TEST_NAME "mempcpy" #include "test-string.h" diff --git a/string/tester.c b/string/tester.c index 4b928b4f5e..8fdbe3de13 100644 --- a/string/tester.c +++ b/string/tester.c @@ -264,8 +264,15 @@ test_stpncpy (void) { it = "stpncpy"; memset (one, 'x', sizeof (one)); + DIAG_PUSH_NEEDS_COMMENT; +#if __GNUC_PREREQ (8, 0) + /* GCC 8 warns about stpncpy truncating output; this is deliberately + tested here. */ + DIAG_IGNORE_NEEDS_COMMENT (8, "-Wstringop-truncation"); +#endif check (stpncpy (one, "abc", 2) == one + 2, 1); check (stpncpy (one, "abc", 3) == one + 3, 2); + DIAG_POP_NEEDS_COMMENT; check (stpncpy (one, "abc", 4) == one + 3, 3); check (one[3] == '\0' && one[4] == 'x', 4); check (stpncpy (one, "abcd", 5) == one + 4, 5); @@ -380,9 +387,11 @@ test_strncat (void) DIAG_PUSH_NEEDS_COMMENT; #if __GNUC_PREREQ (7, 0) /* GCC 7 warns about the size passed to strncat being larger than - the size of the buffer; this is deliberately tested here.. */ + the size of the buffer; this is deliberately tested here; GCC 8 + gives a -Warray-bounds warning about this. */ DIAG_IGNORE_NEEDS_COMMENT (7, "-Wstringop-overflow="); #endif + DIAG_IGNORE_NEEDS_COMMENT (8, "-Warray-bounds"); (void) strncat (one, two, 99); DIAG_POP_NEEDS_COMMENT; equal (one, "ghef", 5); /* Basic test encore. */ @@ -420,13 +429,27 @@ test_strncat (void) equal (one, "cd", 9); (void) strcpy (one, "ab"); + DIAG_PUSH_NEEDS_COMMENT; +#if __GNUC_PREREQ (8, 0) + /* GCC 8 warns about strncat truncating output; this is deliberately + tested here. */ + DIAG_IGNORE_NEEDS_COMMENT (8, "-Wstringop-truncation"); +#endif (void) strncat (one, "cdef", 2); + DIAG_POP_NEEDS_COMMENT; equal (one, "abcd", 10); /* Count-limited. */ (void) strncat (one, "gh", 0); equal (one, "abcd", 11); /* Zero count. */ + DIAG_PUSH_NEEDS_COMMENT; +#if __GNUC_PREREQ (7, 0) + /* GCC 8 warns about strncat bound equal to source length; this is + deliberately tested here. */ + DIAG_IGNORE_NEEDS_COMMENT (8, "-Wstringop-overflow="); +#endif (void) strncat (one, "gh", 2); + DIAG_POP_NEEDS_COMMENT; equal (one, "abcdgh", 12); /* Count and length equal. */ DIAG_PUSH_NEEDS_COMMENT; @@ -459,9 +482,15 @@ test_strncat (void) #if __GNUC_PREREQ (7, 0) /* GCC 7 warns about the size passed to strncat being larger than the size of the buffer; this is - deliberately tested here.. */ + deliberately tested here; GCC 8 gives a -Warray-bounds + warning about this. */ DIAG_IGNORE_NEEDS_COMMENT (7, "-Wstringop-overflow="); + /* GCC 9 as of 2018-06-14 warns that the size passed is + large enough that, if it were the actual object size, + the objects would have to overlap. */ + DIAG_IGNORE_NEEDS_COMMENT (9, "-Wrestrict"); #endif + DIAG_IGNORE_NEEDS_COMMENT (8, "-Warray-bounds"); check (strncat (buf1 + n2, buf2 + n1, ~((size_t) 0) - n4) == buf1 + n2, ntest); DIAG_POP_NEEDS_COMMENT; @@ -523,11 +552,25 @@ test_strncpy (void) equal (one, "abc", 2); /* Did the copy go right? */ (void) strcpy (one, "abcdefgh"); + DIAG_PUSH_NEEDS_COMMENT; +#if __GNUC_PREREQ (8, 0) + /* GCC 8 warns about strncpy truncating output; this is deliberately + tested here. */ + DIAG_IGNORE_NEEDS_COMMENT (8, "-Wstringop-truncation"); +#endif (void) strncpy (one, "xyz", 2); + DIAG_POP_NEEDS_COMMENT; equal (one, "xycdefgh", 3); /* Copy cut by count. */ (void) strcpy (one, "abcdefgh"); + DIAG_PUSH_NEEDS_COMMENT; +#if __GNUC_PREREQ (8, 0) + /* GCC 8 warns about strncpy truncating output; this is deliberately + tested here. */ + DIAG_IGNORE_NEEDS_COMMENT (8, "-Wstringop-truncation"); +#endif (void) strncpy (one, "xyz", 3); /* Copy cut just before NUL. */ + DIAG_POP_NEEDS_COMMENT; equal (one, "xyzdefgh", 4); (void) strcpy (one, "abcdefgh"); @@ -542,7 +585,14 @@ test_strncpy (void) equal (one+5, "fgh", 9); (void) strcpy (one, "abc"); + DIAG_PUSH_NEEDS_COMMENT; +#if __GNUC_PREREQ (8, 0) + /* GCC 8 warns about strncpy truncating output; this is deliberately + tested here. */ + DIAG_IGNORE_NEEDS_COMMENT (8, "-Wstringop-truncation"); +#endif (void) strncpy (one, "xyz", 0); /* Zero-length copy. */ + DIAG_POP_NEEDS_COMMENT; equal (one, "abc", 10); (void) strncpy (one, "", 2); /* Zero-length source. */ @@ -1151,8 +1201,8 @@ test_memcmp (void) { char *a = one + i; char *b = two + i; - strncpy(a, "--------11112222", 16); - strncpy(b, "--------33334444", 16); + memcpy(a, "--------11112222", 16); + memcpy(b, "--------33334444", 16); check(memcmp(b, a, 16) > 0, cnt++); check(memcmp(a, b, 16) < 0, cnt++); } diff --git a/support/Makefile b/support/Makefile index 1bda81e55e..652d2cdf69 100644 --- a/support/Makefile +++ b/support/Makefile @@ -52,9 +52,12 @@ libsupport-routines = \ support_format_hostent \ support_format_netent \ support_isolate_in_subprocess \ + support_openpty \ + support_quote_blob \ support_record_failure \ support_run_diff \ support_shared_allocate \ + support_test_compare_blob \ support_test_compare_failure \ support_write_file_string \ support_test_main \ @@ -95,6 +98,9 @@ libsupport-routines = \ xpthread_barrier_destroy \ xpthread_barrier_init \ xpthread_barrier_wait \ + xpthread_barrierattr_destroy \ + xpthread_barrierattr_init \ + xpthread_barrierattr_setpshared \ xpthread_cancel \ xpthread_check_return \ xpthread_cond_wait \ @@ -150,8 +156,10 @@ tests = \ tst-support-namespace \ tst-support_capture_subprocess \ tst-support_format_dns_packet \ + tst-support_quote_blob \ tst-support_record_failure \ tst-test_compare \ + tst-test_compare_blob \ tst-xreadlink \ ifeq ($(run-built-tests),yes) diff --git a/support/check.h b/support/check.h index 2192f38941..b3a4645e92 100644 --- a/support/check.h +++ b/support/check.h @@ -64,6 +64,8 @@ __BEGIN_DECLS (1, __FILE__, __LINE__, #expr); \ }) + + int support_print_failure_impl (const char *file, int line, const char *format, ...) __attribute__ ((nonnull (1), format (printf, 3, 4))); @@ -141,6 +143,26 @@ void support_test_compare_failure (const char *file, int line, int right_size); +/* Compare [LEFT, LEFT + LEFT_LENGTH) with [RIGHT, RIGHT + + RIGHT_LENGTH) and report a test failure if the arrays are + different. LEFT_LENGTH and RIGHT_LENGTH are measured in bytes. If + the length is null, the corresponding pointer is ignored (i.e., it + can be NULL). The blobs should be reasonably short because on + mismatch, both are printed. */ +#define TEST_COMPARE_BLOB(left, left_length, right, right_length) \ + (support_test_compare_blob (left, left_length, right, right_length, \ + __FILE__, __LINE__, \ + #left, #left_length, #right, #right_length)) + +void support_test_compare_blob (const void *left, + unsigned long int left_length, + const void *right, + unsigned long int right_length, + const char *file, int line, + const char *left_exp, const char *left_len_exp, + const char *right_exp, + const char *right_len_exp); + /* Internal function called by the test driver. */ int support_report_failure (int status) __attribute__ ((weak, warn_unused_result)); diff --git a/support/support.h b/support/support.h index bc5827ed87..b61fe0735c 100644 --- a/support/support.h +++ b/support/support.h @@ -59,6 +59,12 @@ void support_shared_free (void *); process on error. */ void support_write_file_string (const char *path, const char *contents); +/* Quote the contents of the byte array starting at BLOB, of LENGTH + bytes, in such a way that the result string can be included in a C + literal (in single/double quotes, without putting the quotes into + the result). */ +char *support_quote_blob (const void *blob, size_t length); + /* Error-checking wrapper functions which terminate the process on error. */ diff --git a/support/support_format_addrinfo.c b/support/support_format_addrinfo.c index c5e00e516a..60d2cc40f6 100644 --- a/support/support_format_addrinfo.c +++ b/support/support_format_addrinfo.c @@ -67,8 +67,6 @@ format_ai_flags (FILE *out, struct addrinfo *ai) FLAG (AI_ADDRCONFIG); FLAG (AI_IDN); FLAG (AI_CANONIDN); - FLAG (AI_IDN_ALLOW_UNASSIGNED); - FLAG (AI_IDN_USE_STD3_ASCII_RULES); FLAG (AI_NUMERICSERV); #undef FLAG int remaining = ai->ai_flags & ~flags_printed; @@ -220,7 +218,11 @@ support_format_addrinfo (struct addrinfo *ai, int ret) xopen_memstream (&mem); if (ret != 0) { - fprintf (mem.out, "error: %s\n", gai_strerror (ret)); + const char *errmsg = gai_strerror (ret); + if (strcmp (errmsg, "Unknown error") == 0) + fprintf (mem.out, "error: Unknown error %d\n", ret); + else + fprintf (mem.out, "error: %s\n", errmsg); if (ret == EAI_SYSTEM) { errno = errno_copy; diff --git a/support/support_openpty.c b/support/support_openpty.c new file mode 100644 index 0000000000..ac779ab91e --- /dev/null +++ b/support/support_openpty.c @@ -0,0 +1,109 @@ +/* Open a pseudoterminal. + Copyright (C) 2018 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 <support/tty.h> +#include <support/check.h> +#include <support/support.h> + +#include <errno.h> +#include <stdlib.h> +#include <string.h> + +#include <fcntl.h> +#include <termios.h> +#include <sys/ioctl.h> +#include <unistd.h> + +/* As ptsname, but allocates space for an appropriately-sized string + using malloc. */ +static char * +xptsname (int fd) +{ + int rv; + size_t buf_len = 128; + char *buf = xmalloc (buf_len); + for (;;) + { + rv = ptsname_r (fd, buf, buf_len); + if (rv) + FAIL_EXIT1 ("ptsname_r: %s", strerror (errno)); + + if (memchr (buf, '\0', buf_len)) + return buf; /* ptsname succeeded and the buffer was not truncated */ + + buf_len *= 2; + buf = xrealloc (buf, buf_len); + } +} + +void +support_openpty (int *a_outer, int *a_inner, char **a_name, + const struct termios *termp, + const struct winsize *winp) +{ + int outer = -1, inner = -1; + char *namebuf = 0; + + outer = posix_openpt (O_RDWR | O_NOCTTY); + if (outer == -1) + FAIL_EXIT1 ("posix_openpt: %s", strerror (errno)); + + if (grantpt (outer)) + FAIL_EXIT1 ("grantpt: %s", strerror (errno)); + + if (unlockpt (outer)) + FAIL_EXIT1 ("unlockpt: %s", strerror (errno)); + + +#ifdef TIOCGPTPEER + inner = ioctl (outer, TIOCGPTPEER, O_RDWR | O_NOCTTY); +#endif + if (inner == -1) + { + /* The kernel might not support TIOCGPTPEER, fall back to open + by name. */ + namebuf = xptsname (outer); + inner = open (namebuf, O_RDWR | O_NOCTTY); + if (inner == -1) + FAIL_EXIT1 ("%s: %s", namebuf, strerror (errno)); + } + + if (termp) + { + if (tcsetattr (inner, TCSAFLUSH, termp)) + FAIL_EXIT1 ("tcsetattr: %s", strerror (errno)); + } +#ifdef TIOCSWINSZ + if (winp) + { + if (ioctl (inner, TIOCSWINSZ, winp)) + FAIL_EXIT1 ("TIOCSWINSZ: %s", strerror (errno)); + } +#endif + + if (a_name) + { + if (!namebuf) + namebuf = xptsname (outer); + *a_name = namebuf; + } + else + free (namebuf); + *a_outer = outer; + *a_inner = inner; +} diff --git a/support/support_quote_blob.c b/support/support_quote_blob.c new file mode 100644 index 0000000000..d6a678d8d6 --- /dev/null +++ b/support/support_quote_blob.c @@ -0,0 +1,83 @@ +/* Quote a blob so that it can be used in C literals. + Copyright (C) 2018 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 <support/support.h> +#include <support/xmemstream.h> + +char * +support_quote_blob (const void *blob, size_t length) +{ + struct xmemstream out; + xopen_memstream (&out); + + const unsigned char *p = blob; + for (size_t i = 0; i < length; ++i) + { + unsigned char ch = p[i]; + + /* Use C backslash escapes for those control characters for + which they are defined. */ + switch (ch) + { + case '\a': + putc_unlocked ('\\', out.out); + putc_unlocked ('a', out.out); + break; + case '\b': + putc_unlocked ('\\', out.out); + putc_unlocked ('b', out.out); + break; + case '\f': + putc_unlocked ('\\', out.out); + putc_unlocked ('f', out.out); + break; + case '\n': + putc_unlocked ('\\', out.out); + putc_unlocked ('n', out.out); + break; + case '\r': + putc_unlocked ('\\', out.out); + putc_unlocked ('r', out.out); + break; + case '\t': + putc_unlocked ('\\', out.out); + putc_unlocked ('t', out.out); + break; + case '\v': + putc_unlocked ('\\', out.out); + putc_unlocked ('v', out.out); + break; + case '\\': + case '\'': + case '\"': + putc_unlocked ('\\', out.out); + putc_unlocked (ch, out.out); + break; + default: + if (ch < ' ' || ch > '~') + /* Use octal sequences because they are fixed width, + unlike hexadecimal sequences. */ + fprintf (out.out, "\\%03o", ch); + else + putc_unlocked (ch, out.out); + } + } + + xfclose_memstream (&out); + return out.buffer; +} diff --git a/support/support_test_compare_blob.c b/support/support_test_compare_blob.c new file mode 100644 index 0000000000..c5e63d1b93 --- /dev/null +++ b/support/support_test_compare_blob.c @@ -0,0 +1,76 @@ +/* Check two binary blobs for equality. + Copyright (C) 2018 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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <support/check.h> +#include <support/support.h> +#include <support/xmemstream.h> + +static void +report_length (const char *what, unsigned long int length, const char *expr) +{ + printf (" %s %lu bytes (from %s)\n", what, length, expr); +} + +static void +report_blob (const char *what, const unsigned char *blob, + unsigned long int length, const char *expr) +{ + if (length > 0) + { + printf (" %s (evaluated from %s):\n", what, expr); + char *quoted = support_quote_blob (blob, length); + printf (" \"%s\"\n", quoted); + free (quoted); + + fputs (" ", stdout); + for (unsigned long i = 0; i < length; ++i) + printf (" %02X", blob[i]); + putc ('\n', stdout); + } +} + +void +support_test_compare_blob (const void *left, unsigned long int left_length, + const void *right, unsigned long int right_length, + const char *file, int line, + const char *left_expr, const char *left_len_expr, + const char *right_expr, const char *right_len_expr) +{ + /* No differences are possible if both lengths are null. */ + if (left_length == 0 && right_length == 0) + return; + + if (left_length != right_length || left == NULL || right == NULL + || memcmp (left, right, left_length) != 0) + { + support_record_failure (); + printf ("%s:%d: error: blob comparison failed\n", file, line); + if (left_length == right_length) + printf (" blob length: %lu bytes\n", left_length); + else + { + report_length ("left length: ", left_length, left_len_expr); + report_length ("right length:", right_length, right_len_expr); + } + report_blob ("left", left, left_length, left_expr); + report_blob ("right", right, right_length, right_expr); + } +} diff --git a/support/support_test_main.c b/support/support_test_main.c index 396385729b..23429779ac 100644 --- a/support/support_test_main.c +++ b/support/support_test_main.c @@ -270,7 +270,8 @@ support_test_main (int argc, char **argv, const struct test_config *config) timeout = DEFAULT_TIMEOUT; /* Make sure we see all message, even those on stdout. */ - setvbuf (stdout, NULL, _IONBF, 0); + if (!config->no_setvbuf) + setvbuf (stdout, NULL, _IONBF, 0); /* Make sure temporary files are deleted. */ if (support_delete_temp_files != NULL) diff --git a/support/test-driver.c b/support/test-driver.c index 09c8783e4f..9798f16227 100644 --- a/support/test-driver.c +++ b/support/test-driver.c @@ -140,6 +140,10 @@ main (int argc, char **argv) test_config.no_mallopt = 1; #endif +#ifdef TEST_NO_SETVBUF + test_config.no_setvbuf = 1; +#endif + #ifdef TIMEOUT test_config.timeout = TIMEOUT; #endif diff --git a/support/test-driver.h b/support/test-driver.h index 1708d68d60..549179b254 100644 --- a/support/test-driver.h +++ b/support/test-driver.h @@ -35,6 +35,7 @@ struct test_config int expected_status; /* Expected exit status. */ int expected_signal; /* If non-zero, expect termination by signal. */ char no_mallopt; /* Boolean flag to disable mallopt. */ + char no_setvbuf; /* Boolean flag to disable setvbuf. */ const char *optstring; /* Short command line options. */ }; diff --git a/support/tst-support_quote_blob.c b/support/tst-support_quote_blob.c new file mode 100644 index 0000000000..5467a190a6 --- /dev/null +++ b/support/tst-support_quote_blob.c @@ -0,0 +1,61 @@ +/* Test the support_quote_blob function. + Copyright (C) 2018 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 <support/check.h> +#include <support/support.h> +#include <string.h> +#include <stdlib.h> + +static int +do_test (void) +{ + /* Check handling of the empty blob, both with and without trailing + NUL byte. */ + char *p = support_quote_blob ("", 0); + TEST_COMPARE (strlen (p), 0); + free (p); + p = support_quote_blob ("X", 0); + TEST_COMPARE (strlen (p), 0); + free (p); + + /* Check escaping of backslash-escaped characters, and lack of + escaping for other shell meta-characters. */ + p = support_quote_blob ("$()*?`@[]{}~\'\"X", 14); + TEST_COMPARE (strcmp (p, "$()*?`@[]{}~\\'\\\""), 0); + free (p); + + /* Check lack of escaping for letters and digits. */ +#define LETTERS_AND_DIGTS \ + "abcdefghijklmnopqrstuvwxyz" \ + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \ + "0123456789" + p = support_quote_blob (LETTERS_AND_DIGTS "@", 2 * 26 + 10); + TEST_COMPARE (strcmp (p, LETTERS_AND_DIGTS), 0); + free (p); + + /* Check escaping of control characters and other non-printable + characters. */ + p = support_quote_blob ("\r\n\t\a\b\f\v\1\177\200\377\0@", 14); + TEST_COMPARE (strcmp (p, "\\r\\n\\t\\a\\b\\f\\v\\001" + "\\177\\200\\377\\000@\\000"), 0); + free (p); + + return 0; +} + +#include <support/test-driver.c> diff --git a/support/tst-test_compare_blob.c b/support/tst-test_compare_blob.c new file mode 100644 index 0000000000..aa8643e182 --- /dev/null +++ b/support/tst-test_compare_blob.c @@ -0,0 +1,125 @@ +/* Basic test for the TEST_COMPARE_BLOB macro. + Copyright (C) 2018 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 <string.h> +#include <support/check.h> +#include <support/capture_subprocess.h> + +static void +subprocess (void *closure) +{ + /* These tests should fail. They were chosen to cover differences + in length (with the same contents), single-bit mismatches, and + mismatching null pointers. */ + TEST_COMPARE_BLOB ("", 0, "", 1); /* Line 29. */ + TEST_COMPARE_BLOB ("X", 1, "", 1); /* Line 30. */ + TEST_COMPARE_BLOB ("abcd", 3, "abcd", 4); /* Line 31. */ + TEST_COMPARE_BLOB ("abcd", 4, "abcD", 4); /* Line 32. */ + TEST_COMPARE_BLOB ("abcd", 4, NULL, 0); /* Line 33. */ + TEST_COMPARE_BLOB (NULL, 0, "abcd", 4); /* Line 34. */ +} + +/* Same contents, different addresses. */ +char buffer_abc_1[] = "abc"; +char buffer_abc_2[] = "abc"; + +static int +do_test (void) +{ + /* This should succeed. Even if the pointers and array contents are + different, zero-length inputs are not different. */ + TEST_COMPARE_BLOB ("", 0, "", 0); + TEST_COMPARE_BLOB ("", 0, buffer_abc_1, 0); + TEST_COMPARE_BLOB (buffer_abc_1, 0, "", 0); + TEST_COMPARE_BLOB (NULL, 0, "", 0); + TEST_COMPARE_BLOB ("", 0, NULL, 0); + TEST_COMPARE_BLOB (NULL, 0, NULL, 0); + + /* Check equality of blobs containing a single NUL byte. */ + TEST_COMPARE_BLOB ("", 1, "", 1); + TEST_COMPARE_BLOB ("", 1, &buffer_abc_1[3], 1); + + /* Check equality of blobs of varying lengths. */ + for (size_t i = 0; i <= sizeof (buffer_abc_1); ++i) + TEST_COMPARE_BLOB (buffer_abc_1, i, buffer_abc_2, i); + + struct support_capture_subprocess proc = support_capture_subprocess + (&subprocess, NULL); + + /* Discard the reported error. */ + support_record_failure_reset (); + + puts ("info: *** subprocess output starts ***"); + fputs (proc.out.buffer, stdout); + puts ("info: *** subprocess output ends ***"); + + TEST_VERIFY + (strcmp (proc.out.buffer, +"tst-test_compare_blob.c:29: error: blob comparison failed\n" +" left length: 0 bytes (from 0)\n" +" right length: 1 bytes (from 1)\n" +" right (evaluated from \"\"):\n" +" \"\\000\"\n" +" 00\n" +"tst-test_compare_blob.c:30: error: blob comparison failed\n" +" blob length: 1 bytes\n" +" left (evaluated from \"X\"):\n" +" \"X\"\n" +" 58\n" +" right (evaluated from \"\"):\n" +" \"\\000\"\n" +" 00\n" +"tst-test_compare_blob.c:31: error: blob comparison failed\n" +" left length: 3 bytes (from 3)\n" +" right length: 4 bytes (from 4)\n" +" left (evaluated from \"abcd\"):\n" +" \"abc\"\n" +" 61 62 63\n" +" right (evaluated from \"abcd\"):\n" +" \"abcd\"\n" +" 61 62 63 64\n" +"tst-test_compare_blob.c:32: error: blob comparison failed\n" +" blob length: 4 bytes\n" +" left (evaluated from \"abcd\"):\n" +" \"abcd\"\n" +" 61 62 63 64\n" +" right (evaluated from \"abcD\"):\n" +" \"abcD\"\n" +" 61 62 63 44\n" +"tst-test_compare_blob.c:33: error: blob comparison failed\n" +" left length: 4 bytes (from 4)\n" +" right length: 0 bytes (from 0)\n" +" left (evaluated from \"abcd\"):\n" +" \"abcd\"\n" +" 61 62 63 64\n" +"tst-test_compare_blob.c:34: error: blob comparison failed\n" +" left length: 0 bytes (from 0)\n" +" right length: 4 bytes (from 4)\n" +" right (evaluated from \"abcd\"):\n" +" \"abcd\"\n" +" 61 62 63 64\n" + ) == 0); + + /* Check that there is no output on standard error. */ + support_capture_subprocess_check (&proc, "TEST_COMPARE_BLOB", + 0, sc_allow_stdout); + + return 0; +} + +#include <support/test-driver.c> diff --git a/support/tty.h b/support/tty.h new file mode 100644 index 0000000000..1d37c42279 --- /dev/null +++ b/support/tty.h @@ -0,0 +1,45 @@ +/* Support functions related to (pseudo)terminals. + Copyright (C) 2018 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/>. */ + +#ifndef _SUPPORT_TTY_H +#define _SUPPORT_TTY_H 1 + +struct termios; +struct winsize; + +/** Open a pseudoterminal pair. The outer fd is written to the address + A_OUTER and the inner fd to A_INNER. + + If A_NAME is not NULL, it will be set to point to a string naming + the /dev/pts/NNN device corresponding to the inner fd; space for + this string is allocated with malloc and should be freed by the + caller when no longer needed. (This is different from the libutil + function 'openpty'.) + + If TERMP is not NULL, the terminal parameters will be initialized + according to the termios structure it points to. + + If WINP is not NULL, the terminal window size will be set + accordingly. + + Terminates the process on failure (like xmalloc). */ +extern void support_openpty (int *a_outer, int *a_inner, char **a_name, + const struct termios *termp, + const struct winsize *winp); + +#endif diff --git a/support/xpthread_barrierattr_destroy.c b/support/xpthread_barrierattr_destroy.c new file mode 100644 index 0000000000..3e471f9a81 --- /dev/null +++ b/support/xpthread_barrierattr_destroy.c @@ -0,0 +1,26 @@ +/* pthread_barrierattr_destroy with error checking. + Copyright (C) 2018 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 <support/xthread.h> + +void +xpthread_barrierattr_destroy (pthread_barrierattr_t *attr) +{ + xpthread_check_return ("pthread_barrierattr_destroy", + pthread_barrierattr_destroy (attr)); +} diff --git a/support/xpthread_barrierattr_init.c b/support/xpthread_barrierattr_init.c new file mode 100644 index 0000000000..4ee14e78f3 --- /dev/null +++ b/support/xpthread_barrierattr_init.c @@ -0,0 +1,26 @@ +/* pthread_barrierattr_init with error checking. + Copyright (C) 2018 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 <support/xthread.h> + +void +xpthread_barrierattr_init (pthread_barrierattr_t *attr) +{ + xpthread_check_return ("pthread_barrierattr_init", + pthread_barrierattr_init (attr)); +} diff --git a/support/xpthread_barrierattr_setpshared.c b/support/xpthread_barrierattr_setpshared.c new file mode 100644 index 0000000000..90b2c5bec6 --- /dev/null +++ b/support/xpthread_barrierattr_setpshared.c @@ -0,0 +1,26 @@ +/* pthread_barrierattr_setpshared with error checking. + Copyright (C) 2018 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 <support/xthread.h> + +void +xpthread_barrierattr_setpshared (pthread_barrierattr_t *attr, int pshared) +{ + xpthread_check_return ("pthread_barrierattr_setpshared", + pthread_barrierattr_setpshared (attr, pshared)); +} diff --git a/support/xthread.h b/support/xthread.h index 79358e7c99..623f5ad0ac 100644 --- a/support/xthread.h +++ b/support/xthread.h @@ -41,6 +41,9 @@ void xpthread_check_return (const char *function, int value); void xpthread_barrier_init (pthread_barrier_t *barrier, pthread_barrierattr_t *attr, unsigned int count); void xpthread_barrier_destroy (pthread_barrier_t *barrier); +void xpthread_barrierattr_destroy (pthread_barrierattr_t *); +void xpthread_barrierattr_init (pthread_barrierattr_t *); +void xpthread_barrierattr_setpshared (pthread_barrierattr_t *, int pshared); void xpthread_mutexattr_destroy (pthread_mutexattr_t *); void xpthread_mutexattr_init (pthread_mutexattr_t *); void xpthread_mutexattr_setprotocol (pthread_mutexattr_t *, int); diff --git a/sysdeps/gnu/bits/utmp.h b/sysdeps/gnu/bits/utmp.h index 2ee11cb706..71c9fa2a9f 100644 --- a/sysdeps/gnu/bits/utmp.h +++ b/sysdeps/gnu/bits/utmp.h @@ -59,10 +59,13 @@ struct utmp { short int ut_type; /* Type of login. */ pid_t ut_pid; /* Process ID of login process. */ - char ut_line[UT_LINESIZE]; /* Devicename. */ + char ut_line[UT_LINESIZE] + __attribute_nonstring__; /* Devicename. */ char ut_id[4]; /* Inittab ID. */ - char ut_user[UT_NAMESIZE]; /* Username. */ - char ut_host[UT_HOSTSIZE]; /* Hostname for remote login. */ + char ut_user[UT_NAMESIZE] + __attribute_nonstring__; /* Username. */ + char ut_host[UT_HOSTSIZE] + __attribute_nonstring__; /* Hostname for remote login. */ struct exit_status ut_exit; /* Exit status of a process marked as DEAD_PROCESS. */ /* The ut_session and ut_tv fields must be the same size when compiled diff --git a/sysdeps/i386/i686/multiarch/memcpy-sse2-unaligned.S b/sysdeps/i386/i686/multiarch/memcpy-sse2-unaligned.S index 2fe2072cb1..043f4260e2 100644 --- a/sysdeps/i386/i686/multiarch/memcpy-sse2-unaligned.S +++ b/sysdeps/i386/i686/multiarch/memcpy-sse2-unaligned.S @@ -72,7 +72,7 @@ ENTRY (MEMCPY) cmp %edx, %eax # ifdef USE_AS_MEMMOVE - jg L(check_forward) + ja L(check_forward) L(mm_len_0_or_more_backward): /* Now do checks for lengths. We do [0..16], [16..32], [32..64], [64..128] @@ -81,7 +81,7 @@ L(mm_len_0_or_more_backward): jbe L(mm_len_0_16_bytes_backward) cmpl $32, %ecx - jg L(mm_len_32_or_more_backward) + ja L(mm_len_32_or_more_backward) /* Copy [0..32] and return. */ movdqu (%eax), %xmm0 @@ -92,7 +92,7 @@ L(mm_len_0_or_more_backward): L(mm_len_32_or_more_backward): cmpl $64, %ecx - jg L(mm_len_64_or_more_backward) + ja L(mm_len_64_or_more_backward) /* Copy [0..64] and return. */ movdqu (%eax), %xmm0 @@ -107,7 +107,7 @@ L(mm_len_32_or_more_backward): L(mm_len_64_or_more_backward): cmpl $128, %ecx - jg L(mm_len_128_or_more_backward) + ja L(mm_len_128_or_more_backward) /* Copy [0..128] and return. */ movdqu (%eax), %xmm0 @@ -132,7 +132,7 @@ L(mm_len_128_or_more_backward): add %ecx, %eax cmp %edx, %eax movl SRC(%esp), %eax - jle L(forward) + jbe L(forward) PUSH (%esi) PUSH (%edi) PUSH (%ebx) @@ -269,7 +269,7 @@ L(check_forward): add %edx, %ecx cmp %eax, %ecx movl LEN(%esp), %ecx - jle L(forward) + jbe L(forward) /* Now do checks for lengths. We do [0..16], [0..32], [0..64], [0..128] separately. */ diff --git a/sysdeps/nptl/lowlevellock.h b/sysdeps/nptl/lowlevellock.h index 54e3c28b0b..649aea813c 100644 --- a/sysdeps/nptl/lowlevellock.h +++ b/sysdeps/nptl/lowlevellock.h @@ -181,11 +181,14 @@ extern int __lll_timedlock_wait (int *futex, const struct timespec *, thread ID while the clone is running and is reset to zero by the kernel afterwards. The kernel up to version 3.16.3 does not use the private futex operations for futex wake-up when the clone terminates. */ -#define lll_wait_tid(tid) \ - do { \ - __typeof (tid) __tid; \ - while ((__tid = (tid)) != 0) \ - lll_futex_wait (&(tid), __tid, LLL_SHARED);\ +#define lll_wait_tid(tid) \ + do { \ + __typeof (tid) __tid; \ + /* We need acquire MO here so that we synchronize \ + with the kernel's store to 0 when the clone \ + terminates. (see above) */ \ + while ((__tid = atomic_load_acquire (&(tid))) != 0) \ + lll_futex_wait (&(tid), __tid, LLL_SHARED); \ } while (0) extern int __lll_timedwait_tid (int *, const struct timespec *) diff --git a/sysdeps/posix/preadv2.c b/sysdeps/posix/preadv2.c index d27f7028ed..fe73d3cbea 100644 --- a/sysdeps/posix/preadv2.c +++ b/sysdeps/posix/preadv2.c @@ -32,7 +32,10 @@ preadv2 (int fd, const struct iovec *vector, int count, OFF_T offset, return -1; } - return preadv (fd, vector, count, offset); + if (offset == -1) + return __readv (fd, vector, count); + else + return preadv (fd, vector, count, offset); } #endif diff --git a/sysdeps/posix/preadv64v2.c b/sysdeps/posix/preadv64v2.c index ce7cb40bf2..8569c8b398 100644 --- a/sysdeps/posix/preadv64v2.c +++ b/sysdeps/posix/preadv64v2.c @@ -29,7 +29,10 @@ preadv64v2 (int fd, const struct iovec *vector, int count, OFF_T offset, return -1; } - return preadv64 (fd, vector, count, offset); + if (offset == -1) + return __readv (fd, vector, count); + else + return preadv64 (fd, vector, count, offset); } #ifdef __OFF_T_MATCHES_OFF64_T diff --git a/sysdeps/posix/pwritev2.c b/sysdeps/posix/pwritev2.c index 7ec8cbc407..b24b491a81 100644 --- a/sysdeps/posix/pwritev2.c +++ b/sysdeps/posix/pwritev2.c @@ -32,7 +32,10 @@ pwritev2 (int fd, const struct iovec *vector, int count, OFF_T offset, return -1; } - return pwritev (fd, vector, count, offset); + if (offset == -1) + return __writev (fd, vector, count); + else + return pwritev (fd, vector, count, offset); } #endif diff --git a/sysdeps/posix/pwritev64v2.c b/sysdeps/posix/pwritev64v2.c index be98aeed9d..ae4c4284c2 100644 --- a/sysdeps/posix/pwritev64v2.c +++ b/sysdeps/posix/pwritev64v2.c @@ -30,7 +30,10 @@ pwritev64v2 (int fd, const struct iovec *vector, int count, OFF_T offset, return -1; } - return pwritev64 (fd, vector, count, offset); + if (offset == -1) + return __writev (fd, vector, count); + else + return pwritev64 (fd, vector, count, offset); } #ifdef __OFF_T_MATCHES_OFF64_T diff --git a/sysdeps/powerpc/fpu/libm-test-ulps b/sysdeps/powerpc/fpu/libm-test-ulps index 7fb67446a5..117c7adb6f 100644 --- a/sysdeps/powerpc/fpu/libm-test-ulps +++ b/sysdeps/powerpc/fpu/libm-test-ulps @@ -860,10 +860,10 @@ ldouble: 3 Function: "cbrt_upward": double: 5 float: 1 -float128: 1 +float128: 2 idouble: 5 ifloat: 1 -ifloat128: 1 +ifloat128: 2 ildouble: 2 ldouble: 2 diff --git a/sysdeps/powerpc/powerpc64/fpu/multiarch/Makefile b/sysdeps/powerpc/powerpc64/fpu/multiarch/Makefile index d6f14f360a..73f2f69377 100644 --- a/sysdeps/powerpc/powerpc64/fpu/multiarch/Makefile +++ b/sysdeps/powerpc/powerpc64/fpu/multiarch/Makefile @@ -1,33 +1,35 @@ ifeq ($(subdir),math) -sysdep_routines += s_isnan-power7 s_isnan-power6x s_isnan-power6 \ - s_isnan-power5 s_isnan-ppc64 s_copysign-power6 \ - s_copysign-ppc64 s_finite-power7 s_finite-ppc64 \ - s_finitef-ppc64 s_isinff-ppc64 s_isinf-power7 \ - s_isinf-ppc64 s_modf-power5+ s_modf-ppc64 \ - s_modff-power5+ s_modff-ppc64 s_isnan-power8 \ - s_isinf-power8 s_finite-power8 +# These functions are built both for libc and libm because they're required +# by printf. While the libc objects have the prefix s_, the libm ones are +# prefixed with m_. +sysdep_calls := s_copysign-power6 s_copysign-ppc64 \ + s_finite-power8 s_finite-power7 s_finite-ppc64 \ + s_finitef-ppc64 \ + s_isinf-power8 s_isinf-ppc64 \ + s_isinff-ppc64 s_isinf-power7 \ + s_isnan-power8 s_isnan-power7 s_isnan-power6x s_isnan-power6 \ + s_isnan-power5 s_isnan-ppc64 \ + s_modf-power5+ s_modf-ppc64 \ + s_modff-power5+ s_modff-ppc64 -libm-sysdep_routines += s_isnan-power7 s_isnan-power6x s_isnan-power6 \ - s_isnan-power5 s_isnan-ppc64 s_llround-power6x \ +sysdep_routines += $(sysdep_calls) +libm-sysdep_routines += s_llround-power6x \ s_llround-power5+ s_llround-ppc64 s_ceil-power5+ \ s_ceil-ppc64 s_ceilf-power5+ s_ceilf-ppc64 \ s_floor-power5+ s_floor-ppc64 s_floorf-power5+ \ s_floorf-ppc64 s_round-power5+ s_round-ppc64 \ s_roundf-power5+ s_roundf-ppc64 s_trunc-power5+ \ s_trunc-ppc64 s_truncf-power5+ s_truncf-ppc64 \ - s_copysign-power6 s_copysign-ppc64 s_llrint-power6x \ - s_llrint-ppc64 s_finite-power7 s_finite-ppc64 \ - s_finitef-ppc64 s_isinff-ppc64 s_isinf-power7 \ - s_isinf-ppc64 s_logb-power7 s_logbf-power7 \ + s_llrint-power6x s_llrint-ppc64 \ + s_logb-power7 s_logbf-power7 \ s_logbl-power7 s_logb-ppc64 s_logbf-ppc64 \ - s_logbl-ppc64 s_modf-power5+ s_modf-ppc64 \ - s_modff-power5+ s_modff-ppc64 e_hypot-ppc64 \ + s_logbl-ppc64 e_hypot-ppc64 \ e_hypot-power7 e_hypotf-ppc64 e_hypotf-power7 \ - s_isnan-power8 s_isinf-power8 s_finite-power8 \ s_llrint-power8 s_llround-power8 s_llroundf-ppc64 \ e_expf-power8 e_expf-ppc64 \ s_sinf-ppc64 s_sinf-power8 \ - s_cosf-ppc64 s_cosf-power8 + s_cosf-ppc64 s_cosf-power8 \ + $(sysdep_calls:s_%=m_%) CFLAGS-s_logbf-power7.c = -mcpu=power7 CFLAGS-s_logbl-power7.c = -mcpu=power7 diff --git a/sysdeps/powerpc/powerpc64/fpu/multiarch/s_isnan-ppc64.S b/sysdeps/powerpc/powerpc64/fpu/multiarch/s_isnan-ppc64.S index ee219c14be..eba0d4ff5e 100644 --- a/sysdeps/powerpc/powerpc64/fpu/multiarch/s_isnan-ppc64.S +++ b/sysdeps/powerpc/powerpc64/fpu/multiarch/s_isnan-ppc64.S @@ -23,6 +23,9 @@ #define weak_alias(a,b) #undef strong_alias #define strong_alias(a,b) +#undef compat_symbol +#define compat_symbol(a,b,c,d) + #define __isnan __isnan_ppc64 #undef hidden_def diff --git a/sysdeps/unix/getlogin_r.c b/sysdeps/unix/getlogin_r.c index 4a6a40eeb2..ad8e9111f6 100644 --- a/sysdeps/unix/getlogin_r.c +++ b/sysdeps/unix/getlogin_r.c @@ -80,7 +80,7 @@ __getlogin_r (char *name, size_t name_len) if (result == 0) { - size_t needed = strlen (ut->ut_user) + 1; + size_t needed = __strnlen (ut->ut_user, UT_NAMESIZE) + 1; if (needed > name_len) { @@ -89,7 +89,8 @@ __getlogin_r (char *name, size_t name_len) } else { - memcpy (name, ut->ut_user, needed); + memcpy (name, ut->ut_user, needed - 1); + name[needed - 1] = 0; result = 0; } } diff --git a/sysdeps/unix/sysv/linux/bits/types/siginfo_t.h b/sysdeps/unix/sysv/linux/bits/types/siginfo_t.h index bed69148f9..18d60bc705 100644 --- a/sysdeps/unix/sysv/linux/bits/types/siginfo_t.h +++ b/sysdeps/unix/sysv/linux/bits/types/siginfo_t.h @@ -107,7 +107,7 @@ typedef struct /* SIGPOLL. */ struct { - long int si_band; /* Band event for SIGPOLL. */ + __SI_BAND_TYPE si_band; /* Band event for SIGPOLL. */ int si_fd; } _sigpoll; diff --git a/sysdeps/unix/sysv/linux/getlogin_r.c b/sysdeps/unix/sysv/linux/getlogin_r.c index 05ac36b491..fe81fd196a 100644 --- a/sysdeps/unix/sysv/linux/getlogin_r.c +++ b/sysdeps/unix/sysv/linux/getlogin_r.c @@ -54,6 +54,15 @@ __getlogin_r_loginuid (char *name, size_t namesize) endp == uidbuf || *endp != '\0')) return -1; + /* If there is no login uid, linux sets /proc/self/loginid to the sentinel + value of, (uid_t) -1, so check if that value is set and return early to + avoid making unneeded nss lookups. */ + if (uid == (uid_t) -1) + { + __set_errno (ENXIO); + return ENXIO; + } + size_t buflen = 1024; char *buf = alloca (buflen); bool use_malloc = false; diff --git a/sysdeps/unix/sysv/linux/i386/Makefile b/sysdeps/unix/sysv/linux/i386/Makefile index 4080b8c966..da716e2c1b 100644 --- a/sysdeps/unix/sysv/linux/i386/Makefile +++ b/sysdeps/unix/sysv/linux/i386/Makefile @@ -3,6 +3,9 @@ default-abi := 32 ifeq ($(subdir),misc) sysdep_routines += ioperm iopl vm86 + +tests += tst-bz21269 +$(objpfx)tst-bz21269: $(shared-thread-library) endif ifeq ($(subdir),elf) diff --git a/sysdeps/unix/sysv/linux/i386/sigaction.c b/sysdeps/unix/sysv/linux/i386/sigaction.c index 0cc9d67ad9..1cad07b26c 100644 --- a/sysdeps/unix/sysv/linux/i386/sigaction.c +++ b/sysdeps/unix/sysv/linux/i386/sigaction.c @@ -42,7 +42,6 @@ extern void restore_rt (void) asm ("__restore_rt") attribute_hidden; #endif extern void restore (void) asm ("__restore") attribute_hidden; - /* If ACT is not NULL, change the action for SIG to *ACT. If OACT is not NULL, put the old action for SIG in *OACT. */ int @@ -65,6 +64,8 @@ __libc_sigaction (int sig, const struct sigaction *act, struct sigaction *oact) kact.sa_restorer = ((act->sa_flags & SA_SIGINFO) ? &restore_rt : &restore); } + else + kact.sa_restorer = NULL; } /* XXX The size argument hopefully will have to be changed to the diff --git a/sysdeps/unix/sysv/linux/i386/tst-bz21269.c b/sysdeps/unix/sysv/linux/i386/tst-bz21269.c new file mode 100644 index 0000000000..353e36507d --- /dev/null +++ b/sysdeps/unix/sysv/linux/i386/tst-bz21269.c @@ -0,0 +1,233 @@ +/* Test for i386 sigaction sa_restorer handling (BZ#21269) + Copyright (C) 2017 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/>. */ + +/* This is based on Linux test tools/testing/selftests/x86/ldt_gdt.c, + more specifically in do_multicpu_tests function. The main changes + are: + + - C11 atomics instead of plain access. + - Remove x86_64 support which simplifies the syscall handling + and fallbacks. + - Replicate only the test required to trigger the issue for the + BZ#21269. */ + +#include <stdatomic.h> + +#include <asm/ldt.h> +#include <linux/futex.h> + +#include <setjmp.h> +#include <signal.h> +#include <errno.h> +#include <sys/syscall.h> +#include <sys/mman.h> + +#include <support/xunistd.h> +#include <support/check.h> +#include <support/xthread.h> + +static int +xset_thread_area (struct user_desc *u_info) +{ + long ret = syscall (SYS_set_thread_area, u_info); + TEST_VERIFY_EXIT (ret == 0); + return ret; +} + +static void +xmodify_ldt (int func, const void *ptr, unsigned long bytecount) +{ + TEST_VERIFY_EXIT (syscall (SYS_modify_ldt, 1, ptr, bytecount) == 0); +} + +static int +futex (int *uaddr, int futex_op, int val, void *timeout, int *uaddr2, + int val3) +{ + return syscall (SYS_futex, uaddr, futex_op, val, timeout, uaddr2, val3); +} + +static void +xsethandler (int sig, void (*handler)(int, siginfo_t *, void *), int flags) +{ + struct sigaction sa = { 0 }; + sa.sa_sigaction = handler; + sa.sa_flags = SA_SIGINFO | flags; + TEST_VERIFY_EXIT (sigemptyset (&sa.sa_mask) == 0); + TEST_VERIFY_EXIT (sigaction (sig, &sa, 0) == 0); +} + +static jmp_buf jmpbuf; + +static void +sigsegv_handler (int sig, siginfo_t *info, void *ctx_void) +{ + siglongjmp (jmpbuf, 1); +} + +/* Points to an array of 1024 ints, each holding its own index. */ +static const unsigned int *counter_page; +static struct user_desc *low_user_desc; +static struct user_desc *low_user_desc_clear; /* Used to delete GDT entry. */ +static int gdt_entry_num; + +static void +setup_counter_page (void) +{ + long page_size = sysconf (_SC_PAGE_SIZE); + TEST_VERIFY_EXIT (page_size > 0); + unsigned int *page = xmmap (NULL, page_size, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE | MAP_32BIT, -1); + for (int i = 0; i < (page_size / sizeof (unsigned int)); i++) + page[i] = i; + counter_page = page; +} + +static void +setup_low_user_desc (void) +{ + low_user_desc = xmmap (NULL, 2 * sizeof (struct user_desc), + PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE | MAP_32BIT, -1); + + low_user_desc->entry_number = -1; + low_user_desc->base_addr = (unsigned long) &counter_page[1]; + low_user_desc->limit = 0xffff; + low_user_desc->seg_32bit = 1; + low_user_desc->contents = 0; + low_user_desc->read_exec_only = 0; + low_user_desc->limit_in_pages = 1; + low_user_desc->seg_not_present = 0; + low_user_desc->useable = 0; + + xset_thread_area (low_user_desc); + + low_user_desc_clear = low_user_desc + 1; + low_user_desc_clear->entry_number = gdt_entry_num; + low_user_desc_clear->read_exec_only = 1; + low_user_desc_clear->seg_not_present = 1; +} + +/* Possible values of futex: + 0: thread is idle. + 1: thread armed. + 2: thread should clear LDT entry 0. + 3: thread should exit. */ +static atomic_uint ftx; + +static void * +threadproc (void *ctx) +{ + while (1) + { + futex ((int *) &ftx, FUTEX_WAIT, 1, NULL, NULL, 0); + while (atomic_load (&ftx) != 2) + { + if (atomic_load (&ftx) >= 3) + return NULL; + } + + /* clear LDT entry 0. */ + const struct user_desc desc = { 0 }; + xmodify_ldt (1, &desc, sizeof (desc)); + + /* If ftx == 2, set it to zero, If ftx == 100, quit. */ + if (atomic_fetch_add (&ftx, -2) != 2) + return NULL; + } +} + + +/* As described in testcase, for historical reasons x86_32 Linux (and compat + on x86_64) interprets SA_RESTORER clear with nonzero sa_restorer as a + request for stack switching if the SS segment is 'funny' (this is default + scenario for vDSO system). This means that anything that tries to mix + signal handling with segmentation should explicit clear the sa_restorer. + + This testcase check if sigaction in fact does it by changing the local + descriptor table (LDT) through the modify_ldt syscall and triggering + a synchronous segfault on iret fault by trying to install an invalid + segment. With a correct zeroed sa_restorer it should not trigger an + 'real' SEGSEGV and allows the siglongjmp in signal handler. */ + +static int +do_test (void) +{ + setup_counter_page (); + setup_low_user_desc (); + + pthread_t thread; + unsigned short orig_ss; + + xsethandler (SIGSEGV, sigsegv_handler, 0); + /* 32-bit kernels send SIGILL instead of SIGSEGV on IRET faults. */ + xsethandler (SIGILL, sigsegv_handler, 0); + + thread = xpthread_create (0, threadproc, 0); + + asm volatile ("mov %%ss, %0" : "=rm" (orig_ss)); + + for (int i = 0; i < 5; i++) + { + if (sigsetjmp (jmpbuf, 1) != 0) + continue; + + /* Make sure the thread is ready after the last test. */ + while (atomic_load (&ftx) != 0) + ; + + struct user_desc desc = { + .entry_number = 0, + .base_addr = 0, + .limit = 0xffff, + .seg_32bit = 1, + .contents = 0, + .read_exec_only = 0, + .limit_in_pages = 1, + .seg_not_present = 0, + .useable = 0 + }; + + xmodify_ldt (0x11, &desc, sizeof (desc)); + + /* Arm the thread. */ + ftx = 1; + futex ((int*) &ftx, FUTEX_WAKE, 0, NULL, NULL, 0); + + asm volatile ("mov %0, %%ss" : : "r" (0x7)); + + /* Fire up thread modify_ldt call. */ + atomic_store (&ftx, 2); + + while (atomic_load (&ftx) != 0) + ; + + /* On success, modify_ldt will segfault us synchronously and we will + escape via siglongjmp. */ + support_record_failure (); + } + + atomic_store (&ftx, 100); + futex ((int*) &ftx, FUTEX_WAKE, 0, NULL, NULL, 0); + + xpthread_join (thread); + + return 0; +} + +#include <support/test-driver.c> diff --git a/sysdeps/unix/sysv/linux/if_index.c b/sysdeps/unix/sysv/linux/if_index.c index 8ba5eae781..b620d21936 100644 --- a/sysdeps/unix/sysv/linux/if_index.c +++ b/sysdeps/unix/sysv/linux/if_index.c @@ -38,12 +38,19 @@ __if_nametoindex (const char *ifname) return 0; #else struct ifreq ifr; + if (strlen (ifname) >= IFNAMSIZ) + { + __set_errno (ENODEV); + return 0; + } + + strncpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); + int fd = __opensock (); if (fd < 0) return 0; - strncpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); if (__ioctl (fd, SIOCGIFINDEX, &ifr) < 0) { int saved_errno = errno; diff --git a/sysdeps/unix/sysv/linux/ifaddrs.c b/sysdeps/unix/sysv/linux/ifaddrs.c index 3bc9902863..4f75401850 100644 --- a/sysdeps/unix/sysv/linux/ifaddrs.c +++ b/sysdeps/unix/sysv/linux/ifaddrs.c @@ -371,6 +371,14 @@ getifaddrs_internal (struct ifaddrs **ifap) if ((pid_t) nlh->nlmsg_pid != nh.pid || nlh->nlmsg_seq != nlp->seq) continue; + /* If the dump got interrupted, we can't rely on the results + so try again. */ + if (nlh->nlmsg_flags & NLM_F_DUMP_INTR) + { + result = -EAGAIN; + goto exit_free; + } + if (nlh->nlmsg_type == NLMSG_DONE) break; /* ok */ diff --git a/sysdeps/unix/sysv/linux/preadv2.c b/sysdeps/unix/sysv/linux/preadv2.c index 137e2dd791..c7f91025f2 100644 --- a/sysdeps/unix/sysv/linux/preadv2.c +++ b/sysdeps/unix/sysv/linux/preadv2.c @@ -32,7 +32,7 @@ preadv2 (int fd, const struct iovec *vector, int count, off_t offset, # ifdef __NR_preadv2 ssize_t result = SYSCALL_CANCEL (preadv2, fd, vector, count, LO_HI_LONG (offset), flags); - if (result >= 0) + if (result >= 0 || errno != ENOSYS) return result; # endif /* Trying to emulate the preadv2 syscall flags is troublesome: @@ -49,7 +49,10 @@ preadv2 (int fd, const struct iovec *vector, int count, off_t offset, __set_errno (ENOTSUP); return -1; } - return preadv (fd, vector, count, offset); + if (offset == -1) + return __readv (fd, vector, count); + else + return preadv (fd, vector, count, offset); } #endif diff --git a/sysdeps/unix/sysv/linux/preadv64v2.c b/sysdeps/unix/sysv/linux/preadv64v2.c index 8f413253f4..4dbea0a8d4 100644 --- a/sysdeps/unix/sysv/linux/preadv64v2.c +++ b/sysdeps/unix/sysv/linux/preadv64v2.c @@ -30,7 +30,7 @@ preadv64v2 (int fd, const struct iovec *vector, int count, off64_t offset, #ifdef __NR_preadv64v2 ssize_t result = SYSCALL_CANCEL (preadv64v2, fd, vector, count, LO_HI_LONG (offset), flags); - if (result >= 0) + if (result >= 0 || errno != ENOSYS) return result; #endif /* Trying to emulate the preadv2 syscall flags is troublesome: @@ -47,7 +47,11 @@ preadv64v2 (int fd, const struct iovec *vector, int count, off64_t offset, __set_errno (ENOTSUP); return -1; } - return preadv64 (fd, vector, count, offset); + + if (offset == -1) + return __readv (fd, vector, count); + else + return preadv64 (fd, vector, count, offset); } #ifdef __OFF_T_MATCHES_OFF64_T diff --git a/sysdeps/unix/sysv/linux/pwritev2.c b/sysdeps/unix/sysv/linux/pwritev2.c index 8e5032fe2f..a33ed56c55 100644 --- a/sysdeps/unix/sysv/linux/pwritev2.c +++ b/sysdeps/unix/sysv/linux/pwritev2.c @@ -28,7 +28,7 @@ pwritev2 (int fd, const struct iovec *vector, int count, off_t offset, # ifdef __NR_pwritev2 ssize_t result = SYSCALL_CANCEL (pwritev2, fd, vector, count, LO_HI_LONG (offset), flags); - if (result >= 0) + if (result >= 0 || errno != ENOSYS) return result; # endif /* Trying to emulate the pwritev2 syscall flags is troublesome: @@ -45,7 +45,10 @@ pwritev2 (int fd, const struct iovec *vector, int count, off_t offset, __set_errno (ENOTSUP); return -1; } - return pwritev (fd, vector, count, offset); + if (offset == -1) + return __writev (fd, vector, count); + else + return pwritev (fd, vector, count, offset); } #endif diff --git a/sysdeps/unix/sysv/linux/pwritev64v2.c b/sysdeps/unix/sysv/linux/pwritev64v2.c index d2800c6657..f0ffd2f1f6 100644 --- a/sysdeps/unix/sysv/linux/pwritev64v2.c +++ b/sysdeps/unix/sysv/linux/pwritev64v2.c @@ -30,7 +30,7 @@ pwritev64v2 (int fd, const struct iovec *vector, int count, off64_t offset, #ifdef __NR_pwritev64v2 ssize_t result = SYSCALL_CANCEL (pwritev64v2, fd, vector, count, LO_HI_LONG (offset), flags); - if (result >= 0) + if (result >= 0 || errno != ENOSYS) return result; #endif /* Trying to emulate the pwritev2 syscall flags is troublesome: @@ -47,7 +47,10 @@ pwritev64v2 (int fd, const struct iovec *vector, int count, off64_t offset, __set_errno (ENOTSUP); return -1; } - return pwritev64 (fd, vector, count, offset); + if (offset == -1) + return __writev (fd, vector, count); + else + return pwritev64 (fd, vector, count, offset); } #ifdef __OFF_T_MATCHES_OFF64_T diff --git a/sysdeps/unix/sysv/linux/s390/bits/utmp.h b/sysdeps/unix/sysv/linux/s390/bits/utmp.h index 36114c3b0e..f754f374b5 100644 --- a/sysdeps/unix/sysv/linux/s390/bits/utmp.h +++ b/sysdeps/unix/sysv/linux/s390/bits/utmp.h @@ -59,10 +59,13 @@ struct utmp { short int ut_type; /* Type of login. */ pid_t ut_pid; /* Process ID of login process. */ - char ut_line[UT_LINESIZE]; /* Devicename. */ + char ut_line[UT_LINESIZE] + __attribute_nonstring__; /* Devicename. */ char ut_id[4]; /* Inittab ID. */ - char ut_user[UT_NAMESIZE]; /* Username. */ - char ut_host[UT_HOSTSIZE]; /* Hostname for remote login. */ + char ut_user[UT_NAMESIZE] + __attribute_nonstring__; /* Username. */ + char ut_host[UT_HOSTSIZE] + __attribute_nonstring__; /* Hostname for remote login. */ struct exit_status ut_exit; /* Exit status of a process marked as DEAD_PROCESS. */ /* The ut_session and ut_tv fields must be the same size when compiled diff --git a/sysdeps/unix/sysv/linux/spawni.c b/sysdeps/unix/sysv/linux/spawni.c index 7d23df84d2..2d7502adaa 100644 --- a/sysdeps/unix/sysv/linux/spawni.c +++ b/sysdeps/unix/sysv/linux/spawni.c @@ -101,7 +101,7 @@ maybe_script_execute (struct posix_spawn_args *args) ptrdiff_t argc = args->argc; /* Construct an argument list for the shell. */ - char *new_argv[argc + 1]; + char *new_argv[argc + 2]; new_argv[0] = (char *) _PATH_BSHELL; new_argv[1] = (char *) args->file; if (argc > 1) diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c index 87aaa8683c..b3a5f4b26a 100644 --- a/sysdeps/x86/cpu-features.c +++ b/sysdeps/x86/cpu-features.c @@ -31,6 +31,20 @@ extern void TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *) #endif static void +get_extended_indices (struct cpu_features *cpu_features) +{ + unsigned int eax, ebx, ecx, edx; + __cpuid (0x80000000, eax, ebx, ecx, edx); + if (eax >= 0x80000001) + __cpuid (0x80000001, + cpu_features->cpuid[COMMON_CPUID_INDEX_80000001].eax, + cpu_features->cpuid[COMMON_CPUID_INDEX_80000001].ebx, + cpu_features->cpuid[COMMON_CPUID_INDEX_80000001].ecx, + cpu_features->cpuid[COMMON_CPUID_INDEX_80000001].edx); + +} + +static void get_common_indeces (struct cpu_features *cpu_features, unsigned int *family, unsigned int *model, unsigned int *extended_model, unsigned int *stepping) @@ -205,6 +219,8 @@ init_cpu_features (struct cpu_features *cpu_features) get_common_indeces (cpu_features, &family, &model, &extended_model, &stepping); + get_extended_indices (cpu_features); + if (family == 0x06) { model += extended_model; @@ -281,7 +297,13 @@ init_cpu_features (struct cpu_features *cpu_features) | bit_arch_Fast_Unaligned_Copy | bit_arch_Prefer_PMINUB_for_stringop); break; + } + /* Disable TSX on some Haswell processors to avoid TSX on kernels that + weren't updated with the latest microcode package (which disables + broken feature by default). */ + switch (model) + { case 0x3f: /* Xeon E7 v3 with stepping >= 4 has working TSX. */ if (stepping >= 4) @@ -324,16 +346,9 @@ init_cpu_features (struct cpu_features *cpu_features) get_common_indeces (cpu_features, &family, &model, &extended_model, &stepping); - ecx = cpu_features->cpuid[COMMON_CPUID_INDEX_1].ecx; + get_extended_indices (cpu_features); - unsigned int eax; - __cpuid (0x80000000, eax, ebx, ecx, edx); - if (eax >= 0x80000001) - __cpuid (0x80000001, - cpu_features->cpuid[COMMON_CPUID_INDEX_80000001].eax, - cpu_features->cpuid[COMMON_CPUID_INDEX_80000001].ebx, - cpu_features->cpuid[COMMON_CPUID_INDEX_80000001].ecx, - cpu_features->cpuid[COMMON_CPUID_INDEX_80000001].edx); + ecx = cpu_features->cpuid[COMMON_CPUID_INDEX_1].ecx; if (HAS_ARCH_FEATURE (AVX_Usable)) { diff --git a/sysdeps/x86/cpu-features.h b/sysdeps/x86/cpu-features.h index 1d88f7a68c..e4eb6bf41a 100644 --- a/sysdeps/x86/cpu-features.h +++ b/sysdeps/x86/cpu-features.h @@ -196,7 +196,7 @@ enum { COMMON_CPUID_INDEX_1 = 0, COMMON_CPUID_INDEX_7, - COMMON_CPUID_INDEX_80000001, /* for AMD */ + COMMON_CPUID_INDEX_80000001, /* Keep the following line at the end. */ COMMON_CPUID_INDEX_MAX }; @@ -292,7 +292,7 @@ extern const struct cpu_features *__get_cpu_features (void) # define index_cpu_HTT COMMON_CPUID_INDEX_1 # define index_cpu_BMI1 COMMON_CPUID_INDEX_7 # define index_cpu_BMI2 COMMON_CPUID_INDEX_7 -# define index_cpu_LZCNT COMMON_CPUID_INDEX_1 +# define index_cpu_LZCNT COMMON_CPUID_INDEX_80000001 # define index_cpu_MOVBE COMMON_CPUID_INDEX_1 # define index_cpu_POPCNT COMMON_CPUID_INDEX_1 diff --git a/sysdeps/x86_64/multiarch/memmove-avx512-no-vzeroupper.S b/sysdeps/x86_64/multiarch/memmove-avx512-no-vzeroupper.S index f3ef10577c..ae84ddc667 100644 --- a/sysdeps/x86_64/multiarch/memmove-avx512-no-vzeroupper.S +++ b/sysdeps/x86_64/multiarch/memmove-avx512-no-vzeroupper.S @@ -340,6 +340,7 @@ L(preloop_large): vmovups (%rsi), %zmm4 vmovups 0x40(%rsi), %zmm5 + mov %rdi, %r11 /* Align destination for access with non-temporal stores in the loop. */ mov %rdi, %r8 and $-0x80, %rdi @@ -370,8 +371,8 @@ L(gobble_256bytes_nt_loop): cmp $256, %rdx ja L(gobble_256bytes_nt_loop) sfence - vmovups %zmm4, (%rax) - vmovups %zmm5, 0x40(%rax) + vmovups %zmm4, (%r11) + vmovups %zmm5, 0x40(%r11) jmp L(check) L(preloop_large_bkw): diff --git a/time/bits/types/struct_timespec.h b/time/bits/types/struct_timespec.h index 644db9fdb6..5b77c52b4f 100644 --- a/time/bits/types/struct_timespec.h +++ b/time/bits/types/struct_timespec.h @@ -1,5 +1,6 @@ -#ifndef __timespec_defined -#define __timespec_defined 1 +/* NB: Include guard matches what <linux/time.h> uses. */ +#ifndef _STRUCT_TIMESPEC +#define _STRUCT_TIMESPEC 1 #include <bits/types.h> diff --git a/timezone/zic.c b/timezone/zic.c index 946bf6ff8e..e738386600 100644 --- a/timezone/zic.c +++ b/timezone/zic.c @@ -1949,7 +1949,7 @@ writezone(const char *const name, const char *const string, char version) } #define DO(field) fwrite(tzh.field, sizeof tzh.field, 1, fp) tzh = tzh0; - strncpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic); + memcpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic); tzh.tzh_version[0] = version; convert(thistypecnt, tzh.tzh_ttisgmtcnt); convert(thistypecnt, tzh.tzh_ttisstdcnt); |