commit 7f11842e7483da7aa9fa3031be122021978ef600 Author: Samuel Thibault Date: Wed Aug 8 01:55:04 2018 +0200 hurd: Add missing symbols for proper libc_get/setspecific * htl/Versions (__pthread_getspecific, __pthread_setspecific): Add symbols. diff --git a/ChangeLog b/ChangeLog index 08b42bd2f5..31abb116a5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2018-08-08 Samuel Thibault + + * htl/Versions (__pthread_getspecific, __pthread_setspecific): Add + symbols. + 2018-08-01 Carlos O'Donel * version.h (RELEASE): Set to "stable". diff --git a/htl/Versions b/htl/Versions index 6a63a1b8a1..c5a616da10 100644 --- a/htl/Versions +++ b/htl/Versions @@ -150,6 +150,8 @@ libpthread { __cthread_keycreate; __cthread_getspecific; __cthread_setspecific; + __pthread_getspecific; + __pthread_setspecific; __pthread_getattr_np; __pthread_attr_getstack; } commit 726e1554ce4db5e35af41cb0110c54c5e1232054 Author: Samuel Thibault Date: Thu Aug 9 01:26:19 2018 +0200 hurd: Avoid PLTs for __pthread_get/setspecific * sysdeps/htl/pthreadP.h [IS_IN (libpthread)] (__pthread_getspecific, __pthread_setspecific): Add hidden proto. * sysdeps/htl/pt-getspecific.c (__pthread_getspecific): Add hidden def. * sysdeps/htl/pt-setspecific.c (__pthread_setspecific): Add hidden def. diff --git a/ChangeLog b/ChangeLog index 31abb116a5..dbcc56667b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,10 @@ * htl/Versions (__pthread_getspecific, __pthread_setspecific): Add symbols. + * sysdeps/htl/pthreadP.h [IS_IN (libpthread)] (__pthread_getspecific, + __pthread_setspecific): Add hidden proto. + * sysdeps/htl/pt-getspecific.c (__pthread_getspecific): Add hidden def. + * sysdeps/htl/pt-setspecific.c (__pthread_setspecific): Add hidden def. 2018-08-01 Carlos O'Donel diff --git a/sysdeps/htl/pt-getspecific.c b/sysdeps/htl/pt-getspecific.c index a0227a67f6..64ddf9551a 100644 --- a/sysdeps/htl/pt-getspecific.c +++ b/sysdeps/htl/pt-getspecific.c @@ -36,3 +36,4 @@ __pthread_getspecific (pthread_key_t key) return self->thread_specifics[key]; } strong_alias (__pthread_getspecific, pthread_getspecific); +hidden_def (__pthread_getspecific) diff --git a/sysdeps/htl/pt-setspecific.c b/sysdeps/htl/pt-setspecific.c index a46a12f157..02aff417ef 100644 --- a/sysdeps/htl/pt-setspecific.c +++ b/sysdeps/htl/pt-setspecific.c @@ -48,3 +48,4 @@ __pthread_setspecific (pthread_key_t key, const void *value) return 0; } strong_alias (__pthread_setspecific, pthread_setspecific); +hidden_def (__pthread_setspecific) diff --git a/sysdeps/htl/pthreadP.h b/sysdeps/htl/pthreadP.h index 132ac1718e..71c2fcd9c6 100644 --- a/sysdeps/htl/pthreadP.h +++ b/sysdeps/htl/pthreadP.h @@ -68,6 +68,8 @@ struct __pthread_cancelation_handler **___pthread_get_cleanup_stack (void) attri #if IS_IN (libpthread) hidden_proto (__pthread_key_create) +hidden_proto (__pthread_getspecific) +hidden_proto (__pthread_setspecific) hidden_proto (_pthread_mutex_init) #endif commit 4b25485f03158959cff45379eecc1d73c7dcdd11 Author: Florian Weimer Date: Fri Aug 10 11:19:26 2018 +0200 Linux: Rewrite __old_getdents64 [BZ #23497] Commit 298d0e3129c0b5137f4989275b13fe30d0733c4d ("Consolidate Linux getdents{64} implementation") broke the implementation because it does not take into account struct offset differences. The new implementation is close to the old one, before the consolidation, but has been cleaned up slightly. (cherry picked from commit 690652882b499defb3d950dfeff8fe421d13cab5) diff --git a/ChangeLog b/ChangeLog index dbcc56667b..f32ed3e74c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2018-08-10 Florian Weimer + + [BZ #23497] + * sysdeps/unix/sysv/linux/getdents64.c (handle_overflow): New + function. + (__old_getdents64): Use getdents64. Convert entries without + moving them. + * sysdeps/unix/sysv/linux/tst-readdir64-compat.c: New file. + * sysdeps/unix/sysv/linux/Makefile (tests-internal): Add + tst-readdir64-compat. + 2018-08-08 Samuel Thibault * htl/Versions (__pthread_getspecific, __pthread_setspecific): Add diff --git a/NEWS b/NEWS index 154ab22d7c..b733755ff6 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,13 @@ See the end for copying conditions. Please send GNU C library bug reports via using `glibc' in the "product" field. +Version 2.28.1 + +The following bugs are resolved with this release: + + [23497] readdir64@GLIBC_2.1 cannot parse the kernel directory stream + + Version 2.28 Major new features: diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile index f71cc39c7e..773aaea0e9 100644 --- a/sysdeps/unix/sysv/linux/Makefile +++ b/sysdeps/unix/sysv/linux/Makefile @@ -161,6 +161,7 @@ inhibit-glue = yes ifeq ($(subdir),dirent) sysdep_routines += getdirentries getdirentries64 +tests-internal += tst-readdir64-compat endif ifeq ($(subdir),nis) diff --git a/sysdeps/unix/sysv/linux/getdents64.c b/sysdeps/unix/sysv/linux/getdents64.c index 3bde0cf4f0..bc140b5a7f 100644 --- a/sysdeps/unix/sysv/linux/getdents64.c +++ b/sysdeps/unix/sysv/linux/getdents64.c @@ -33,41 +33,80 @@ strong_alias (__getdents64, __getdents) # include # if SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_2) -# include +# include +# include -/* kernel definition of as of 3.2. */ -struct compat_linux_dirent +static ssize_t +handle_overflow (int fd, __off64_t offset, ssize_t count) { - /* Both d_ino and d_off are compat_ulong_t which are defined in all - architectures as 'u32'. */ - uint32_t d_ino; - uint32_t d_off; - unsigned short d_reclen; - char d_name[1]; -}; + /* If this is the first entry in the buffer, we can report the + error. */ + if (count == 0) + { + __set_errno (EOVERFLOW); + return -1; + } + + /* Otherwise, seek to the overflowing entry, so that the next call + will report the error, and return the data read so far.. */ + if (__lseek64 (fd, offset, SEEK_SET) != 0) + return -1; + return count; +} ssize_t __old_getdents64 (int fd, char *buf, size_t nbytes) { - ssize_t retval = INLINE_SYSCALL_CALL (getdents, fd, buf, nbytes); + /* We do not move the individual directory entries. This is only + possible if the target type (struct __old_dirent64) is smaller + than the source type. */ + _Static_assert (offsetof (struct __old_dirent64, d_name) + <= offsetof (struct dirent64, d_name), + "__old_dirent64 is larger than dirent64"); + _Static_assert (__alignof__ (struct __old_dirent64) + <= __alignof__ (struct dirent64), + "alignment of __old_dirent64 is larger than dirent64"); - /* The kernel added the d_type value after the name. Change this now. */ - if (retval != -1) + ssize_t retval = INLINE_SYSCALL_CALL (getdents64, fd, buf, nbytes); + if (retval > 0) { - union - { - struct compat_linux_dirent k; - struct dirent u; - } *kbuf = (void *) buf; - - while ((char *) kbuf < buf + retval) + char *p = buf; + char *end = buf + retval; + while (p < end) { - char d_type = *((char *) kbuf + kbuf->k.d_reclen - 1); - memmove (kbuf->u.d_name, kbuf->k.d_name, - strlen (kbuf->k.d_name) + 1); - kbuf->u.d_type = d_type; + struct dirent64 *source = (struct dirent64 *) p; + + /* Copy out the fixed-size data. */ + __ino_t ino = source->d_ino; + __off64_t offset = source->d_off; + unsigned int reclen = source->d_reclen; + unsigned char type = source->d_type; + + /* Check for ino_t overflow. */ + if (__glibc_unlikely (ino != source->d_ino)) + return handle_overflow (fd, offset, p - buf); + + /* Convert to the target layout. Use a separate struct and + memcpy to side-step aliasing issues. */ + struct __old_dirent64 result; + result.d_ino = ino; + result.d_off = offset; + result.d_reclen = reclen; + result.d_type = type; + + /* Write the fixed-sized part of the result to the + buffer. */ + size_t result_name_offset = offsetof (struct __old_dirent64, d_name); + memcpy (p, &result, result_name_offset); + + /* Adjust the position of the name if necessary. Copy + everything until the end of the record, including the + terminating NUL byte. */ + if (result_name_offset != offsetof (struct dirent64, d_name)) + memmove (p + result_name_offset, source->d_name, + reclen - offsetof (struct dirent64, d_name)); - kbuf = (void *) ((char *) kbuf + kbuf->k.d_reclen); + p += reclen; } } return retval; diff --git a/sysdeps/unix/sysv/linux/tst-readdir64-compat.c b/sysdeps/unix/sysv/linux/tst-readdir64-compat.c new file mode 100644 index 0000000000..43c4a8477c --- /dev/null +++ b/sysdeps/unix/sysv/linux/tst-readdir64-compat.c @@ -0,0 +1,111 @@ +/* Test readdir64 compatibility symbol. + 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 + . */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* Copied from . */ +struct __old_dirent64 + { + __ino_t d_ino; + __off64_t d_off; + unsigned short int d_reclen; + unsigned char d_type; + char d_name[256]; + }; + +typedef struct __old_dirent64 *(*compat_readdir64_type) (DIR *); + +#if TEST_COMPAT (libc, GLIBC_2_1, GLIBC_2_2) +struct __old_dirent64 *compat_readdir64 (DIR *); +compat_symbol_reference (libc, compat_readdir64, readdir64, GLIBC_2_1); +#endif + +static int +do_test (void) +{ +#if TEST_COMPAT (libc, GLIBC_2_1, GLIBC_2_2) + + /* Directory stream using the non-compat readdir64 symbol. The test + checks against this. */ + DIR *dir_reference = opendir ("."); + TEST_VERIFY_EXIT (dir_reference != NULL); + DIR *dir_test = opendir ("."); + TEST_VERIFY_EXIT (dir_test != NULL); + + /* This loop assumes that the enumeration order is consistent for + two different handles. Nothing should write to the current + directory (in the source tree) while this test runs, so there + should not be any difference due to races. */ + size_t count = 0; + while (true) + { + errno = 0; + struct dirent64 *entry_reference = readdir64 (dir_reference); + if (entry_reference == NULL && errno != 0) + FAIL_EXIT1 ("readdir64 entry %zu: %m\n", count); + struct __old_dirent64 *entry_test = compat_readdir64 (dir_test); + if (entry_reference == NULL) + { + if (errno == EOVERFLOW) + { + TEST_VERIFY (entry_reference->d_ino + != (__ino_t) entry_reference->d_ino); + printf ("info: inode number overflow at entry %zu\n", count); + break; + } + if (errno != 0) + FAIL_EXIT1 ("compat readdir64 entry %zu: %m\n", count); + } + + /* Check that both streams end at the same time. */ + if (entry_reference == NULL) + { + TEST_VERIFY (entry_test == NULL); + break; + } + else + TEST_VERIFY_EXIT (entry_test != NULL); + + /* Check that the entries are the same. */ + TEST_COMPARE_BLOB (entry_reference->d_name, + strlen (entry_reference->d_name), + entry_test->d_name, strlen (entry_test->d_name)); + TEST_COMPARE (entry_reference->d_ino, entry_test->d_ino); + TEST_COMPARE (entry_reference->d_off, entry_test->d_off); + TEST_COMPARE (entry_reference->d_type, entry_test->d_type); + TEST_COMPARE (entry_reference->d_reclen, entry_test->d_reclen); + + ++count; + } + printf ("info: %zu directory entries found\n", count); + TEST_VERIFY (count >= 3); /* ".", "..", and some source files. */ + + TEST_COMPARE (closedir (dir_test), 0); + TEST_COMPARE (closedir (dir_reference), 0); +#endif + return 0; +} + +#include commit d05b05d1570ba3ae354a2f5a3cfeefb373b09979 Author: Florian Weimer Date: Mon Aug 13 14:28:07 2018 +0200 error, error_at_line: Add missing va_end calls (cherry picked from commit b7b52b9dec337a08a89bc67638773be652eba332) diff --git a/ChangeLog b/ChangeLog index f32ed3e74c..cc918e96a3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2018-08-13 Florian Weimer + + * misc/error.c (error): Add missing va_end call. + (error_at_line): Likewise. + 2018-08-10 Florian Weimer [BZ #23497] diff --git a/misc/error.c b/misc/error.c index b4e8b6c938..03378e2f2a 100644 --- a/misc/error.c +++ b/misc/error.c @@ -319,6 +319,7 @@ error (int status, int errnum, const char *message, ...) va_start (args, message); error_tail (status, errnum, message, args); + va_end (args); #ifdef _LIBC _IO_funlockfile (stderr); @@ -390,6 +391,7 @@ error_at_line (int status, int errnum, const char *file_name, va_start (args, message); error_tail (status, errnum, message, args); + va_end (args); #ifdef _LIBC _IO_funlockfile (stderr); commit bfcfa22589f2b4277a65e60c6b736b6bbfbd87d0 Author: Florian Weimer Date: Tue Aug 14 10:51:07 2018 +0200 nscd: Deallocate existing user names in file parser This avoids a theoretical memory leak (theoretical because it depends on multiple server-user/stat-user directives in the configuration file). (cherry picked from commit 2d7acfac3ebf266dcbc82d0d6cc576f626953a03) diff --git a/ChangeLog b/ChangeLog index cc918e96a3..0cbfb504f4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2018-08-14 Florian Weimer + + * nscd/nscd_conf.c (nscd_parse_file): Deallocate old storage for + server_user, stat_user. + 2018-08-13 Florian Weimer * misc/error.c (error): Add missing va_end call. diff --git a/nscd/nscd_conf.c b/nscd/nscd_conf.c index 265a02434d..7293b795b6 100644 --- a/nscd/nscd_conf.c +++ b/nscd/nscd_conf.c @@ -190,7 +190,10 @@ nscd_parse_file (const char *fname, struct database_dyn dbs[lastdb]) if (!arg1) error (0, 0, _("Must specify user name for server-user option")); else - server_user = xstrdup (arg1); + { + free ((char *) server_user); + server_user = xstrdup (arg1); + } } else if (strcmp (entry, "stat-user") == 0) { @@ -198,6 +201,7 @@ nscd_parse_file (const char *fname, struct database_dyn dbs[lastdb]) error (0, 0, _("Must specify user name for stat-user option")); else { + free ((char *) stat_user); stat_user = xstrdup (arg1); struct passwd *pw = getpwnam (stat_user); commit 2f498f3d140ab5152bd784df2be7af7d9c5e63ed Author: Florian Weimer Date: Tue Aug 14 10:57:48 2018 +0200 nss_files: Fix file stream leak in aliases lookup [BZ #23521] In order to get a clean test case, it was necessary to fix partially fixed bug 23522 as well. (cherry picked from commit e95c6f61920a0f9237cfb292fa44ad500e1df09b) diff --git a/ChangeLog b/ChangeLog index 0cbfb504f4..d900e1eba1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2018-08-14 Florian Weimer + + [BZ #23521] + [BZ #23522] + * nss/nss_files/files-alias.c (get_next_alias): During :include: + processing, bail out if no room, and close the stream before + returning ERANGE. + * nss/Makefile (tests): Add tst-nss-files-alias-leak. + (tst-nss-files-alias-leak): Link with libdl. + (tst-nss-files-alias-leak.out): Depend on nss_files. + + * nss/tst-nss-files-alias-leak.c: New file. + 2018-08-14 Florian Weimer * nscd/nscd_conf.c (nscd_parse_file): Deallocate old storage for diff --git a/NEWS b/NEWS index b733755ff6..873cf8f64f 100644 --- a/NEWS +++ b/NEWS @@ -10,6 +10,7 @@ Version 2.28.1 The following bugs are resolved with this release: [23497] readdir64@GLIBC_2.1 cannot parse the kernel directory stream + [23521] nss_files aliases database file stream leak Version 2.28 diff --git a/nss/Makefile b/nss/Makefile index 66fac7f5b8..5209fc0456 100644 --- a/nss/Makefile +++ b/nss/Makefile @@ -65,6 +65,7 @@ ifeq (yes,$(build-shared)) tests += tst-nss-files-hosts-erange tests += tst-nss-files-hosts-multi tests += tst-nss-files-hosts-getent +tests += tst-nss-files-alias-leak endif # If we have a thread library then we can test cancellation against @@ -171,3 +172,5 @@ endif $(objpfx)tst-nss-files-hosts-erange: $(libdl) $(objpfx)tst-nss-files-hosts-multi: $(libdl) $(objpfx)tst-nss-files-hosts-getent: $(libdl) +$(objpfx)tst-nss-files-alias-leak: $(libdl) +$(objpfx)tst-nss-files-alias-leak.out: $(objpfx)/libnss_files.so diff --git a/nss/nss_files/files-alias.c b/nss/nss_files/files-alias.c index cfd34b66b9..35b0bfc5d2 100644 --- a/nss/nss_files/files-alias.c +++ b/nss/nss_files/files-alias.c @@ -221,6 +221,13 @@ get_next_alias (FILE *stream, const char *match, struct aliasent *result, { while (! feof_unlocked (listfile)) { + if (room_left < 2) + { + free (old_line); + fclose (listfile); + goto no_more_room; + } + first_unused[room_left - 1] = '\xff'; line = fgets_unlocked (first_unused, room_left, listfile); @@ -229,6 +236,7 @@ get_next_alias (FILE *stream, const char *match, struct aliasent *result, if (first_unused[room_left - 1] != '\xff') { free (old_line); + fclose (listfile); goto no_more_room; } @@ -256,6 +264,7 @@ get_next_alias (FILE *stream, const char *match, struct aliasent *result, + __alignof__ (char *))) { free (old_line); + fclose (listfile); goto no_more_room; } room_left -= ((first_unused - cp) diff --git a/nss/tst-nss-files-alias-leak.c b/nss/tst-nss-files-alias-leak.c new file mode 100644 index 0000000000..26d38e2dba --- /dev/null +++ b/nss/tst-nss-files-alias-leak.c @@ -0,0 +1,237 @@ +/* Check for file descriptor leak in alias :include: processing (bug 23521). + 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 + . */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct support_chroot *chroot_env; + +/* Number of the aliases for the "many" user. This must be large + enough to trigger reallocation for the pointer array, but result in + answers below the maximum size tried in do_test. */ +enum { many_aliases = 30 }; + +static void +prepare (int argc, char **argv) +{ + chroot_env = support_chroot_create + ((struct support_chroot_configuration) { } ); + + char *path = xasprintf ("%s/etc/aliases", chroot_env->path_chroot); + add_temp_file (path); + support_write_file_string + (path, + "user1: :include:/etc/aliases.user1\n" + "user2: :include:/etc/aliases.user2\n" + "comment: comment1, :include:/etc/aliases.comment\n" + "many: :include:/etc/aliases.many\n"); + free (path); + + path = xasprintf ("%s/etc/aliases.user1", chroot_env->path_chroot); + add_temp_file (path); + support_write_file_string (path, "alias1\n"); + free (path); + + path = xasprintf ("%s/etc/aliases.user2", chroot_env->path_chroot); + add_temp_file (path); + support_write_file_string (path, "alias1a, alias2\n"); + free (path); + + path = xasprintf ("%s/etc/aliases.comment", chroot_env->path_chroot); + add_temp_file (path); + support_write_file_string + (path, + /* The line must be longer than the line with the :include: + directive in /etc/aliases. */ + "# Long line. ##############################################\n" + "comment2\n"); + free (path); + + path = xasprintf ("%s/etc/aliases.many", chroot_env->path_chroot); + add_temp_file (path); + FILE *fp = xfopen (path, "w"); + for (int i = 0; i < many_aliases; ++i) + fprintf (fp, "a%d\n", i); + TEST_VERIFY_EXIT (! ferror (fp)); + xfclose (fp); + free (path); +} + +/* The names of the users to test. */ +static const char *users[] = { "user1", "user2", "comment", "many" }; + +static void +check_aliases (int id, const struct aliasent *e) +{ + TEST_VERIFY_EXIT (id >= 0 || id < array_length (users)); + const char *name = users[id]; + TEST_COMPARE_BLOB (e->alias_name, strlen (e->alias_name), + name, strlen (name)); + + switch (id) + { + case 0: + TEST_COMPARE (e->alias_members_len, 1); + TEST_COMPARE_BLOB (e->alias_members[0], strlen (e->alias_members[0]), + "alias1", strlen ("alias1")); + break; + + case 1: + TEST_COMPARE (e->alias_members_len, 2); + TEST_COMPARE_BLOB (e->alias_members[0], strlen (e->alias_members[0]), + "alias1a", strlen ("alias1a")); + TEST_COMPARE_BLOB (e->alias_members[1], strlen (e->alias_members[1]), + "alias2", strlen ("alias2")); + break; + + case 2: + TEST_COMPARE (e->alias_members_len, 2); + TEST_COMPARE_BLOB (e->alias_members[0], strlen (e->alias_members[0]), + "comment1", strlen ("comment1")); + TEST_COMPARE_BLOB (e->alias_members[1], strlen (e->alias_members[1]), + "comment2", strlen ("comment2")); + break; + + case 3: + TEST_COMPARE (e->alias_members_len, many_aliases); + for (int i = 0; i < e->alias_members_len; ++i) + { + char alias[30]; + int len = snprintf (alias, sizeof (alias), "a%d", i); + TEST_VERIFY_EXIT (len > 0); + TEST_COMPARE_BLOB (e->alias_members[i], strlen (e->alias_members[i]), + alias, len); + } + break; + } +} + +static int +do_test (void) +{ + /* Make sure we don't try to load the module in the chroot. */ + if (dlopen (LIBNSS_FILES_SO, RTLD_NOW) == NULL) + FAIL_EXIT1 ("could not load " LIBNSS_FILES_SO ": %s", dlerror ()); + + /* Some of these descriptors will become unavailable if there is a + file descriptor leak. 10 is chosen somewhat arbitrarily. The + array must be longer than the number of files opened by nss_files + at the same time (currently that number is 2). */ + int next_descriptors[10]; + for (size_t i = 0; i < array_length (next_descriptors); ++i) + { + next_descriptors[i] = dup (0); + TEST_VERIFY_EXIT (next_descriptors[i] > 0); + } + for (size_t i = 0; i < array_length (next_descriptors); ++i) + xclose (next_descriptors[i]); + + support_become_root (); + if (!support_can_chroot ()) + return EXIT_UNSUPPORTED; + + __nss_configure_lookup ("aliases", "files"); + + xchroot (chroot_env->path_chroot); + + /* Attempt various buffer sizes. If the operation succeeds, we + expect correct data. */ + for (int id = 0; id < array_length (users); ++id) + { + bool found = false; + for (size_t size = 1; size <= 1000; ++size) + { + void *buffer = malloc (size); + struct aliasent result; + struct aliasent *res; + errno = EINVAL; + int ret = getaliasbyname_r (users[id], &result, buffer, size, &res); + if (ret == 0) + { + if (res != NULL) + { + found = true; + check_aliases (id, res); + } + else + { + support_record_failure (); + printf ("error: failed lookup for user \"%s\", size %zu\n", + users[id], size); + } + } + else if (ret != ERANGE) + { + support_record_failure (); + printf ("error: invalid return code %d (user \%s\", size %zu)\n", + ret, users[id], size); + } + free (buffer); + + /* Make sure that we did not have a file descriptor leak. */ + for (size_t i = 0; i < array_length (next_descriptors); ++i) + { + int new_fd = dup (0); + if (new_fd != next_descriptors[i]) + { + support_record_failure (); + printf ("error: descriptor %d at index %zu leaked" + " (user \"%s\", size %zu)\n", + next_descriptors[i], i, users[id], size); + + /* Close unexpected descriptor, the leak probing + descriptors, and the leaked descriptor + next_descriptors[i]. */ + xclose (new_fd); + for (size_t j = 0; j <= i; ++j) + xclose (next_descriptors[j]); + goto next_size; + } + } + for (size_t i = 0; i < array_length (next_descriptors); ++i) + xclose (next_descriptors[i]); + + next_size: + ; + } + if (!found) + { + support_record_failure (); + printf ("error: user %s not found\n", users[id]); + } + } + + support_chroot_free (chroot_env); + return 0; +} + +#define PREPARE prepare +#include commit b0aa03dfffc20ec7a00db73a3dedecb2130ca6ab Author: DJ Delorie Date: Fri Aug 3 13:43:31 2018 -0400 RISC-V: Fix rounding save/restore bug. * sysdeps/riscv/rvf/math_private.h (libc_feholdexcept_setround_riscv): Fix rounding save-restore bug. Fixes about a hundred off-by-ULP failures in the math testsuite. (cherry picked from commit bf4181878780be9b53e37a3b0fbabc40cdd07649) diff --git a/ChangeLog b/ChangeLog index d900e1eba1..b1cba70bc4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2018-08-03 DJ Delorie + + * sysdeps/riscv/rvf/math_private.h (libc_feholdexcept_setround_riscv): + Fix rounding save-restore bug. + 2018-08-14 Florian Weimer [BZ #23521] diff --git a/sysdeps/riscv/rvf/math_private.h b/sysdeps/riscv/rvf/math_private.h index cdb7858fc8..ca587620cb 100644 --- a/sysdeps/riscv/rvf/math_private.h +++ b/sysdeps/riscv/rvf/math_private.h @@ -72,8 +72,8 @@ libc_fesetround_riscv (int round) static __always_inline void libc_feholdexcept_setround_riscv (fenv_t *envp, int round) { - libc_fesetround_riscv (round); libc_feholdexcept_riscv (envp); + libc_fesetround_riscv (round); } #define libc_feholdexcept_setround libc_feholdexcept_setround_riscv commit 66fdfd57fe20616dc3333b0eb4f5a411e85fd8aa Author: DJ Delorie Date: Fri Aug 3 13:52:01 2018 -0400 Regen RISC-V rvd ULPs * sysdeps/riscv/rv64/rvd/libm-test-ulps: Update. Note: I regen'd these from scratch, but I'm only committing the increases, as I only tested on hardware. There were a few 2->1 decreases that I omitted, possibly "for now". (cherry picked from commit bb17621ab89b2135c4d8d0d250b2aab5aa3e36c4) diff --git a/ChangeLog b/ChangeLog index b1cba70bc4..e296da9699 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,8 @@ * sysdeps/riscv/rvf/math_private.h (libc_feholdexcept_setround_riscv): Fix rounding save-restore bug. + * sysdeps/riscv/rv64/rvd/libm-test-ulps: Update. + 2018-08-14 Florian Weimer [BZ #23521] diff --git a/sysdeps/riscv/rv64/rvd/libm-test-ulps b/sysdeps/riscv/rv64/rvd/libm-test-ulps index f8feadcd0d..61be2df60d 100644 --- a/sysdeps/riscv/rv64/rvd/libm-test-ulps +++ b/sysdeps/riscv/rv64/rvd/libm-test-ulps @@ -1006,6 +1006,8 @@ ildouble: 2 ldouble: 2 Function: "cos": +double: 1 +idouble: 1 ildouble: 1 ldouble: 1 @@ -1348,9 +1350,9 @@ ildouble: 4 ldouble: 4 Function: Imaginary part of "ctan_towardzero": -double: 1 +double: 2 float: 2 -idouble: 1 +idouble: 2 ifloat: 2 ildouble: 5 ldouble: 5 @@ -1898,10 +1900,12 @@ ldouble: 2 Function: "log_upward": double: 1 idouble: 1 -ildouble: 1 -ldouble: 1 +ildouble: 2 +ldouble: 2 Function: "pow": +double: 1 +idouble: 1 ildouble: 2 ldouble: 2 @@ -1930,6 +1934,8 @@ ildouble: 2 ldouble: 2 Function: "sin": +double: 1 +idouble: 1 ildouble: 1 ldouble: 1 @@ -1952,6 +1958,8 @@ ildouble: 3 ldouble: 3 Function: "sincos": +double: 1 +idouble: 1 ildouble: 1 ldouble: 1 commit c87b5bab241c8d1e7709061c6b63f1b435ee3ac9 Author: DJ Delorie Date: Wed Aug 22 18:54:51 2018 +0200 Improve ChangeLog message. (cherry picked from commit e5721f45f6377c27ccb2572001dc98f7a2e6a146) diff --git a/ChangeLog b/ChangeLog index e296da9699..b9e732a192 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,7 +1,7 @@ 2018-08-03 DJ Delorie * sysdeps/riscv/rvf/math_private.h (libc_feholdexcept_setround_riscv): - Fix rounding save-restore bug. + Move libc_fesetround_riscv after libc_feholdexcept_riscv. * sysdeps/riscv/rv64/rvd/libm-test-ulps: Update. commit aa8a3e4cdef20c50cb20f008864fff05cbfbdf29 Author: Martin Kuchta Date: Mon Aug 27 18:54:46 2018 +0200 pthread_cond_broadcast: Fix waiters-after-spinning case [BZ #23538] (cherry picked from commit 99ea93ca31795469d2a1f1570f17a5c39c2eb7e2) diff --git a/ChangeLog b/ChangeLog index b9e732a192..ef83777833 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2018-08-27 Martin Kuchta + Torvald Riegel + + [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-08-03 DJ Delorie * sysdeps/riscv/rvf/math_private.h (libc_feholdexcept_setround_riscv): diff --git a/NEWS b/NEWS index 873cf8f64f..3073712cba 100644 --- a/NEWS +++ b/NEWS @@ -11,6 +11,7 @@ The following bugs are resolved with this release: [23497] readdir64@GLIBC_2.1 cannot parse the kernel directory stream [23521] nss_files aliases database file stream leak + [23538] pthread_cond_broadcast: Fix waiters-after-spinning case Version 2.28 diff --git a/nptl/pthread_cond_common.c b/nptl/pthread_cond_common.c index 8e425eb01e..479e54febb 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); commit 58559f14437d2aa71753a29fed435efa06aa4576 Author: Paul Eggert Date: Tue Aug 28 21:54:28 2018 +0200 regex: fix uninitialized memory access I introduced this bug into gnulib in commit 8335a4d6c7b4448cd0bcb6d0bebf1d456bcfdb17 dated 2006-04-10; eventually it was merged into glibc. The bug was found by project-repo and reported here: https://lists.gnu.org/r/sed-devel/2018-08/msg00017.html Diagnosis and draft fix reported by Assaf Gordon here: https://lists.gnu.org/r/bug-gnulib/2018-08/msg00071.html https://lists.gnu.org/r/bug-gnulib/2018-08/msg00142.html * posix/regex_internal.c (build_wcs_upper_buffer): Fix bug when mbrtowc returns 0. (cherry picked from commit bc680b336971305cb39896b30d72dc7101b62242) diff --git a/ChangeLog b/ChangeLog index ef83777833..8625e6c9f5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +2018-08-25 Paul Eggert + + [BZ #23578] + regex: fix uninitialized memory access + I introduced this bug into gnulib in commit + 8335a4d6c7b4448cd0bcb6d0bebf1d456bcfdb17 dated 2006-04-10; + eventually it was merged into glibc. The bug was found by + project-repo and reported here: + https://lists.gnu.org/r/sed-devel/2018-08/msg00017.html + Diagnosis and draft fix reported by Assaf Gordon here: + https://lists.gnu.org/r/bug-gnulib/2018-08/msg00071.html + https://lists.gnu.org/r/bug-gnulib/2018-08/msg00142.html + * posix/regex_internal.c (build_wcs_upper_buffer): + Fix bug when mbrtowc returns 0. + 2018-08-27 Martin Kuchta Torvald Riegel diff --git a/NEWS b/NEWS index 3073712cba..2855ffde58 100644 --- a/NEWS +++ b/NEWS @@ -12,6 +12,7 @@ The following bugs are resolved with this release: [23497] readdir64@GLIBC_2.1 cannot parse the kernel directory stream [23521] nss_files aliases database file stream leak [23538] pthread_cond_broadcast: Fix waiters-after-spinning case + [23578] regex: Fix memory overread in re_compile_pattern Version 2.28 diff --git a/posix/regex_internal.c b/posix/regex_internal.c index 7f0083b918..b10588f1cc 100644 --- a/posix/regex_internal.c +++ b/posix/regex_internal.c @@ -317,7 +317,7 @@ build_wcs_upper_buffer (re_string_t *pstr) mbclen = __mbrtowc (&wc, ((const char *) pstr->raw_mbs + pstr->raw_mbs_idx + byte_idx), remain_len, &pstr->cur_state); - if (BE (mbclen < (size_t) -2, 1)) + if (BE (0 < mbclen && mbclen < (size_t) -2, 1)) { wchar_t wcu = __towupper (wc); if (wcu != wc) @@ -386,7 +386,7 @@ build_wcs_upper_buffer (re_string_t *pstr) else p = (const char *) pstr->raw_mbs + pstr->raw_mbs_idx + src_idx; mbclen = __mbrtowc (&wc, p, remain_len, &pstr->cur_state); - if (BE (mbclen < (size_t) -2, 1)) + if (BE (0 < mbclen && mbclen < (size_t) -2, 1)) { wchar_t wcu = __towupper (wc); if (wcu != wc) commit 0b79004569e5ce1669136b8c41564c3809730f15 Author: Florian Weimer Date: Tue Aug 28 12:57:46 2018 +0200 regex: Add test tst-regcomp-truncated [BZ #23578] (cherry picked from commit 761404b74d9853ce1608195e24f25b78a910591a) diff --git a/ChangeLog b/ChangeLog index 8625e6c9f5..94b8718365 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2018-08-28 Florian Weimer + + [BZ #23578] + * posix/tst-regcomp-truncated.c: New file. + * posix/Makefile (tests): Add it. + (tst-regcomp-truncated.out): Depend on generated locales. + 2018-08-25 Paul Eggert [BZ #23578] diff --git a/posix/Makefile b/posix/Makefile index 00c62841a2..83162123f9 100644 --- a/posix/Makefile +++ b/posix/Makefile @@ -96,7 +96,7 @@ tests := test-errno tstgetopt testfnm runtests runptests \ tst-posix_fadvise tst-posix_fadvise64 \ tst-sysconf-empty-chroot tst-glob_symlinks tst-fexecve \ tst-glob-tilde test-ssize-max tst-spawn4 bug-regex37 \ - bug-regex38 + bug-regex38 tst-regcomp-truncated tests-internal := bug-regex5 bug-regex20 bug-regex33 \ tst-rfc3484 tst-rfc3484-2 tst-rfc3484-3 \ tst-glob_lstat_compat tst-spawn4-compat @@ -194,6 +194,7 @@ $(objpfx)tst-regex2.out: $(gen-locales) $(objpfx)tst-regexloc.out: $(gen-locales) $(objpfx)tst-rxspencer.out: $(gen-locales) $(objpfx)tst-rxspencer-no-utf8.out: $(gen-locales) +$(objpfx)tst-regcomp-truncated.out: $(gen-locales) endif # If we will use the generic uname implementation, we must figure out what diff --git a/posix/tst-regcomp-truncated.c b/posix/tst-regcomp-truncated.c new file mode 100644 index 0000000000..a4a1581bbc --- /dev/null +++ b/posix/tst-regcomp-truncated.c @@ -0,0 +1,191 @@ +/* Test compilation of truncated regular expressions. + 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 + . */ + +/* This test constructs various patterns in an attempt to trigger + over-reading the regular expression compiler, such as bug + 23578. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Locales to test. */ +static const char locales[][17] = + { + "C", + "en_US.UTF-8", + "de_DE.ISO-8859-1", + }; + +/* Syntax options. Will be combined with other flags. */ +static const reg_syntax_t syntaxes[] = + { + RE_SYNTAX_EMACS, + RE_SYNTAX_AWK, + RE_SYNTAX_GNU_AWK, + RE_SYNTAX_POSIX_AWK, + RE_SYNTAX_GREP, + RE_SYNTAX_EGREP, + RE_SYNTAX_POSIX_EGREP, + RE_SYNTAX_POSIX_BASIC, + RE_SYNTAX_POSIX_EXTENDED, + RE_SYNTAX_POSIX_MINIMAL_EXTENDED, + }; + +/* Trailing characters placed after the initial character. */ +static const char trailing_strings[][4] = + { + "", + "[", + "\\", + "[\\", + "(", + "(\\", + "\\(", + }; + +static int +do_test (void) +{ + /* Staging buffer for the constructed regular expression. */ + char buffer[16]; + + /* Allocation used to detect over-reading by the regular expression + compiler. */ + struct support_next_to_fault ntf + = support_next_to_fault_allocate (sizeof (buffer)); + + /* Arbitrary Unicode codepoint at which we stop generating + characters. We do not probe the whole range because that would + take too long due to combinatorical exploision as the result of + combination with other flags. */ + static const wchar_t last_character = 0xfff; + + for (size_t locale_idx = 0; locale_idx < array_length (locales); + ++ locale_idx) + { + if (setlocale (LC_ALL, locales[locale_idx]) == NULL) + { + support_record_failure (); + printf ("error: setlocale (\"%s\"): %m", locales[locale_idx]); + continue; + } + if (test_verbose > 0) + printf ("info: testing locale \"%s\"\n", locales[locale_idx]); + + for (wchar_t wc = 0; wc <= last_character; ++wc) + { + char *after_wc; + if (wc == 0) + { + /* wcrtomb treats L'\0' in a special way. */ + *buffer = '\0'; + after_wc = &buffer[1]; + } + else + { + mbstate_t ps = { }; + size_t ret = wcrtomb (buffer, wc, &ps); + if (ret == (size_t) -1) + { + /* EILSEQ means that the target character set + cannot encode the character. */ + if (errno != EILSEQ) + { + support_record_failure (); + printf ("error: wcrtomb (0x%x) failed: %m\n", + (unsigned) wc); + } + continue; + } + TEST_VERIFY_EXIT (ret != 0); + after_wc = &buffer[ret]; + } + + for (size_t trailing_idx = 0; + trailing_idx < array_length (trailing_strings); + ++trailing_idx) + { + char *after_trailing + = stpcpy (after_wc, trailing_strings[trailing_idx]); + + for (int do_nul = 0; do_nul < 2; ++do_nul) + { + char *after_nul; + if (do_nul) + { + *after_trailing = '\0'; + after_nul = &after_trailing[1]; + } + else + after_nul = after_trailing; + + size_t length = after_nul - buffer; + + /* Make sure that the faulting region starts + after the used portion of the buffer. */ + char *ntf_start = ntf.buffer + sizeof (buffer) - length; + memcpy (ntf_start, buffer, length); + + for (const reg_syntax_t *psyntax = syntaxes; + psyntax < array_end (syntaxes); ++psyntax) + for (int do_icase = 0; do_icase < 2; ++do_icase) + { + re_syntax_options = *psyntax; + if (do_icase) + re_syntax_options |= RE_ICASE; + + regex_t reg; + memset (®, 0, sizeof (reg)); + const char *msg = re_compile_pattern + (ntf_start, length, ®); + if (msg != NULL) + { + if (test_verbose > 0) + { + char *quoted = support_quote_blob + (buffer, length); + printf ("info: compilation failed for pattern" + " \"%s\", syntax 0x%lx: %s\n", + quoted, re_syntax_options, msg); + free (quoted); + } + } + else + regfree (®); + } + } + } + } + } + + support_next_to_fault_free (&ntf); + + return 0; +} + +#include commit 1fe2b9ca8a50aaa789d72944b5a91f1d35337adc Author: Stefan Liebler Date: Thu Sep 6 14:27:03 2018 +0200 Fix segfault in maybe_script_execute. If glibc is built with gcc 8 and -march=z900, the testcase posix/tst-spawn4-compat crashes with a segfault. In function maybe_script_execute, the new_argv array is dynamically initialized on stack with (argc + 1) elements. The function wants to add _PATH_BSHELL as the first argument and writes out of bounds of new_argv. There is an off-by-one because maybe_script_execute fails to count the terminating NULL when sizing new_argv. ChangeLog: * sysdeps/unix/sysv/linux/spawni.c (maybe_script_execute): Increment size of new_argv by one. (cherry picked from commit 28669f86f6780a18daca264f32d66b1428c9c6f1) diff --git a/ChangeLog b/ChangeLog index 94b8718365..d9e7e6f1d8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2018-09-06 Stefan Liebler + + * sysdeps/unix/sysv/linux/spawni.c (maybe_script_execute): + Increment size of new_argv by one. + 2018-08-28 Florian Weimer [BZ #23578] diff --git a/sysdeps/unix/sysv/linux/spawni.c b/sysdeps/unix/sysv/linux/spawni.c index cf0213ece5..85239cedbf 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) commit e7d22db29cfdd2f1fb97a70a76fa53d151569945 Author: Mingli Yu Date: Thu Sep 20 12:41:13 2018 +0200 Linux gethostid: Check for NULL value from gethostbyname_r [BZ #23679] A NULL value can happen with certain gethostbyname_r failures. (cherry picked from commit 1214ba06e6771acb953a190091b0f6055c64fd25) diff --git a/ChangeLog b/ChangeLog index d9e7e6f1d8..fc1ea1e418 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2018-09-20 Mingli Yu + + * sysdeps/unix/sysv/linux/gethostid.c (gethostid): Check for NULL + value from gethostbyname_r. + 2018-09-06 Stefan Liebler * sysdeps/unix/sysv/linux/spawni.c (maybe_script_execute): diff --git a/NEWS b/NEWS index 2855ffde58..502e0c19f5 100644 --- a/NEWS +++ b/NEWS @@ -13,6 +13,7 @@ The following bugs are resolved with this release: [23521] nss_files aliases database file stream leak [23538] pthread_cond_broadcast: Fix waiters-after-spinning case [23578] regex: Fix memory overread in re_compile_pattern + [23679] gethostid: Missing NULL check for gethostbyname_r result Version 2.28 diff --git a/sysdeps/unix/sysv/linux/gethostid.c b/sysdeps/unix/sysv/linux/gethostid.c index 2e20f034dc..ee0190e7f9 100644 --- a/sysdeps/unix/sysv/linux/gethostid.c +++ b/sysdeps/unix/sysv/linux/gethostid.c @@ -102,12 +102,12 @@ gethostid (void) { int ret = __gethostbyname_r (hostname, &hostbuf, tmpbuf.data, tmpbuf.length, &hp, &herr); - if (ret == 0) + if (ret == 0 && hp != NULL) break; else { /* Enlarge the buffer on ERANGE. */ - if (herr == NETDB_INTERNAL && errno == ERANGE) + if (ret != 0 && herr == NETDB_INTERNAL && errno == ERANGE) { if (!scratch_buffer_grow (&tmpbuf)) return 0; commit 307d04334d516bb180f484a2b283f97310bfee66 Author: Florian Weimer Date: Thu Sep 20 12:03:01 2018 +0200 misc: New test misc/tst-gethostid The empty /etc/hosts file used to trigger bug 23679. (cherry picked from commit db9a8ad4ff3fc58e3773a9a4d0cabe3c1bc9c94c) diff --git a/ChangeLog b/ChangeLog index fc1ea1e418..b380048e1e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2018-09-20 Florian Weimer + + * misc/tst-gethostid.c: New file. + * misc/Makefile [$(build-shared)] (tests): Add tst-gethostid. + (tst-gethostid): Link with -ldl. + 2018-09-20 Mingli Yu * sysdeps/unix/sysv/linux/gethostid.c (gethostid): Check for NULL diff --git a/misc/Makefile b/misc/Makefile index b7be2bc19a..c9f81515ac 100644 --- a/misc/Makefile +++ b/misc/Makefile @@ -86,6 +86,11 @@ tests := tst-dirname tst-tsearch tst-fdset tst-efgcvt tst-mntent tst-hsearch \ tst-preadvwritev tst-preadvwritev64 tst-makedev tst-empty \ tst-preadvwritev2 tst-preadvwritev64v2 +# Tests which need libdl. +ifeq (yes,$(build-shared)) +tests += tst-gethostid +endif + tests-internal := tst-atomic tst-atomic-long tst-allocate_once tests-static := tst-empty @@ -145,3 +150,5 @@ tst-allocate_once-ENV = MALLOC_TRACE=$(objpfx)tst-allocate_once.mtrace $(objpfx)tst-allocate_once-mem.out: $(objpfx)tst-allocate_once.out $(common-objpfx)malloc/mtrace $(objpfx)tst-allocate_once.mtrace > $@; \ $(evaluate-test) + +$(objpfx)tst-gethostid: $(libdl) diff --git a/misc/tst-gethostid.c b/misc/tst-gethostid.c new file mode 100644 index 0000000000..1490aaf3f5 --- /dev/null +++ b/misc/tst-gethostid.c @@ -0,0 +1,108 @@ +/* Basic test for gethostid. + 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 + . */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Initial test is run outside a chroot, to increase the likelihood of + success. */ +static void +outside_chroot (void *closure) +{ + long id = gethostid (); + printf ("info: host ID outside chroot: 0x%lx\n", id); +} + +/* The same, but this time perform a chroot operation. */ +static void +in_chroot (void *closure) +{ + const char *chroot_path = closure; + xchroot (chroot_path); + long id = gethostid (); + printf ("info: host ID in chroot: 0x%lx\n", id); +} + +static int +do_test (void) +{ + support_isolate_in_subprocess (outside_chroot, NULL); + + /* Now run the test inside a chroot. */ + support_become_root (); + if (!support_can_chroot ()) + /* Cannot perform further tests. */ + return 0; + + /* Only use nss_files. */ + __nss_configure_lookup ("hosts", "files"); + + /* Load the DSO outside of the chroot. */ + xdlopen (LIBNSS_FILES_SO, RTLD_LAZY); + + char *chroot_dir = support_create_temp_directory ("tst-gethostid-"); + support_isolate_in_subprocess (in_chroot, chroot_dir); + + /* Tests with /etc/hosts in the chroot. */ + { + char *path = xasprintf ("%s/etc", chroot_dir); + add_temp_file (path); + xmkdir (path, 0777); + free (path); + path = xasprintf ("%s/etc/hosts", chroot_dir); + add_temp_file (path); + + FILE *fp = xfopen (path, "w"); + xfclose (fp); + printf ("info: chroot test with an empty /etc/hosts file\n"); + support_isolate_in_subprocess (in_chroot, chroot_dir); + + char hostname[1024]; + int ret = gethostname (hostname, sizeof (hostname)); + if (ret < 0) + printf ("warning: invalid result from gethostname: %d\n", ret); + else if (strlen (hostname) == 0) + puts ("warning: gethostname returned empty string"); + else + { + printf ("info: chroot test with IPv6 address in /etc/hosts for: %s\n", + hostname); + fp = xfopen (path, "w"); + /* Use an IPv6 address to induce another lookup failure. */ + fprintf (fp, "2001:db8::1 %s\n", hostname); + xfclose (fp); + support_isolate_in_subprocess (in_chroot, chroot_dir); + } + free (path); + } + free (chroot_dir); + + return 0; +} + +#include commit a55e109709af55e6ed67d3f9536cac5d929c982e Author: Carlos O'Donell Date: Wed Sep 5 01:16:42 2018 -0400 Fix tst-setcontext9 for optimized small stacks. If the compiler reduces the stack usage in function f1 before calling into function f2, then when we swapcontext back to f1 and continue execution we may overwrite registers that were spilled to the stack while f2 was executing. Later when we return to f2 the corrupt registers will be reloaded from the stack and the test will crash. This was most commonly observed on i686 with __x86.get_pc_thunk.dx and needing to save and restore $edx. Overall i686 has few registers and the spilling to the stack is bound to happen, therefore the solution to making this test robust is to split function f1 into two parts f1a and f1b, and allocate f1b it's own stack such that subsequent execution does not overwrite the stack in use by function f2. Tested on i686 and x86_64. Signed-off-by: Carlos O'Donell (cherry picked from commit 791b350dc725545e3f9b5db0f97ebdbc60c9735f) diff --git a/ChangeLog b/ChangeLog index b380048e1e..bda963483f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2018-09-19 Carlos O'Donell + + * stdlib/tst-setcontext9.c (f1): Rename to... + (f1a): ... this. + (f1b): New function implementing lower half of f1 in alternate stack. + 2018-09-20 Florian Weimer * misc/tst-gethostid.c: New file. diff --git a/stdlib/tst-setcontext9.c b/stdlib/tst-setcontext9.c index 4636ce9030..db8355766c 100644 --- a/stdlib/tst-setcontext9.c +++ b/stdlib/tst-setcontext9.c @@ -41,26 +41,55 @@ f2 (void) } static void -f1 (void) +f1b (void) { - puts ("start f1"); - if (getcontext (&ctx[2]) != 0) - { - printf ("%s: getcontext: %m\n", __FUNCTION__); - exit (EXIT_FAILURE); - } if (done) { - puts ("set context in f1"); + puts ("set context in f1b"); if (setcontext (&ctx[3]) != 0) { printf ("%s: setcontext: %m\n", __FUNCTION__); exit (EXIT_FAILURE); } } + exit (EXIT_FAILURE); +} + +static void +f1a (void) +{ + char st2[32768]; + puts ("start f1a"); + if (getcontext (&ctx[2]) != 0) + { + printf ("%s: getcontext: %m\n", __FUNCTION__); + exit (EXIT_FAILURE); + } + ctx[2].uc_stack.ss_sp = st2; + ctx[2].uc_stack.ss_size = sizeof st2; + ctx[2].uc_link = &ctx[0]; + makecontext (&ctx[2], (void (*) (void)) f1b, 0); f2 (); } +/* The execution path through the test looks like this: + do_test (call) + -> "making contexts" + -> "swap contexts" + f1a (via swapcontext to ctx[1], with alternate stack) + -> "start f1a" + f2 (call) + -> "swap contexts in f2" + f1b (via swapcontext to ctx[2], with alternate stack) + -> "set context in f1b" + do_test (via setcontext to ctx[3], main stack) + -> "setcontext" + f2 (via setcontext to ctx[4], with alternate stack) + -> "end f2" + + We must use an alternate stack for f1b, because if we don't then the + result of executing an earlier caller may overwrite registers + spilled to the stack in f2. */ static int do_test (void) { @@ -79,7 +108,7 @@ do_test (void) ctx[1].uc_stack.ss_sp = st1; ctx[1].uc_stack.ss_size = sizeof st1; ctx[1].uc_link = &ctx[0]; - makecontext (&ctx[1], (void (*) (void)) f1, 0); + makecontext (&ctx[1], (void (*) (void)) f1a, 0); puts ("swap contexts"); if (swapcontext (&ctx[3], &ctx[1]) != 0) { commit 0ef2f4400c06927af34c515555f68840a70ba409 Author: Wilco Dijkstra Date: Wed Sep 19 16:50:18 2018 +0100 Fix strstr bug with huge needles (bug 23637) The generic strstr in GLIBC 2.28 fails to match huge needles. The optimized AVAILABLE macro reads ahead a large fixed amount to reduce the overhead of repeatedly checking for the end of the string. However if the needle length is larger than this, two_way_long_needle may confuse this as meaning the end of the string and return NULL. This is fixed by adding the needle length to the amount to read ahead. [BZ #23637] * string/test-strstr.c (pr23637): New function. (test_main): Add tests with longer needles. * string/strcasestr.c (AVAILABLE): Fix readahead distance. * string/strstr.c (AVAILABLE): Likewise. (cherry picked from commit 83a552b0bb9fc2a5e80a0ab3723c0a80ce1db9f2) diff --git a/ChangeLog b/ChangeLog index bda963483f..a111f0131b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2018-09-19 Wilco Dijkstra + + [BZ #23637] + * string/test-strstr.c (pr23637): New function. + (test_main): Add tests with longer needles. + * string/strcasestr.c (AVAILABLE): Fix readahead distance. + * string/strstr.c (AVAILABLE): Likewise. + 2018-09-19 Carlos O'Donell * stdlib/tst-setcontext9.c (f1): Rename to... diff --git a/string/strcasestr.c b/string/strcasestr.c index 5909fe3cdb..421764bd1b 100644 --- a/string/strcasestr.c +++ b/string/strcasestr.c @@ -37,8 +37,9 @@ /* Two-Way algorithm. */ #define RETURN_TYPE char * #define AVAILABLE(h, h_l, j, n_l) \ - (((j) + (n_l) <= (h_l)) || ((h_l) += __strnlen ((void*)((h) + (h_l)), 512), \ - (j) + (n_l) <= (h_l))) + (((j) + (n_l) <= (h_l)) \ + || ((h_l) += __strnlen ((void*)((h) + (h_l)), (n_l) + 512), \ + (j) + (n_l) <= (h_l))) #define CHECK_EOL (1) #define RET0_IF_0(a) if (!a) goto ret0 #define CANON_ELEMENT(c) TOLOWER (c) diff --git a/string/strstr.c b/string/strstr.c index 265e9f310c..79ebcc7532 100644 --- a/string/strstr.c +++ b/string/strstr.c @@ -33,8 +33,9 @@ #define RETURN_TYPE char * #define AVAILABLE(h, h_l, j, n_l) \ - (((j) + (n_l) <= (h_l)) || ((h_l) += __strnlen ((void*)((h) + (h_l)), 512), \ - (j) + (n_l) <= (h_l))) + (((j) + (n_l) <= (h_l)) \ + || ((h_l) += __strnlen ((void*)((h) + (h_l)), (n_l) + 512), \ + (j) + (n_l) <= (h_l))) #define CHECK_EOL (1) #define RET0_IF_0(a) if (!a) goto ret0 #define FASTSEARCH(S,C,N) (void*) strchr ((void*)(S), (C)) diff --git a/string/test-strstr.c b/string/test-strstr.c index 8d99716ff3..5861b01b73 100644 --- a/string/test-strstr.c +++ b/string/test-strstr.c @@ -151,6 +151,32 @@ check2 (void) } } +#define N 1024 + +static void +pr23637 (void) +{ + char *h = (char*) buf1; + char *n = (char*) buf2; + + for (int i = 0; i < N; i++) + { + n[i] = 'x'; + h[i] = ' '; + h[i + N] = 'x'; + } + + n[N] = '\0'; + h[N * 2] = '\0'; + + /* Ensure we don't match at the first 'x'. */ + h[0] = 'x'; + + char *exp_result = stupid_strstr (h, n); + FOR_EACH_IMPL (impl, 0) + check_result (impl, h, n, exp_result); +} + static int test_main (void) { @@ -158,6 +184,7 @@ test_main (void) check1 (); check2 (); + pr23637 (); printf ("%23s", ""); FOR_EACH_IMPL (impl, 0) @@ -202,6 +229,9 @@ test_main (void) do_test (15, 9, hlen, klen, 1); do_test (15, 15, hlen, klen, 0); do_test (15, 15, hlen, klen, 1); + + do_test (15, 15, hlen + klen * 4, klen * 4, 0); + do_test (15, 15, hlen + klen * 4, klen * 4, 1); } do_test (0, 0, page_size - 1, 16, 0); commit 2339d6a55eb7a7e040ae888e906adc49eeb59eab Author: H.J. Lu Date: Wed Sep 12 08:40:59 2018 -0700 i386: Use ENTRY and END in start.S [BZ #23606] Wrapping the _start function with ENTRY and END to insert ENDBR32 at function entry when CET is enabled. Since _start now includes CFI, without "cfi_undefined (eip)", unwinder may not terminate at _start and we will get Program received signal SIGSEGV, Segmentation fault. 0xf7dc661e in ?? () from /lib/libgcc_s.so.1 Missing separate debuginfos, use: dnf debuginfo-install libgcc-8.2.1-3.0.fc28.i686 (gdb) bt #0 0xf7dc661e in ?? () from /lib/libgcc_s.so.1 #1 0xf7dc7c18 in _Unwind_Backtrace () from /lib/libgcc_s.so.1 #2 0xf7f0d809 in __GI___backtrace (array=array@entry=0xffffc7d0, size=size@entry=20) at ../sysdeps/i386/backtrace.c:127 #3 0x08049254 in compare (p1=p1@entry=0xffffcad0, p2=p2@entry=0xffffcad4) at backtrace-tst.c:12 #4 0xf7e2a28c in msort_with_tmp (p=p@entry=0xffffca5c, b=b@entry=0xffffcad0, n=n@entry=2) at msort.c:65 #5 0xf7e29f64 in msort_with_tmp (n=2, b=0xffffcad0, p=0xffffca5c) at msort.c:53 #6 msort_with_tmp (p=p@entry=0xffffca5c, b=b@entry=0xffffcad0, n=n@entry=5) at msort.c:53 #7 0xf7e29f64 in msort_with_tmp (n=5, b=0xffffcad0, p=0xffffca5c) at msort.c:53 #8 msort_with_tmp (p=p@entry=0xffffca5c, b=b@entry=0xffffcad0, n=n@entry=10) at msort.c:53 #9 0xf7e29f64 in msort_with_tmp (n=10, b=0xffffcad0, p=0xffffca5c) at msort.c:53 #10 msort_with_tmp (p=p@entry=0xffffca5c, b=b@entry=0xffffcad0, n=n@entry=20) at msort.c:53 #11 0xf7e2a5b6 in msort_with_tmp (n=20, b=0xffffcad0, p=0xffffca5c) at msort.c:297 #12 __GI___qsort_r (b=b@entry=0xffffcad0, n=n@entry=20, s=s@entry=4, cmp=cmp@entry=0x8049230 , arg=arg@entry=0x0) at msort.c:297 #13 0xf7e2a84d in __GI_qsort (b=b@entry=0xffffcad0, n=n@entry=20, s=s@entry=4, cmp=cmp@entry=0x8049230 ) at msort.c:308 #14 0x080490f6 in main (argc=2, argv=0xffffcbd4) at backtrace-tst.c:39 FAIL: debug/backtrace-tst [BZ #23606] * sysdeps/i386/start.S: Include (_start): Use ENTRY/END to insert ENDBR32 at entry when CET is enabled. Add cfi_undefined (eip). Signed-off-by: H.J. Lu (cherry picked from commit 5a274db4ea363d6b0b92933f085a92daaf1be2f2) diff --git a/ChangeLog b/ChangeLog index a111f0131b..84503e3a0c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2018-09-21 H.J. Lu + Xuepeng Guo + + [BZ #23606] + * sysdeps/i386/start.S: Include + (_start): Use ENTRY/END to insert ENDBR32 at entry when CET is + enabled. Add cfi_undefined (eip). + 2018-09-19 Wilco Dijkstra [BZ #23637] diff --git a/NEWS b/NEWS index 502e0c19f5..d1f1dd4b22 100644 --- a/NEWS +++ b/NEWS @@ -13,6 +13,7 @@ The following bugs are resolved with this release: [23521] nss_files aliases database file stream leak [23538] pthread_cond_broadcast: Fix waiters-after-spinning case [23578] regex: Fix memory overread in re_compile_pattern + [23606] Missing ENDBR32 in sysdeps/i386/start.S [23679] gethostid: Missing NULL check for gethostbyname_r result diff --git a/sysdeps/i386/start.S b/sysdeps/i386/start.S index 91035fa83f..e35e9bd31b 100644 --- a/sysdeps/i386/start.S +++ b/sysdeps/i386/start.S @@ -52,10 +52,11 @@ NULL */ - .text - .globl _start - .type _start,@function -_start: +#include + +ENTRY (_start) + /* Clearing frame pointer is insufficient, use CFI. */ + cfi_undefined (eip) /* Clear the frame pointer. The ABI suggests this be done, to mark the outermost frame obviously. */ xorl %ebp, %ebp @@ -131,6 +132,7 @@ _start: 1: movl (%esp), %ebx ret #endif +END (_start) /* To fulfill the System V/i386 ABI we need this symbol. Yuck, it's so meaningless since we don't support machines < 80386. */ commit 3a67c72c1512f778304a5644dea2fcf5bdece274 Author: Andreas Schwab Date: Thu Sep 27 12:37:06 2018 +0200 Fix stack overflow in tst-setcontext9 (bug 23717) The function f1a, executed on a stack of size 32k, allocates an object of size 32k on the stack. Make the stack variables static to reduce excessive stack usage. (cherry picked from commit f841c97e515a1673485a2b12b3c280073d737890) diff --git a/ChangeLog b/ChangeLog index 84503e3a0c..4fbb9e2ad8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2018-09-27 Andreas Schwab + + [BZ #23717] + * stdlib/tst-setcontext9.c (f1a): Make st2 static. + (do_test): Make st1 static. + 2018-09-21 H.J. Lu Xuepeng Guo diff --git a/NEWS b/NEWS index d1f1dd4b22..bc568bcec0 100644 --- a/NEWS +++ b/NEWS @@ -15,6 +15,7 @@ The following bugs are resolved with this release: [23578] regex: Fix memory overread in re_compile_pattern [23606] Missing ENDBR32 in sysdeps/i386/start.S [23679] gethostid: Missing NULL check for gethostbyname_r result + [23717] Fix stack overflow in stdlib/tst-setcontext9 Version 2.28 diff --git a/stdlib/tst-setcontext9.c b/stdlib/tst-setcontext9.c index db8355766c..009928235d 100644 --- a/stdlib/tst-setcontext9.c +++ b/stdlib/tst-setcontext9.c @@ -58,7 +58,7 @@ f1b (void) static void f1a (void) { - char st2[32768]; + static char st2[32768]; puts ("start f1a"); if (getcontext (&ctx[2]) != 0) { @@ -93,7 +93,7 @@ f1a (void) static int do_test (void) { - char st1[32768]; + static char st1[32768]; puts ("making contexts"); if (getcontext (&ctx[0]) != 0) { commit 044c96f0d5595aeb0bb4e79355081c5a7f4faca5 Author: Adhemerval Zanella Date: Wed Aug 29 16:36:44 2018 -0300 Fix misreported errno on preadv2/pwritev2 (BZ#23579) The fallback code of Linux wrapper for preadv2/pwritev2 executes regardless of the errno code for preadv2, instead of the case where the syscall is not supported. This fixes it by calling the fallback code iff errno is ENOSYS. The patch also adds tests for both invalid file descriptor and invalid iov_len and vector count. The only discrepancy between preadv2 and fallback code regarding error reporting is when an invalid flags are used. The fallback code bails out earlier with ENOTSUP instead of EINVAL/EBADF when the syscall is used. Checked on x86_64-linux-gnu on a 4.4.0 and 4.15.0 kernel. [BZ #23579] * misc/tst-preadvwritev2-common.c (do_test_with_invalid_fd): New test. * misc/tst-preadvwritev2.c, misc/tst-preadvwritev64v2.c (do_test): Call do_test_with_invalid_fd. * 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. (cherry picked from commit 7a16bdbb9ff4122af0a28dc20996c95352011fdd) diff --git a/ChangeLog b/ChangeLog index 4fbb9e2ad8..11a9b8d98e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +2018-09-28 Adhemerval Zanella + + [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-27 Andreas Schwab [BZ #23717] diff --git a/NEWS b/NEWS index bc568bcec0..fd14941128 100644 --- a/NEWS +++ b/NEWS @@ -13,6 +13,7 @@ The following bugs are resolved with this release: [23521] nss_files aliases database file stream leak [23538] pthread_cond_broadcast: Fix waiters-after-spinning case [23578] regex: Fix memory overread in re_compile_pattern + [23579] libc: Errors misreported in preadv2 [23606] Missing ENDBR32 in sysdeps/i386/start.S [23679] gethostid: Missing NULL check for gethostbyname_r result [23717] Fix stack overflow in stdlib/tst-setcontext9 diff --git a/misc/tst-preadvwritev2-common.c b/misc/tst-preadvwritev2-common.c index f889a21544..50b9da3fea 100644 --- a/misc/tst-preadvwritev2-common.c +++ b/misc/tst-preadvwritev2-common.c @@ -19,9 +19,6 @@ #include #include -static void -do_test_with_invalid_flags (void) -{ #ifndef RWF_HIPRI # define RWF_HIPRI 0 #endif @@ -39,6 +36,68 @@ do_test_with_invalid_flags (void) #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) +{ /* Set the next bit from the mask of all supported flags. */ int invalid_flag = RWF_SUPPORTED != 0 ? __builtin_clz (RWF_SUPPORTED) : 2; invalid_flag = 0x1 << ((sizeof (int) * CHAR_BIT) - invalid_flag); diff --git a/misc/tst-preadvwritev2.c b/misc/tst-preadvwritev2.c index be22802dbe..cb58cbe41e 100644 --- a/misc/tst-preadvwritev2.c +++ b/misc/tst-preadvwritev2.c @@ -30,6 +30,8 @@ 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 8d3cc32b28..6a9de54c78 100644 --- a/misc/tst-preadvwritev64v2.c +++ b/misc/tst-preadvwritev64v2.c @@ -32,6 +32,8 @@ 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/sysdeps/unix/sysv/linux/preadv2.c b/sysdeps/unix/sysv/linux/preadv2.c index c8bf0764ef..bb08cbc5fd 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: diff --git a/sysdeps/unix/sysv/linux/preadv64v2.c b/sysdeps/unix/sysv/linux/preadv64v2.c index d7400a0252..b72a047347 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: diff --git a/sysdeps/unix/sysv/linux/pwritev2.c b/sysdeps/unix/sysv/linux/pwritev2.c index 29c2264c8f..26333ebd43 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: diff --git a/sysdeps/unix/sysv/linux/pwritev64v2.c b/sysdeps/unix/sysv/linux/pwritev64v2.c index 42da321149..17ea905aa6 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: commit 5473739a7b44f27965b70d1acf480f5f72603e78 Author: Rafal Luzynski Date: Tue Oct 2 23:34:18 2018 +0200 kl_GL: Fix spelling of Sunday, should be "sapaat" (bug 20209). Although CLDR says otherwise, it is confirmed by Oqaasileriffik, the official Greenlandic language regulator, that this change is correct. [BZ #20209] * localedata/locales/kl_GL: (abday): Fix spelling of Sun (Sunday), should be "sap" rather than "sab". (day): Fix spelling of Sunday, should be "sapaat" rather than "sabaat". (cherry picked from commit dae3ed958c3d0090838e49ff4f78c201262b1cf0) diff --git a/ChangeLog b/ChangeLog index 11a9b8d98e..32b9cbfbe2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2018-10-09 Rafal Luzynski + + [BZ #20209] + * localedata/locales/kl_GL: (abday): Fix spelling of Sun (Sunday), + should be "sap" rather than "sab". + (day): Fix spelling of Sunday, should be "sapaat" rather than + "sabaat". + 2018-09-28 Adhemerval Zanella [BZ #23579] diff --git a/NEWS b/NEWS index fd14941128..594cecfc75 100644 --- a/NEWS +++ b/NEWS @@ -9,6 +9,7 @@ Version 2.28.1 The following bugs are resolved with this release: + [20209] localedata: Spelling mistake for Sunday in Greenlandic kl_GL [23497] readdir64@GLIBC_2.1 cannot parse the kernel directory stream [23521] nss_files aliases database file stream leak [23538] pthread_cond_broadcast: Fix waiters-after-spinning case diff --git a/localedata/locales/kl_GL b/localedata/locales/kl_GL index 5ab14a31aa..5723ce7dcf 100644 --- a/localedata/locales/kl_GL +++ b/localedata/locales/kl_GL @@ -70,11 +70,11 @@ copy "da_DK" END LC_NUMERIC LC_TIME -abday "sab";"ata";/ +abday "sap";"ata";/ "mar";"pin";/ "sis";"tal";/ "arf" -day "sabaat";/ +day "sapaat";/ "ataasinngorneq";/ "marlunngorneq";/ "pingasunngorneq";/ commit 5a74abda201907cafbdabd1debf98890313ff71e Author: H.J. Lu Date: Fri Sep 28 13:31:19 2018 -0700 i386: Use _dl_runtime_[resolve|profile]_shstk for SHSTK [BZ #23716] When elf_machine_runtime_setup is called to set up resolver, it should use _dl_runtime_resolve_shstk or _dl_runtime_profile_shstk if SHSTK is enabled by kernel. Tested on i686 with and without --enable-cet as well as on CET emulator with --enable-cet. [BZ #23716] * sysdeps/i386/dl-cet.c: Removed. * sysdeps/i386/dl-machine.h (_dl_runtime_resolve_shstk): New prototype. (_dl_runtime_profile_shstk): Likewise. (elf_machine_runtime_setup): Use _dl_runtime_profile_shstk or _dl_runtime_resolve_shstk if SHSTK is enabled by kernel. Signed-off-by: H.J. Lu (cherry picked from commit 7b1f9406761331cf35fe521fbdb592beecf68a2c) diff --git a/ChangeLog b/ChangeLog index 32b9cbfbe2..7f4c6a48bc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2018-10-09 H.J. Lu + + [BZ #23716] + * sysdeps/i386/dl-cet.c: Removed. + * sysdeps/i386/dl-machine.h (_dl_runtime_resolve_shstk): New + prototype. + (_dl_runtime_profile_shstk): Likewise. + (elf_machine_runtime_setup): Use _dl_runtime_profile_shstk or + _dl_runtime_resolve_shstk if SHSTK is enabled by kernel. + 2018-10-09 Rafal Luzynski [BZ #20209] diff --git a/sysdeps/i386/dl-cet.c b/sysdeps/i386/dl-cet.c deleted file mode 100644 index 5d9a4e8d51..0000000000 --- a/sysdeps/i386/dl-cet.c +++ /dev/null @@ -1,67 +0,0 @@ -/* Linux/i386 CET initializers function. - Copyright (C) 2018 Free Software Foundation, Inc. - - 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 - . */ - - -#define LINKAGE static inline -#define _dl_cet_check cet_check -#include -#undef _dl_cet_check - -#ifdef SHARED -void -_dl_cet_check (struct link_map *main_map, const char *program) -{ - cet_check (main_map, program); - - if ((GL(dl_x86_feature_1)[0] & GNU_PROPERTY_X86_FEATURE_1_SHSTK)) - { - /* Replace _dl_runtime_resolve and _dl_runtime_profile with - _dl_runtime_resolve_shstk and _dl_runtime_profile_shstk, - respectively if SHSTK is enabled. */ - extern void _dl_runtime_resolve (Elf32_Word) attribute_hidden; - extern void _dl_runtime_resolve_shstk (Elf32_Word) attribute_hidden; - extern void _dl_runtime_profile (Elf32_Word) attribute_hidden; - extern void _dl_runtime_profile_shstk (Elf32_Word) attribute_hidden; - unsigned int i; - struct link_map *l; - Elf32_Addr *got; - - if (main_map->l_info[DT_JMPREL]) - { - got = (Elf32_Addr *) D_PTR (main_map, l_info[DT_PLTGOT]); - if (got[2] == (Elf32_Addr) &_dl_runtime_resolve) - got[2] = (Elf32_Addr) &_dl_runtime_resolve_shstk; - else if (got[2] == (Elf32_Addr) &_dl_runtime_profile) - got[2] = (Elf32_Addr) &_dl_runtime_profile_shstk; - } - - i = main_map->l_searchlist.r_nlist; - while (i-- > 0) - { - l = main_map->l_initfini[i]; - if (l->l_info[DT_JMPREL]) - { - got = (Elf32_Addr *) D_PTR (l, l_info[DT_PLTGOT]); - if (got[2] == (Elf32_Addr) &_dl_runtime_resolve) - got[2] = (Elf32_Addr) &_dl_runtime_resolve_shstk; - else if (got[2] == (Elf32_Addr) &_dl_runtime_profile) - got[2] = (Elf32_Addr) &_dl_runtime_profile_shstk; - } - } - } -} -#endif diff --git a/sysdeps/i386/dl-machine.h b/sysdeps/i386/dl-machine.h index 1afdcbd9ea..f6cfb90e21 100644 --- a/sysdeps/i386/dl-machine.h +++ b/sysdeps/i386/dl-machine.h @@ -67,6 +67,11 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile) Elf32_Addr *got; extern void _dl_runtime_resolve (Elf32_Word) attribute_hidden; extern void _dl_runtime_profile (Elf32_Word) attribute_hidden; + extern void _dl_runtime_resolve_shstk (Elf32_Word) attribute_hidden; + extern void _dl_runtime_profile_shstk (Elf32_Word) attribute_hidden; + /* Check if SHSTK is enabled by kernel. */ + bool shstk_enabled + = (GL(dl_x86_feature_1)[0] & GNU_PROPERTY_X86_FEATURE_1_SHSTK) != 0; if (l->l_info[DT_JMPREL] && lazy) { @@ -93,7 +98,9 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile) end in this function. */ if (__glibc_unlikely (profile)) { - got[2] = (Elf32_Addr) &_dl_runtime_profile; + got[2] = (shstk_enabled + ? (Elf32_Addr) &_dl_runtime_profile_shstk + : (Elf32_Addr) &_dl_runtime_profile); if (GLRO(dl_profile) != NULL && _dl_name_match_p (GLRO(dl_profile), l)) @@ -104,7 +111,9 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile) else /* This function will get called to fix up the GOT entry indicated by the offset on the stack, and then jump to the resolved address. */ - got[2] = (Elf32_Addr) &_dl_runtime_resolve; + got[2] = (shstk_enabled + ? (Elf32_Addr) &_dl_runtime_resolve_shstk + : (Elf32_Addr) &_dl_runtime_resolve); } return lazy; commit 314e181dc90cb290942d8b2b57823306ae956696 Author: Stefan Liebler Date: Wed Oct 17 12:23:04 2018 +0200 Fix race in pthread_mutex_lock while promoting to PTHREAD_MUTEX_ELISION_NP [BZ #23275] The race leads either to pthread_mutex_destroy returning EBUSY or triggering an assertion (See description in bugzilla). This patch is fixing the race by ensuring that the elision path is used in all cases if elision is enabled by the GLIBC_TUNABLES framework. The __kind variable in struct __pthread_mutex_s is accessed concurrently. Therefore we are now using the atomic macros. The new testcase tst-mutex10 is triggering the race on s390x and intel. Presumably also on power, but I don't have access to a power machine with lock-elision. At least the code for power is the same as on the other two architectures. ChangeLog: [BZ #23275] * nptl/tst-mutex10.c: New File. * nptl/Makefile (tests): Add tst-mutex10. (tst-mutex10-ENV): New variable. * sysdeps/unix/sysv/linux/s390/force-elision.h: (FORCE_ELISION): Ensure that elision path is used if elision is available. * sysdeps/unix/sysv/linux/powerpc/force-elision.h (FORCE_ELISION): Likewise. * sysdeps/unix/sysv/linux/x86/force-elision.h: (FORCE_ELISION): Likewise. * nptl/pthreadP.h (PTHREAD_MUTEX_TYPE, PTHREAD_MUTEX_TYPE_ELISION) (PTHREAD_MUTEX_PSHARED): Use atomic_load_relaxed. * nptl/pthread_mutex_consistent.c (pthread_mutex_consistent): Likewise. * nptl/pthread_mutex_getprioceiling.c (pthread_mutex_getprioceiling): Likewise. * nptl/pthread_mutex_lock.c (__pthread_mutex_lock_full) (__pthread_mutex_cond_lock_adjust): Likewise. * nptl/pthread_mutex_setprioceiling.c (pthread_mutex_setprioceiling): Likewise. * nptl/pthread_mutex_timedlock.c (__pthread_mutex_timedlock): Likewise. * nptl/pthread_mutex_trylock.c (__pthread_mutex_trylock): Likewise. * nptl/pthread_mutex_unlock.c (__pthread_mutex_unlock_full): Likewise. * sysdeps/nptl/bits/thread-shared-types.h (struct __pthread_mutex_s): Add comments. * nptl/pthread_mutex_destroy.c (__pthread_mutex_destroy): Use atomic_load_relaxed and atomic_store_relaxed. * nptl/pthread_mutex_init.c (__pthread_mutex_init): Use atomic_store_relaxed. (cherry picked from commit 403b4feb22dcbc85ace72a361d2a951380372471) diff --git a/ChangeLog b/ChangeLog index 7f4c6a48bc..5b743f2fdb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,34 @@ +2018-10-17 Stefan Liebler + + [BZ #23275] + * nptl/tst-mutex10.c: New File. + * nptl/Makefile (tests): Add tst-mutex10. + (tst-mutex10-ENV): New variable. + * sysdeps/unix/sysv/linux/s390/force-elision.h: (FORCE_ELISION): + Ensure that elision path is used if elision is available. + * sysdeps/unix/sysv/linux/powerpc/force-elision.h (FORCE_ELISION): + Likewise. + * sysdeps/unix/sysv/linux/x86/force-elision.h: (FORCE_ELISION): + Likewise. + * nptl/pthreadP.h (PTHREAD_MUTEX_TYPE, PTHREAD_MUTEX_TYPE_ELISION) + (PTHREAD_MUTEX_PSHARED): Use atomic_load_relaxed. + * nptl/pthread_mutex_consistent.c (pthread_mutex_consistent): Likewise. + * nptl/pthread_mutex_getprioceiling.c (pthread_mutex_getprioceiling): + Likewise. + * nptl/pthread_mutex_lock.c (__pthread_mutex_lock_full) + (__pthread_mutex_cond_lock_adjust): Likewise. + * nptl/pthread_mutex_setprioceiling.c (pthread_mutex_setprioceiling): + Likewise. + * nptl/pthread_mutex_timedlock.c (__pthread_mutex_timedlock): Likewise. + * nptl/pthread_mutex_trylock.c (__pthread_mutex_trylock): Likewise. + * nptl/pthread_mutex_unlock.c (__pthread_mutex_unlock_full): Likewise. + * sysdeps/nptl/bits/thread-shared-types.h (struct __pthread_mutex_s): + Add comments. + * nptl/pthread_mutex_destroy.c (__pthread_mutex_destroy): + Use atomic_load_relaxed and atomic_store_relaxed. + * nptl/pthread_mutex_init.c (__pthread_mutex_init): + Use atomic_store_relaxed. + 2018-10-09 H.J. Lu [BZ #23716] diff --git a/nptl/Makefile b/nptl/Makefile index be8066524c..49b6faa330 100644 --- a/nptl/Makefile +++ b/nptl/Makefile @@ -241,9 +241,9 @@ LDLIBS-tst-minstack-throw = -lstdc++ tests = tst-attr1 tst-attr2 tst-attr3 tst-default-attr \ tst-mutex1 tst-mutex2 tst-mutex3 tst-mutex4 tst-mutex5 tst-mutex6 \ - tst-mutex7 tst-mutex9 tst-mutex5a tst-mutex7a tst-mutex7robust \ - tst-mutexpi1 tst-mutexpi2 tst-mutexpi3 tst-mutexpi4 tst-mutexpi5 \ - tst-mutexpi5a tst-mutexpi6 tst-mutexpi7 tst-mutexpi7a \ + tst-mutex7 tst-mutex9 tst-mutex10 tst-mutex5a tst-mutex7a \ + tst-mutex7robust tst-mutexpi1 tst-mutexpi2 tst-mutexpi3 tst-mutexpi4 \ + tst-mutexpi5 tst-mutexpi5a tst-mutexpi6 tst-mutexpi7 tst-mutexpi7a \ tst-mutexpi9 \ tst-spin1 tst-spin2 tst-spin3 tst-spin4 \ tst-cond1 tst-cond2 tst-cond3 tst-cond4 tst-cond5 tst-cond6 tst-cond7 \ @@ -709,6 +709,8 @@ endif $(objpfx)tst-compat-forwarder: $(objpfx)tst-compat-forwarder-mod.so +tst-mutex10-ENV = GLIBC_TUNABLES=glibc.elision.enable=1 + # The tests here better do not run in parallel ifneq ($(filter %tests,$(MAKECMDGOALS)),) .NOTPARALLEL: diff --git a/nptl/pthreadP.h b/nptl/pthreadP.h index 13bdb11133..19efe1e35f 100644 --- a/nptl/pthreadP.h +++ b/nptl/pthreadP.h @@ -110,19 +110,23 @@ enum }; #define PTHREAD_MUTEX_PSHARED_BIT 128 +/* See concurrency notes regarding __kind in struct __pthread_mutex_s + in sysdeps/nptl/bits/thread-shared-types.h. */ #define PTHREAD_MUTEX_TYPE(m) \ - ((m)->__data.__kind & 127) + (atomic_load_relaxed (&((m)->__data.__kind)) & 127) /* Don't include NO_ELISION, as that type is always the same as the underlying lock type. */ #define PTHREAD_MUTEX_TYPE_ELISION(m) \ - ((m)->__data.__kind & (127|PTHREAD_MUTEX_ELISION_NP)) + (atomic_load_relaxed (&((m)->__data.__kind)) \ + & (127 | PTHREAD_MUTEX_ELISION_NP)) #if LLL_PRIVATE == 0 && LLL_SHARED == 128 # define PTHREAD_MUTEX_PSHARED(m) \ - ((m)->__data.__kind & 128) + (atomic_load_relaxed (&((m)->__data.__kind)) & 128) #else # define PTHREAD_MUTEX_PSHARED(m) \ - (((m)->__data.__kind & 128) ? LLL_SHARED : LLL_PRIVATE) + ((atomic_load_relaxed (&((m)->__data.__kind)) & 128) \ + ? LLL_SHARED : LLL_PRIVATE) #endif /* The kernel when waking robust mutexes on exit never uses diff --git a/nptl/pthread_mutex_consistent.c b/nptl/pthread_mutex_consistent.c index 85b8e1a6cb..4fbd875430 100644 --- a/nptl/pthread_mutex_consistent.c +++ b/nptl/pthread_mutex_consistent.c @@ -23,8 +23,11 @@ int pthread_mutex_consistent (pthread_mutex_t *mutex) { - /* Test whether this is a robust mutex with a dead owner. */ - if ((mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) == 0 + /* Test whether this is a robust mutex with a dead owner. + See concurrency notes regarding __kind in struct __pthread_mutex_s + in sysdeps/nptl/bits/thread-shared-types.h. */ + if ((atomic_load_relaxed (&(mutex->__data.__kind)) + & PTHREAD_MUTEX_ROBUST_NORMAL_NP) == 0 || mutex->__data.__owner != PTHREAD_MUTEX_INCONSISTENT) return EINVAL; diff --git a/nptl/pthread_mutex_destroy.c b/nptl/pthread_mutex_destroy.c index 5a22611541..713ea68496 100644 --- a/nptl/pthread_mutex_destroy.c +++ b/nptl/pthread_mutex_destroy.c @@ -27,12 +27,17 @@ __pthread_mutex_destroy (pthread_mutex_t *mutex) { LIBC_PROBE (mutex_destroy, 1, mutex); - if ((mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) == 0 + /* See concurrency notes regarding __kind in struct __pthread_mutex_s + in sysdeps/nptl/bits/thread-shared-types.h. */ + if ((atomic_load_relaxed (&(mutex->__data.__kind)) + & PTHREAD_MUTEX_ROBUST_NORMAL_NP) == 0 && mutex->__data.__nusers != 0) return EBUSY; - /* Set to an invalid value. */ - mutex->__data.__kind = -1; + /* Set to an invalid value. Relaxed MO is enough as it is undefined behavior + if the mutex is used after it has been destroyed. But you can reinitialize + it with pthread_mutex_init. */ + atomic_store_relaxed (&(mutex->__data.__kind), -1); return 0; } diff --git a/nptl/pthread_mutex_getprioceiling.c b/nptl/pthread_mutex_getprioceiling.c index efa37b0d99..ee85949578 100644 --- a/nptl/pthread_mutex_getprioceiling.c +++ b/nptl/pthread_mutex_getprioceiling.c @@ -24,7 +24,9 @@ int pthread_mutex_getprioceiling (const pthread_mutex_t *mutex, int *prioceiling) { - if (__builtin_expect ((mutex->__data.__kind + /* See concurrency notes regarding __kind in struct __pthread_mutex_s + in sysdeps/nptl/bits/thread-shared-types.h. */ + if (__builtin_expect ((atomic_load_relaxed (&(mutex->__data.__kind)) & PTHREAD_MUTEX_PRIO_PROTECT_NP) == 0, 0)) return EINVAL; diff --git a/nptl/pthread_mutex_init.c b/nptl/pthread_mutex_init.c index d8fe473728..5cf290c272 100644 --- a/nptl/pthread_mutex_init.c +++ b/nptl/pthread_mutex_init.c @@ -101,7 +101,7 @@ __pthread_mutex_init (pthread_mutex_t *mutex, memset (mutex, '\0', __SIZEOF_PTHREAD_MUTEX_T); /* Copy the values from the attribute. */ - mutex->__data.__kind = imutexattr->mutexkind & ~PTHREAD_MUTEXATTR_FLAG_BITS; + int mutex_kind = imutexattr->mutexkind & ~PTHREAD_MUTEXATTR_FLAG_BITS; if ((imutexattr->mutexkind & PTHREAD_MUTEXATTR_FLAG_ROBUST) != 0) { @@ -111,17 +111,17 @@ __pthread_mutex_init (pthread_mutex_t *mutex, return ENOTSUP; #endif - mutex->__data.__kind |= PTHREAD_MUTEX_ROBUST_NORMAL_NP; + mutex_kind |= PTHREAD_MUTEX_ROBUST_NORMAL_NP; } switch (imutexattr->mutexkind & PTHREAD_MUTEXATTR_PROTOCOL_MASK) { case PTHREAD_PRIO_INHERIT << PTHREAD_MUTEXATTR_PROTOCOL_SHIFT: - mutex->__data.__kind |= PTHREAD_MUTEX_PRIO_INHERIT_NP; + mutex_kind |= PTHREAD_MUTEX_PRIO_INHERIT_NP; break; case PTHREAD_PRIO_PROTECT << PTHREAD_MUTEXATTR_PROTOCOL_SHIFT: - mutex->__data.__kind |= PTHREAD_MUTEX_PRIO_PROTECT_NP; + mutex_kind |= PTHREAD_MUTEX_PRIO_PROTECT_NP; int ceiling = (imutexattr->mutexkind & PTHREAD_MUTEXATTR_PRIO_CEILING_MASK) @@ -145,7 +145,11 @@ __pthread_mutex_init (pthread_mutex_t *mutex, FUTEX_PRIVATE_FLAG FUTEX_WAKE. */ if ((imutexattr->mutexkind & (PTHREAD_MUTEXATTR_FLAG_PSHARED | PTHREAD_MUTEXATTR_FLAG_ROBUST)) != 0) - mutex->__data.__kind |= PTHREAD_MUTEX_PSHARED_BIT; + mutex_kind |= PTHREAD_MUTEX_PSHARED_BIT; + + /* See concurrency notes regarding __kind in struct __pthread_mutex_s + in sysdeps/nptl/bits/thread-shared-types.h. */ + atomic_store_relaxed (&(mutex->__data.__kind), mutex_kind); /* Default values: mutex not used yet. */ // mutex->__count = 0; already done by memset diff --git a/nptl/pthread_mutex_lock.c b/nptl/pthread_mutex_lock.c index 1519c142bd..29cc143e6c 100644 --- a/nptl/pthread_mutex_lock.c +++ b/nptl/pthread_mutex_lock.c @@ -62,6 +62,8 @@ static int __pthread_mutex_lock_full (pthread_mutex_t *mutex) int __pthread_mutex_lock (pthread_mutex_t *mutex) { + /* See concurrency notes regarding mutex type which is loaded from __kind + in struct __pthread_mutex_s in sysdeps/nptl/bits/thread-shared-types.h. */ unsigned int type = PTHREAD_MUTEX_TYPE_ELISION (mutex); LIBC_PROBE (mutex_entry, 1, mutex); @@ -350,8 +352,14 @@ __pthread_mutex_lock_full (pthread_mutex_t *mutex) case PTHREAD_MUTEX_PI_ROBUST_NORMAL_NP: case PTHREAD_MUTEX_PI_ROBUST_ADAPTIVE_NP: { - int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP; - int robust = mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP; + int kind, robust; + { + /* See concurrency notes regarding __kind in struct __pthread_mutex_s + in sysdeps/nptl/bits/thread-shared-types.h. */ + int mutex_kind = atomic_load_relaxed (&(mutex->__data.__kind)); + kind = mutex_kind & PTHREAD_MUTEX_KIND_MASK_NP; + robust = mutex_kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP; + } if (robust) { @@ -502,7 +510,10 @@ __pthread_mutex_lock_full (pthread_mutex_t *mutex) case PTHREAD_MUTEX_PP_NORMAL_NP: case PTHREAD_MUTEX_PP_ADAPTIVE_NP: { - int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP; + /* See concurrency notes regarding __kind in struct __pthread_mutex_s + in sysdeps/nptl/bits/thread-shared-types.h. */ + int kind = atomic_load_relaxed (&(mutex->__data.__kind)) + & PTHREAD_MUTEX_KIND_MASK_NP; oldval = mutex->__data.__lock; @@ -607,15 +618,18 @@ hidden_def (__pthread_mutex_lock) void __pthread_mutex_cond_lock_adjust (pthread_mutex_t *mutex) { - assert ((mutex->__data.__kind & PTHREAD_MUTEX_PRIO_INHERIT_NP) != 0); - assert ((mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) == 0); - assert ((mutex->__data.__kind & PTHREAD_MUTEX_PSHARED_BIT) == 0); + /* See concurrency notes regarding __kind in struct __pthread_mutex_s + in sysdeps/nptl/bits/thread-shared-types.h. */ + int mutex_kind = atomic_load_relaxed (&(mutex->__data.__kind)); + assert ((mutex_kind & PTHREAD_MUTEX_PRIO_INHERIT_NP) != 0); + assert ((mutex_kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) == 0); + assert ((mutex_kind & PTHREAD_MUTEX_PSHARED_BIT) == 0); /* Record the ownership. */ pid_t id = THREAD_GETMEM (THREAD_SELF, tid); mutex->__data.__owner = id; - if (mutex->__data.__kind == PTHREAD_MUTEX_PI_RECURSIVE_NP) + if (mutex_kind == PTHREAD_MUTEX_PI_RECURSIVE_NP) ++mutex->__data.__count; } #endif diff --git a/nptl/pthread_mutex_setprioceiling.c b/nptl/pthread_mutex_setprioceiling.c index 8594874f85..8306cabcf4 100644 --- a/nptl/pthread_mutex_setprioceiling.c +++ b/nptl/pthread_mutex_setprioceiling.c @@ -27,9 +27,10 @@ int pthread_mutex_setprioceiling (pthread_mutex_t *mutex, int prioceiling, int *old_ceiling) { - /* The low bits of __kind aren't ever changed after pthread_mutex_init, - so we don't need a lock yet. */ - if ((mutex->__data.__kind & PTHREAD_MUTEX_PRIO_PROTECT_NP) == 0) + /* See concurrency notes regarding __kind in struct __pthread_mutex_s + in sysdeps/nptl/bits/thread-shared-types.h. */ + if ((atomic_load_relaxed (&(mutex->__data.__kind)) + & PTHREAD_MUTEX_PRIO_PROTECT_NP) == 0) return EINVAL; /* See __init_sched_fifo_prio. */ diff --git a/nptl/pthread_mutex_timedlock.c b/nptl/pthread_mutex_timedlock.c index 28237b0e58..888c12fe28 100644 --- a/nptl/pthread_mutex_timedlock.c +++ b/nptl/pthread_mutex_timedlock.c @@ -53,6 +53,8 @@ __pthread_mutex_timedlock (pthread_mutex_t *mutex, /* We must not check ABSTIME here. If the thread does not block abstime must not be checked for a valid value. */ + /* See concurrency notes regarding mutex type which is loaded from __kind + in struct __pthread_mutex_s in sysdeps/nptl/bits/thread-shared-types.h. */ switch (__builtin_expect (PTHREAD_MUTEX_TYPE_ELISION (mutex), PTHREAD_MUTEX_TIMED_NP)) { @@ -338,8 +340,14 @@ __pthread_mutex_timedlock (pthread_mutex_t *mutex, case PTHREAD_MUTEX_PI_ROBUST_NORMAL_NP: case PTHREAD_MUTEX_PI_ROBUST_ADAPTIVE_NP: { - int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP; - int robust = mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP; + int kind, robust; + { + /* See concurrency notes regarding __kind in struct __pthread_mutex_s + in sysdeps/nptl/bits/thread-shared-types.h. */ + int mutex_kind = atomic_load_relaxed (&(mutex->__data.__kind)); + kind = mutex_kind & PTHREAD_MUTEX_KIND_MASK_NP; + robust = mutex_kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP; + } if (robust) { @@ -509,7 +517,10 @@ __pthread_mutex_timedlock (pthread_mutex_t *mutex, case PTHREAD_MUTEX_PP_NORMAL_NP: case PTHREAD_MUTEX_PP_ADAPTIVE_NP: { - int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP; + /* See concurrency notes regarding __kind in struct __pthread_mutex_s + in sysdeps/nptl/bits/thread-shared-types.h. */ + int kind = atomic_load_relaxed (&(mutex->__data.__kind)) + & PTHREAD_MUTEX_KIND_MASK_NP; oldval = mutex->__data.__lock; diff --git a/nptl/pthread_mutex_trylock.c b/nptl/pthread_mutex_trylock.c index 7de61f4f68..fa90c1d1e6 100644 --- a/nptl/pthread_mutex_trylock.c +++ b/nptl/pthread_mutex_trylock.c @@ -36,6 +36,8 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) int oldval; pid_t id = THREAD_GETMEM (THREAD_SELF, tid); + /* See concurrency notes regarding mutex type which is loaded from __kind + in struct __pthread_mutex_s in sysdeps/nptl/bits/thread-shared-types.h. */ switch (__builtin_expect (PTHREAD_MUTEX_TYPE_ELISION (mutex), PTHREAD_MUTEX_TIMED_NP)) { @@ -199,8 +201,14 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) case PTHREAD_MUTEX_PI_ROBUST_NORMAL_NP: case PTHREAD_MUTEX_PI_ROBUST_ADAPTIVE_NP: { - int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP; - int robust = mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP; + int kind, robust; + { + /* See concurrency notes regarding __kind in struct __pthread_mutex_s + in sysdeps/nptl/bits/thread-shared-types.h. */ + int mutex_kind = atomic_load_relaxed (&(mutex->__data.__kind)); + kind = mutex_kind & PTHREAD_MUTEX_KIND_MASK_NP; + robust = mutex_kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP; + } if (robust) /* Note: robust PI futexes are signaled by setting bit 0. */ @@ -325,7 +333,10 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) case PTHREAD_MUTEX_PP_NORMAL_NP: case PTHREAD_MUTEX_PP_ADAPTIVE_NP: { - int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP; + /* See concurrency notes regarding __kind in struct __pthread_mutex_s + in sysdeps/nptl/bits/thread-shared-types.h. */ + int kind = atomic_load_relaxed (&(mutex->__data.__kind)) + & PTHREAD_MUTEX_KIND_MASK_NP; oldval = mutex->__data.__lock; diff --git a/nptl/pthread_mutex_unlock.c b/nptl/pthread_mutex_unlock.c index 9ea62943b7..68d04d5395 100644 --- a/nptl/pthread_mutex_unlock.c +++ b/nptl/pthread_mutex_unlock.c @@ -35,6 +35,8 @@ int attribute_hidden __pthread_mutex_unlock_usercnt (pthread_mutex_t *mutex, int decr) { + /* See concurrency notes regarding mutex type which is loaded from __kind + in struct __pthread_mutex_s in sysdeps/nptl/bits/thread-shared-types.h. */ int type = PTHREAD_MUTEX_TYPE_ELISION (mutex); if (__builtin_expect (type & ~(PTHREAD_MUTEX_KIND_MASK_NP|PTHREAD_MUTEX_ELISION_FLAGS_NP), 0)) @@ -222,13 +224,19 @@ __pthread_mutex_unlock_full (pthread_mutex_t *mutex, int decr) /* If the previous owner died and the caller did not succeed in making the state consistent, mark the mutex as unrecoverable and make all waiters. */ - if ((mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) != 0 + /* See concurrency notes regarding __kind in struct __pthread_mutex_s + in sysdeps/nptl/bits/thread-shared-types.h. */ + if ((atomic_load_relaxed (&(mutex->__data.__kind)) + & PTHREAD_MUTEX_ROBUST_NORMAL_NP) != 0 && __builtin_expect (mutex->__data.__owner == PTHREAD_MUTEX_INCONSISTENT, 0)) pi_notrecoverable: newowner = PTHREAD_MUTEX_NOTRECOVERABLE; - if ((mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) != 0) + /* See concurrency notes regarding __kind in struct __pthread_mutex_s + in sysdeps/nptl/bits/thread-shared-types.h. */ + if ((atomic_load_relaxed (&(mutex->__data.__kind)) + & PTHREAD_MUTEX_ROBUST_NORMAL_NP) != 0) { continue_pi_robust: /* Remove mutex from the list. @@ -251,7 +259,10 @@ __pthread_mutex_unlock_full (pthread_mutex_t *mutex, int decr) /* Unlock. Load all necessary mutex data before releasing the mutex to not violate the mutex destruction requirements (see lll_unlock). */ - int robust = mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP; + /* See concurrency notes regarding __kind in struct __pthread_mutex_s + in sysdeps/nptl/bits/thread-shared-types.h. */ + int robust = atomic_load_relaxed (&(mutex->__data.__kind)) + & PTHREAD_MUTEX_ROBUST_NORMAL_NP; private = (robust ? PTHREAD_ROBUST_MUTEX_PSHARED (mutex) : PTHREAD_MUTEX_PSHARED (mutex)); diff --git a/nptl/tst-mutex10.c b/nptl/tst-mutex10.c new file mode 100644 index 0000000000..e1113ca60a --- /dev/null +++ b/nptl/tst-mutex10.c @@ -0,0 +1,109 @@ +/* Testing race while enabling lock elision. + 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 + . */ +#include +#include +#include +#include +#include +#include +#include +#include + +static pthread_barrier_t barrier; +static pthread_mutex_t mutex; +static long long int iteration_count = 1000000; +static unsigned int thread_count = 3; + +static void * +thr_func (void *arg) +{ + long long int i; + for (i = 0; i < iteration_count; i++) + { + if ((uintptr_t) arg == 0) + { + xpthread_mutex_destroy (&mutex); + xpthread_mutex_init (&mutex, NULL); + } + + xpthread_barrier_wait (&barrier); + + /* Test if enabling lock elision works if it is enabled concurrently. + There was a race in FORCE_ELISION macro which leads to either + pthread_mutex_destroy returning EBUSY as the owner was recorded + by pthread_mutex_lock - in "normal mutex" code path - but was not + resetted in pthread_mutex_unlock - in "elision" code path. + Or it leads to the assertion in nptl/pthread_mutex_lock.c: + assert (mutex->__data.__owner == 0); + Please ensure that the test is run with lock elision: + export GLIBC_TUNABLES=glibc.elision.enable=1 */ + xpthread_mutex_lock (&mutex); + xpthread_mutex_unlock (&mutex); + + xpthread_barrier_wait (&barrier); + } + return NULL; +} + +static int +do_test (void) +{ + unsigned int i; + printf ("Starting %d threads to run %lld iterations.\n", + thread_count, iteration_count); + + pthread_t *threads = xmalloc (thread_count * sizeof (pthread_t)); + xpthread_barrier_init (&barrier, NULL, thread_count); + xpthread_mutex_init (&mutex, NULL); + + for (i = 0; i < thread_count; i++) + threads[i] = xpthread_create (NULL, thr_func, (void *) (uintptr_t) i); + + for (i = 0; i < thread_count; i++) + xpthread_join (threads[i]); + + xpthread_barrier_destroy (&barrier); + free (threads); + + return EXIT_SUCCESS; +} + +#define OPT_ITERATIONS 10000 +#define OPT_THREADS 10001 +#define CMDLINE_OPTIONS \ + { "iterations", required_argument, NULL, OPT_ITERATIONS }, \ + { "threads", required_argument, NULL, OPT_THREADS }, +static void +cmdline_process (int c) +{ + long long int arg = strtoll (optarg, NULL, 0); + switch (c) + { + case OPT_ITERATIONS: + if (arg > 0) + iteration_count = arg; + break; + case OPT_THREADS: + if (arg > 0 && arg < 100) + thread_count = arg; + break; + } +} +#define CMDLINE_PROCESS cmdline_process +#define TIMEOUT 50 +#include diff --git a/sysdeps/nptl/bits/thread-shared-types.h b/sysdeps/nptl/bits/thread-shared-types.h index 1e2092a05d..05c94e7a71 100644 --- a/sysdeps/nptl/bits/thread-shared-types.h +++ b/sysdeps/nptl/bits/thread-shared-types.h @@ -124,7 +124,27 @@ struct __pthread_mutex_s unsigned int __nusers; #endif /* KIND must stay at this position in the structure to maintain - binary compatibility with static initializers. */ + binary compatibility with static initializers. + + Concurrency notes: + The __kind of a mutex is initialized either by the static + PTHREAD_MUTEX_INITIALIZER or by a call to pthread_mutex_init. + + After a mutex has been initialized, the __kind of a mutex is usually not + changed. BUT it can be set to -1 in pthread_mutex_destroy or elision can + be enabled. This is done concurrently in the pthread_mutex_*lock functions + by using the macro FORCE_ELISION. This macro is only defined for + architectures which supports lock elision. + + For elision, there are the flags PTHREAD_MUTEX_ELISION_NP and + PTHREAD_MUTEX_NO_ELISION_NP which can be set in addition to the already set + type of a mutex. + Before a mutex is initialized, only PTHREAD_MUTEX_NO_ELISION_NP can be set + with pthread_mutexattr_settype. + After a mutex has been initialized, the functions pthread_mutex_*lock can + enable elision - if the mutex-type and the machine supports it - by setting + the flag PTHREAD_MUTEX_ELISION_NP. This is done concurrently. Afterwards + the lock / unlock functions are using specific elision code-paths. */ int __kind; __PTHREAD_COMPAT_PADDING_MID #if __PTHREAD_MUTEX_NUSERS_AFTER_KIND diff --git a/sysdeps/unix/sysv/linux/powerpc/force-elision.h b/sysdeps/unix/sysv/linux/powerpc/force-elision.h index fe5d6ceade..d8f5a4b1c7 100644 --- a/sysdeps/unix/sysv/linux/powerpc/force-elision.h +++ b/sysdeps/unix/sysv/linux/powerpc/force-elision.h @@ -18,9 +18,45 @@ /* Automatically enable elision for existing user lock kinds. */ #define FORCE_ELISION(m, s) \ - if (__pthread_force_elision \ - && (m->__data.__kind & PTHREAD_MUTEX_ELISION_FLAGS_NP) == 0) \ + if (__pthread_force_elision) \ { \ - mutex->__data.__kind |= PTHREAD_MUTEX_ELISION_NP; \ - s; \ + /* See concurrency notes regarding __kind in \ + struct __pthread_mutex_s in \ + sysdeps/nptl/bits/thread-shared-types.h. \ + \ + There are the following cases for the kind of a mutex \ + (The mask PTHREAD_MUTEX_ELISION_FLAGS_NP covers the flags \ + PTHREAD_MUTEX_ELISION_NP and PTHREAD_MUTEX_NO_ELISION_NP where \ + only one of both flags can be set): \ + - both flags are not set: \ + This is the first lock operation for this mutex. Enable \ + elision as it is not enabled so far. \ + Note: It can happen that multiple threads are calling e.g. \ + pthread_mutex_lock at the same time as the first lock \ + operation for this mutex. Then elision is enabled for this \ + mutex by multiple threads. Storing with relaxed MO is enough \ + as all threads will store the same new value for the kind of \ + the mutex. But we have to ensure that we always use the \ + elision path regardless if this thread has enabled elision or \ + another one. \ + \ + - PTHREAD_MUTEX_ELISION_NP flag is set: \ + Elision was already enabled for this mutex by a previous lock \ + operation. See case above. Just use the elision path. \ + \ + - PTHREAD_MUTEX_NO_ELISION_NP flag is set: \ + Elision was explicitly disabled by pthread_mutexattr_settype. \ + Do not use the elision path. \ + Note: The flag PTHREAD_MUTEX_NO_ELISION_NP will never be \ + changed after mutex initialization. */ \ + int mutex_kind = atomic_load_relaxed (&((m)->__data.__kind)); \ + if ((mutex_kind & PTHREAD_MUTEX_ELISION_FLAGS_NP) == 0) \ + { \ + mutex_kind |= PTHREAD_MUTEX_ELISION_NP; \ + atomic_store_relaxed (&((m)->__data.__kind), mutex_kind); \ + } \ + if ((mutex_kind & PTHREAD_MUTEX_ELISION_NP) != 0) \ + { \ + s; \ + } \ } diff --git a/sysdeps/unix/sysv/linux/s390/force-elision.h b/sysdeps/unix/sysv/linux/s390/force-elision.h index d8a1b9972f..71f32367dd 100644 --- a/sysdeps/unix/sysv/linux/s390/force-elision.h +++ b/sysdeps/unix/sysv/linux/s390/force-elision.h @@ -18,9 +18,45 @@ /* Automatically enable elision for existing user lock kinds. */ #define FORCE_ELISION(m, s) \ - if (__pthread_force_elision \ - && (m->__data.__kind & PTHREAD_MUTEX_ELISION_FLAGS_NP) == 0) \ + if (__pthread_force_elision) \ { \ - mutex->__data.__kind |= PTHREAD_MUTEX_ELISION_NP; \ - s; \ + /* See concurrency notes regarding __kind in \ + struct __pthread_mutex_s in \ + sysdeps/nptl/bits/thread-shared-types.h. \ + \ + There are the following cases for the kind of a mutex \ + (The mask PTHREAD_MUTEX_ELISION_FLAGS_NP covers the flags \ + PTHREAD_MUTEX_ELISION_NP and PTHREAD_MUTEX_NO_ELISION_NP where \ + only one of both flags can be set): \ + - both flags are not set: \ + This is the first lock operation for this mutex. Enable \ + elision as it is not enabled so far. \ + Note: It can happen that multiple threads are calling e.g. \ + pthread_mutex_lock at the same time as the first lock \ + operation for this mutex. Then elision is enabled for this \ + mutex by multiple threads. Storing with relaxed MO is enough \ + as all threads will store the same new value for the kind of \ + the mutex. But we have to ensure that we always use the \ + elision path regardless if this thread has enabled elision or \ + another one. \ + \ + - PTHREAD_MUTEX_ELISION_NP flag is set: \ + Elision was already enabled for this mutex by a previous lock \ + operation. See case above. Just use the elision path. \ + \ + - PTHREAD_MUTEX_NO_ELISION_NP flag is set: \ + Elision was explicitly disabled by pthread_mutexattr_settype. \ + Do not use the elision path. \ + Note: The flag PTHREAD_MUTEX_NO_ELISION_NP will never be \ + changed after mutex initialization. */ \ + int mutex_kind = atomic_load_relaxed (&((m)->__data.__kind)); \ + if ((mutex_kind & PTHREAD_MUTEX_ELISION_FLAGS_NP) == 0) \ + { \ + mutex_kind |= PTHREAD_MUTEX_ELISION_NP; \ + atomic_store_relaxed (&((m)->__data.__kind), mutex_kind); \ + } \ + if ((mutex_kind & PTHREAD_MUTEX_ELISION_NP) != 0) \ + { \ + s; \ + } \ } diff --git a/sysdeps/unix/sysv/linux/x86/force-elision.h b/sysdeps/unix/sysv/linux/x86/force-elision.h index dd659c908f..61282d6678 100644 --- a/sysdeps/unix/sysv/linux/x86/force-elision.h +++ b/sysdeps/unix/sysv/linux/x86/force-elision.h @@ -18,9 +18,45 @@ /* Automatically enable elision for existing user lock kinds. */ #define FORCE_ELISION(m, s) \ - if (__pthread_force_elision \ - && (m->__data.__kind & PTHREAD_MUTEX_ELISION_FLAGS_NP) == 0) \ + if (__pthread_force_elision) \ { \ - mutex->__data.__kind |= PTHREAD_MUTEX_ELISION_NP; \ - s; \ + /* See concurrency notes regarding __kind in \ + struct __pthread_mutex_s in \ + sysdeps/nptl/bits/thread-shared-types.h. \ + \ + There are the following cases for the kind of a mutex \ + (The mask PTHREAD_MUTEX_ELISION_FLAGS_NP covers the flags \ + PTHREAD_MUTEX_ELISION_NP and PTHREAD_MUTEX_NO_ELISION_NP where \ + only one of both flags can be set): \ + - both flags are not set: \ + This is the first lock operation for this mutex. Enable \ + elision as it is not enabled so far. \ + Note: It can happen that multiple threads are calling e.g. \ + pthread_mutex_lock at the same time as the first lock \ + operation for this mutex. Then elision is enabled for this \ + mutex by multiple threads. Storing with relaxed MO is enough \ + as all threads will store the same new value for the kind of \ + the mutex. But we have to ensure that we always use the \ + elision path regardless if this thread has enabled elision or \ + another one. \ + \ + - PTHREAD_MUTEX_ELISION_NP flag is set: \ + Elision was already enabled for this mutex by a previous lock \ + operation. See case above. Just use the elision path. \ + \ + - PTHREAD_MUTEX_NO_ELISION_NP flag is set: \ + Elision was explicitly disabled by pthread_mutexattr_settype. \ + Do not use the elision path. \ + Note: The flag PTHREAD_MUTEX_NO_ELISION_NP will never be \ + changed after mutex initialization. */ \ + int mutex_kind = atomic_load_relaxed (&((m)->__data.__kind)); \ + if ((mutex_kind & PTHREAD_MUTEX_ELISION_FLAGS_NP) == 0) \ + { \ + mutex_kind |= PTHREAD_MUTEX_ELISION_NP; \ + atomic_store_relaxed (&((m)->__data.__kind), mutex_kind); \ + } \ + if ((mutex_kind & PTHREAD_MUTEX_ELISION_NP) != 0) \ + { \ + s; \ + } \ } commit 69d1e73d99c6ad3f65fc16b6325d6ae289950d03 Author: Ilya Yu. Malakhov Date: Mon Oct 22 13:03:57 2018 +0200 signal: Use correct type for si_band in siginfo_t [BZ #23562] (cherry picked from commit f997b4be18f7e57d757d39e42f7715db26528aa0) diff --git a/ChangeLog b/ChangeLog index 5b743f2fdb..7726438658 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2018-10-19 Ilya Yu. Malakhov + + [BZ #23562] + * sysdeps/unix/sysv/linux/bits/types/siginfo_t.h + (struct siginfo_t): Use correct type for si_band. + 2018-10-17 Stefan Liebler [BZ #23275] diff --git a/NEWS b/NEWS index 594cecfc75..e95a0ea159 100644 --- a/NEWS +++ b/NEWS @@ -13,6 +13,7 @@ The following bugs are resolved with this release: [23497] readdir64@GLIBC_2.1 cannot parse the kernel directory stream [23521] nss_files aliases database file stream leak [23538] pthread_cond_broadcast: Fix waiters-after-spinning case + [23562] signal: Use correct type for si_band in siginfo_t [23578] regex: Fix memory overread in re_compile_pattern [23579] libc: Errors misreported in preadv2 [23606] Missing ENDBR32 in sysdeps/i386/start.S diff --git a/sysdeps/unix/sysv/linux/bits/types/siginfo_t.h b/sysdeps/unix/sysv/linux/bits/types/siginfo_t.h index 33766d1813..43c4e009a4 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; commit aff9b377121f9cfabe5d45f3226acf99c73928a7 Author: Florian Weimer Date: Fri Oct 26 09:19:40 2018 +0200 conform: XFAIL siginfo_t si_band test on sparc64 We can use long int on sparcv9, but on sparc64, we must match the int type used by the kernel (and not long int, as in POSIX). (cherry picked from commit 7c5e34d7f1b8f8f5acd94c2b885ae13b85414dcd) diff --git a/ChangeLog b/ChangeLog index 7726438658..6debca5f83 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2018-10-25 Florian Weimer + + [BZ #23562] + [BZ #23821] + XFAIL siginfo_t si_band conform test on sparc64. + * sysdeps/unix/sysv/linux/sparc/bits/siginfo-arch.h + (__SI_BAND_TYPE): Only override long int default type on sparc64. + * sysdeps/unix/sysv/linux/sparc/sparc64/Makefile + (conformtest-xfail-conds): Add sparc64-linux. + * conform/data/signal.h-data (siginfo_t): XFAIL si_band test on + sparc64. + * conform/data/sys/wait.h-data (siginfo_t): Likewise. + 2018-10-19 Ilya Yu. Malakhov [BZ #23562] diff --git a/NEWS b/NEWS index e95a0ea159..fda6788519 100644 --- a/NEWS +++ b/NEWS @@ -19,6 +19,7 @@ The following bugs are resolved with this release: [23606] Missing ENDBR32 in sysdeps/i386/start.S [23679] gethostid: Missing NULL check for gethostbyname_r result [23717] Fix stack overflow in stdlib/tst-setcontext9 + [23821] si_band in siginfo_t has wrong type long int on sparc64 Version 2.28 diff --git a/conform/data/signal.h-data b/conform/data/signal.h-data index 11e54adb04..674e5793db 100644 --- a/conform/data/signal.h-data +++ b/conform/data/signal.h-data @@ -172,7 +172,8 @@ element siginfo_t pid_t si_pid element siginfo_t uid_t si_uid element siginfo_t {void*} si_addr element siginfo_t int si_status -element siginfo_t long si_band +// Bug 23821: si_band has type int on sparc64. +xfail[sparc64-linux]-element siginfo_t long si_band # endif # ifndef XPG42 element siginfo_t {union sigval} si_value diff --git a/conform/data/sys/wait.h-data b/conform/data/sys/wait.h-data index ed3869b34f..c0761424da 100644 --- a/conform/data/sys/wait.h-data +++ b/conform/data/sys/wait.h-data @@ -46,7 +46,8 @@ element siginfo_t pid_t si_pid element siginfo_t uid_t si_uid element siginfo_t {void*} si_addr element siginfo_t int si_status -element siginfo_t long si_band +// Bug 23821: si_band has type int on sparc64. +xfail[sparc64-linux]-element siginfo_t long si_band # ifndef XPG42 element siginfo_t {union sigval} si_value # endif diff --git a/sysdeps/unix/sysv/linux/sparc/bits/siginfo-arch.h b/sysdeps/unix/sysv/linux/sparc/bits/siginfo-arch.h index 9f79715ebe..4dd35237f6 100644 --- a/sysdeps/unix/sysv/linux/sparc/bits/siginfo-arch.h +++ b/sysdeps/unix/sysv/linux/sparc/bits/siginfo-arch.h @@ -2,7 +2,12 @@ #ifndef _BITS_SIGINFO_ARCH_H #define _BITS_SIGINFO_ARCH_H 1 -#define __SI_BAND_TYPE int +/* The kernel uses int instead of long int (as in POSIX). In 32-bit + mode, we can still use long int, but in 64-bit mode, we need to + deviate from POSIX. */ +#if __WORDSIZE == 64 +# define __SI_BAND_TYPE int +#endif #define __SI_SIGFAULT_ADDL \ int _si_trapno; diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/Makefile b/sysdeps/unix/sysv/linux/sparc/sparc64/Makefile index 715af3df7b..218c246f16 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc64/Makefile +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/Makefile @@ -7,3 +7,8 @@ LD += -melf64_sparc ifeq ($(subdir),stdlib) sysdep_routines += __start_context endif + +ifeq ($(subdir),conform) +# For bug 23821 (incorrect type of si_band). +conformtest-xfail-conds += sparc64-linux +endif commit 5256ffc51e4188a70fa0173cb6b6c94adde03fcb Author: Szabolcs Nagy Date: Fri Oct 26 14:39:42 2018 +0100 i64: fix missing exp2f, log2f and powf symbols in libm.a [BZ #23822] When new symbol versions were introduced without SVID compatible error handling the exp2f, log2f and powf symbols were accidentally removed from the ia64 lim.a. The regression was introduced by the commits f5f0f5265162fe6f4f238abcd3086985f7c38d6d New expf and exp2f version without SVID compat wrapper 72d3d281080be9f674982067d72874fd6cdb4b64 New symbol version for logf, log2f and powf without SVID compat With WEAK_LIBM_ENTRY(foo), there is a hidden __foo and weak foo symbol definition in both SHARED and !SHARED build. [BZ #23822] * sysdeps/ia64/fpu/e_exp2f.S (exp2f): Use WEAK_LIBM_ENTRY. * sysdeps/ia64/fpu/e_log2f.S (log2f): Likewise. * sysdeps/ia64/fpu/e_exp2f.S (powf): Likewise. (cherry picked from commit ba5b14c7613980dfefcad6b6e88f913e5f596c59) diff --git a/ChangeLog b/ChangeLog index 6debca5f83..73d5c57f0d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2018-10-26 Szabolcs Nagy + + [BZ #23822] + * sysdeps/ia64/fpu/e_exp2f.S (exp2f): Use WEAK_LIBM_ENTRY. + * sysdeps/ia64/fpu/e_log2f.S (log2f): Likewise. + * sysdeps/ia64/fpu/e_exp2f.S (powf): Likewise. + 2018-10-25 Florian Weimer [BZ #23562] diff --git a/NEWS b/NEWS index fda6788519..f4d9885819 100644 --- a/NEWS +++ b/NEWS @@ -20,6 +20,7 @@ The following bugs are resolved with this release: [23679] gethostid: Missing NULL check for gethostbyname_r result [23717] Fix stack overflow in stdlib/tst-setcontext9 [23821] si_band in siginfo_t has wrong type long int on sparc64 + [23822] ia64 static libm.a is missing exp2f, log2f and powf symbols Version 2.28 diff --git a/sysdeps/ia64/fpu/e_exp2f.S b/sysdeps/ia64/fpu/e_exp2f.S index 77bc6ea686..3010a95a2d 100644 --- a/sysdeps/ia64/fpu/e_exp2f.S +++ b/sysdeps/ia64/fpu/e_exp2f.S @@ -221,7 +221,7 @@ LOCAL_OBJECT_END(T_table) .section .text -GLOBAL_LIBM_ENTRY(__exp2f) +WEAK_LIBM_ENTRY(exp2f) {.mfi @@ -468,10 +468,10 @@ OUT_RANGE_exp2: } ;; -GLOBAL_LIBM_END(__exp2f) +WEAK_LIBM_END(exp2f) libm_alias_float_other (__exp2, exp2) #ifdef SHARED -.symver __exp2f,exp2f@@GLIBC_2.27 +.symver exp2f,exp2f@@GLIBC_2.27 .weak __exp2f_compat .set __exp2f_compat,__exp2f .symver __exp2f_compat,exp2f@GLIBC_2.2 diff --git a/sysdeps/ia64/fpu/e_log2f.S b/sysdeps/ia64/fpu/e_log2f.S index 5ca3bd61ea..e4ea094344 100644 --- a/sysdeps/ia64/fpu/e_log2f.S +++ b/sysdeps/ia64/fpu/e_log2f.S @@ -252,7 +252,7 @@ LOCAL_OBJECT_END(T_table) .section .text -GLOBAL_LIBM_ENTRY(__log2f) +WEAK_LIBM_ENTRY(log2f) { .mfi alloc r32=ar.pfs,1,4,4,0 @@ -491,10 +491,10 @@ SPECIAL_log2f: br.ret.sptk b0;; } -GLOBAL_LIBM_END(__log2f) +WEAK_LIBM_END(log2f) libm_alias_float_other (__log2, log2) #ifdef SHARED -.symver __log2f,log2f@@GLIBC_2.27 +.symver log2f,log2f@@GLIBC_2.27 .weak __log2f_compat .set __log2f_compat,__log2f .symver __log2f_compat,log2f@GLIBC_2.2 diff --git a/sysdeps/ia64/fpu/e_powf.S b/sysdeps/ia64/fpu/e_powf.S index 7449f8c7d5..945d5cdf28 100644 --- a/sysdeps/ia64/fpu/e_powf.S +++ b/sysdeps/ia64/fpu/e_powf.S @@ -868,7 +868,7 @@ data8 0xEAC0C6E7DD24392F , 0x00003FFF LOCAL_OBJECT_END(pow_tbl2) .section .text -GLOBAL_LIBM_ENTRY(__powf) +WEAK_LIBM_ENTRY(powf) // Get exponent of x. Will be used to calculate K. { .mfi @@ -2002,10 +2002,10 @@ POW_OVER_UNDER_ERROR: } ;; -GLOBAL_LIBM_END(__powf) +WEAK_LIBM_END(powf) libm_alias_float_other (__pow, pow) #ifdef SHARED -.symver __powf,powf@@GLIBC_2.27 +.symver powf,powf@@GLIBC_2.27 .weak __powf_compat .set __powf_compat,__powf .symver __powf_compat,powf@GLIBC_2.2 commit df11de91931597ab4adccb74d9d55c9ddd029a22 Author: Paul Pluzhnikov Date: Fri Nov 2 10:47:07 2018 +0100 Fix BZ#23400 (creating temporary files in source tree), and undefined behavior in test. (cherry picked from commit 6c3a8a9d868a8deddf0d6dcc785b6d120de90523) diff --git a/ChangeLog b/ChangeLog index 73d5c57f0d..43cc1fbc32 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2018-08-24 Paul Pluzhnikov + + [BZ #23400] + * stdlib/test-bz22786.c (do_test): Fix undefined behavior, don't + create temporary files in source tree. + 2018-10-26 Szabolcs Nagy [BZ #23822] diff --git a/NEWS b/NEWS index f4d9885819..79b028008d 100644 --- a/NEWS +++ b/NEWS @@ -10,6 +10,7 @@ Version 2.28.1 The following bugs are resolved with this release: [20209] localedata: Spelling mistake for Sunday in Greenlandic kl_GL + [23400] stdlib/test-bz22786.c creates temporary files in glibc source tree [23497] readdir64@GLIBC_2.1 cannot parse the kernel directory stream [23521] nss_files aliases database file stream leak [23538] pthread_cond_broadcast: Fix waiters-after-spinning case diff --git a/stdlib/test-bz22786.c b/stdlib/test-bz22786.c index e7837f98c1..d1aa69106c 100644 --- a/stdlib/test-bz22786.c +++ b/stdlib/test-bz22786.c @@ -26,28 +26,20 @@ #include #include #include +#include +#include +#include #include #include static int do_test (void) { - const char dir[] = "bz22786"; - const char lnk[] = "bz22786/symlink"; + const char *dir = support_create_temp_directory ("bz22786."); + const char *lnk = xasprintf ("%s/symlink", dir); + const size_t path_len = (size_t) INT_MAX + strlen (lnk) + 1; - 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; + TEST_VERIFY_EXIT (symlink (".", lnk) == 0); DIAG_PUSH_NEEDS_COMMENT; #if __GNUC_PREREQ (7, 0) @@ -55,20 +47,14 @@ do_test (void) allocation to succeed for the test to work. */ DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than="); #endif - char *path = malloc (path_len); + char *path = xmalloc (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); + /* Construct very long path = "/tmp/bz22786.XXXX/symlink/aaaa....." */ + char *p = mempcpy (path, lnk, strlen (lnk)); *(p++) = '/'; - memset (p, 'a', path_len - (path - p) - 2); - p[path_len - (path - p) - 1] = '\0'; + memset (p, 'a', path_len - (p - path) - 2); + p[path_len - (p - path) - 1] = '\0'; /* This call crashes before the fix for bz22786 on 32-bit platforms. */ p = realpath (path, NULL); @@ -81,7 +67,6 @@ do_test (void) /* Cleanup. */ unlink (lnk); - rmdir (dir); return 0; } commit d0b6db4acfba1f48b24da2c9b2a1530f6dd71503 Author: Stefan Liebler Date: Thu Aug 30 08:44:32 2018 +0200 Test stdlib/test-bz22786 exits now with unsupported if malloc fails. The test tries to allocate more than 2^31 bytes which will always fail on s390 as it has maximum 2^31bit of memory. Before commit 6c3a8a9d868a8deddf0d6dcc785b6d120de90523, this test returned unsupported if malloc fails. This patch re enables this behaviour. Furthermore support_delete_temp_files() failed to remove the temp directory in this case as it is not empty due to the created symlink. Thus the creation of the symlink is moved behind malloc. Reviewed-by: Carlos O'Donell ChangeLog: * stdlib/test-bz22786.c (do_test): Return EXIT_UNSUPPORTED if malloc fails. (cherry picked from commit 3bad2358d67d371497079bba4f8eca9c0096f4e2) diff --git a/ChangeLog b/ChangeLog index 43cc1fbc32..645e6607b2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2018-08-30 Stefan Liebler + + * stdlib/test-bz22786.c (do_test): Return EXIT_UNSUPPORTED + if malloc fails. + 2018-08-24 Paul Pluzhnikov [BZ #23400] diff --git a/stdlib/test-bz22786.c b/stdlib/test-bz22786.c index d1aa69106c..777bf9180f 100644 --- a/stdlib/test-bz22786.c +++ b/stdlib/test-bz22786.c @@ -39,16 +39,25 @@ do_test (void) const char *lnk = xasprintf ("%s/symlink", dir); const size_t path_len = (size_t) INT_MAX + strlen (lnk) + 1; - TEST_VERIFY_EXIT (symlink (".", lnk) == 0); - 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 = xmalloc (path_len); + char *path = malloc (path_len); DIAG_POP_NEEDS_COMMENT; + if (path == NULL) + { + printf ("malloc (%zu): %m\n", path_len); + /* On 31-bit s390 the malloc will always fail as we do not have + so much memory, and we want to mark the test unsupported. + Likewise on systems with little physical memory the test will + fail and should be unsupported. */ + return EXIT_UNSUPPORTED; + } + + TEST_VERIFY_EXIT (symlink (".", lnk) == 0); /* Construct very long path = "/tmp/bz22786.XXXX/symlink/aaaa....." */ char *p = mempcpy (path, lnk, strlen (lnk)); commit dcd52b94bf50f337dc4cfffa24ed86d7dfe03dc0 Author: Florian Weimer Date: Tue Oct 30 13:11:47 2018 +0100 stdlib/test-bz22786: Avoid spurious test failures using alias mappings On systems without enough random-access memory, stdlib/test-bz22786 will go deeply into swap and time out, even with a substantial TIMEOUTFACTOR. This commit adds a facility to construct repeating strings with alias mappings, so that the requirement for physical memory, and uses it in stdlib/test-bz22786. (cherry picked from commit f5e7e95921847bd83186bfe621fc2b48c4de5477) diff --git a/ChangeLog b/ChangeLog index 645e6607b2..2043b21dde 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2018-10-30 Florian Weimer + + Avoid spurious test failures in stdlib/test-bz22786. + * support/Makefile (libsupport-routines): Add blob_repeat. + (tests): Add tst-support_blob_repeat. + * support/blob_repeat.h: New file. + * support/blob_repeat.c: Likewise. + * support/tst-support_blob_repeat.c: Likewise. + * stdlib/test-bz22786.c (do_test): Replace malloc and memset with + support_blob_repeat_allocate. + 2018-08-30 Stefan Liebler * stdlib/test-bz22786.c (do_test): Return EXIT_UNSUPPORTED diff --git a/stdlib/test-bz22786.c b/stdlib/test-bz22786.c index 777bf9180f..bb1e04f2de 100644 --- a/stdlib/test-bz22786.c +++ b/stdlib/test-bz22786.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -39,17 +40,12 @@ do_test (void) const char *lnk = xasprintf ("%s/symlink", dir); const size_t path_len = (size_t) INT_MAX + strlen (lnk) + 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; + struct support_blob_repeat repeat + = support_blob_repeat_allocate ("a", 1, path_len); + char *path = repeat.start; if (path == NULL) { - printf ("malloc (%zu): %m\n", path_len); + printf ("Repeated allocation (%zu bytes): %m\n", path_len); /* On 31-bit s390 the malloc will always fail as we do not have so much memory, and we want to mark the test unsupported. Likewise on systems with little physical memory the test will @@ -62,7 +58,6 @@ do_test (void) /* Construct very long path = "/tmp/bz22786.XXXX/symlink/aaaa....." */ char *p = mempcpy (path, lnk, strlen (lnk)); *(p++) = '/'; - memset (p, 'a', path_len - (p - path) - 2); p[path_len - (p - path) - 1] = '\0'; /* This call crashes before the fix for bz22786 on 32-bit platforms. */ @@ -76,6 +71,7 @@ do_test (void) /* Cleanup. */ unlink (lnk); + support_blob_repeat_free (&repeat); return 0; } diff --git a/support/Makefile b/support/Makefile index 652d2cdf69..50470fb749 100644 --- a/support/Makefile +++ b/support/Makefile @@ -25,6 +25,7 @@ extra-libs-others = $(extra-libs) extra-libs-noinstall := $(extra-libs) libsupport-routines = \ + blob_repeat \ check \ check_addrinfo \ check_dns_packet \ @@ -154,6 +155,7 @@ endif tests = \ README-testing \ tst-support-namespace \ + tst-support_blob_repeat \ tst-support_capture_subprocess \ tst-support_format_dns_packet \ tst-support_quote_blob \ diff --git a/support/blob_repeat.c b/support/blob_repeat.c new file mode 100644 index 0000000000..da4ca83043 --- /dev/null +++ b/support/blob_repeat.c @@ -0,0 +1,278 @@ +/* Repeating a memory blob, with alias mapping optimization. + 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 + . */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Small allocations should use malloc directly instead of the mmap + optimization because mappings carry a lot of overhead. */ +static const size_t maximum_small_size = 4 * 1024 * 1024; + +/* Internal helper for fill. */ +static void +fill0 (char *target, const char *element, size_t element_size, + size_t count) +{ + while (count > 0) + { + memcpy (target, element, element_size); + target += element_size; + --count; + } +} + +/* Fill the buffer at TARGET with COUNT copies of the ELEMENT_SIZE + bytes starting at ELEMENT. */ +static void +fill (char *target, const char *element, size_t element_size, + size_t count) +{ + if (element_size == 0 || count == 0) + return; + else if (element_size == 1) + memset (target, element[0], count); + else if (element_size == sizeof (wchar_t)) + { + wchar_t wc; + memcpy (&wc, element, sizeof (wc)); + wmemset ((wchar_t *) target, wc, count); + } + else if (element_size < 1024 && count > 4096) + { + /* Use larger copies for really small element sizes. */ + char buffer[8192]; + size_t buffer_count = sizeof (buffer) / element_size; + fill0 (buffer, element, element_size, buffer_count); + while (count > 0) + { + size_t copy_count = buffer_count; + if (copy_count > count) + copy_count = count; + size_t copy_bytes = copy_count * element_size; + memcpy (target, buffer, copy_bytes); + target += copy_bytes; + count -= copy_count; + } + } + else + fill0 (target, element, element_size, count); +} + +/* Use malloc instead of mmap for small allocations and unusual size + combinations. */ +static struct support_blob_repeat +allocate_malloc (size_t total_size, const void *element, size_t element_size, + size_t count) +{ + void *buffer = malloc (total_size); + if (buffer == NULL) + return (struct support_blob_repeat) { 0 }; + fill (buffer, element, element_size, count); + return (struct support_blob_repeat) + { + .start = buffer, + .size = total_size, + .use_malloc = true + }; +} + +/* Return the least common multiple of PAGE_SIZE and ELEMENT_SIZE, + avoiding overflow. This assumes that PAGE_SIZE is a power of + two. */ +static size_t +minimum_stride_size (size_t page_size, size_t element_size) +{ + TEST_VERIFY_EXIT (page_size > 0); + TEST_VERIFY_EXIT (element_size > 0); + + /* Compute the number of trailing zeros common to both sizes. */ + unsigned int common_zeros = __builtin_ctzll (page_size | element_size); + + /* In the product, this power of two appears twice, but in the least + common multiple, it appears only once. Therefore, shift one + factor. */ + size_t multiple; + if (__builtin_mul_overflow (page_size >> common_zeros, element_size, + &multiple)) + return 0; + return multiple; +} + +/* Allocations larger than maximum_small_size potentially use mmap + with alias mappings. */ +static struct support_blob_repeat +allocate_big (size_t total_size, const void *element, size_t element_size, + size_t count) +{ + unsigned long page_size = xsysconf (_SC_PAGESIZE); + size_t stride_size = minimum_stride_size (page_size, element_size); + if (stride_size == 0) + { + errno = EOVERFLOW; + return (struct support_blob_repeat) { 0 }; + } + + /* Ensure that the stride size is at least maximum_small_size. This + is necessary to reduce the number of distinct mappings. */ + if (stride_size < maximum_small_size) + stride_size + = ((maximum_small_size + stride_size - 1) / stride_size) * stride_size; + + if (stride_size > total_size) + /* The mmap optimization would not save anything. */ + return allocate_malloc (total_size, element, element_size, count); + + /* Reserve the memory region. If we cannot create the mapping, + there is no reason to set up the backing file. */ + void *target = mmap (NULL, total_size, PROT_NONE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + if (target == MAP_FAILED) + return (struct support_blob_repeat) { 0 }; + + /* Create the backing file for the repeated mapping. */ + int fd; + { + char *temppath; + fd = create_temp_file ("support_blob_repeat-", &temppath); + if (fd < 0) + FAIL_EXIT1 ("create_temp_file: %m"); + xunlink (temppath); + free (temppath); + } + + /* Make sure that there is backing storage, so that the fill + operation will not fault. */ + if (posix_fallocate (fd, 0, stride_size) != 0) + FAIL_EXIT1 ("posix_fallocate (%zu): %m", stride_size); + + /* The stride size must still be a multiple of the page size and + element size. */ + TEST_VERIFY_EXIT ((stride_size % page_size) == 0); + TEST_VERIFY_EXIT ((stride_size % element_size) == 0); + + /* Fill the backing store. */ + { + void *ptr = mmap (target, stride_size, PROT_READ | PROT_WRITE, + MAP_FIXED | MAP_FILE | MAP_SHARED, fd, 0); + if (ptr == MAP_FAILED) + { + int saved_errno = errno; + xmunmap (target, total_size); + xclose (fd); + errno = saved_errno; + return (struct support_blob_repeat) { 0 }; + } + if (ptr != target) + FAIL_EXIT1 ("mapping of %zu bytes moved from %p to %p", + stride_size, target, ptr); + + /* Write the repeating data. */ + fill (target, element, element_size, stride_size / element_size); + + /* Return to a PROT_NONE mapping, just to be on the safe side. */ + ptr = mmap (target, stride_size, PROT_NONE, + MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + if (ptr == MAP_FAILED) + FAIL_EXIT1 ("Failed to reinstate PROT_NONE mapping: %m"); + if (ptr != target) + FAIL_EXIT1 ("PROT_NONE mapping of %zu bytes moved from %p to %p", + stride_size, target, ptr); + } + + /* Create the alias mappings. */ + { + size_t remaining_size = total_size; + char *current = target; + int flags = MAP_FIXED | MAP_FILE | MAP_PRIVATE; +#ifdef MAP_NORESERVE + flags |= MAP_NORESERVE; +#endif + while (remaining_size > 0) + { + size_t to_map = stride_size; + if (to_map > remaining_size) + to_map = remaining_size; + void *ptr = mmap (current, to_map, PROT_READ | PROT_WRITE, + flags, fd, 0); + if (ptr == MAP_FAILED) + { + int saved_errno = errno; + xmunmap (target, total_size); + xclose (fd); + errno = saved_errno; + return (struct support_blob_repeat) { 0 }; + } + if (ptr != current) + FAIL_EXIT1 ("MAP_PRIVATE mapping of %zu bytes moved from %p to %p", + to_map, target, ptr); + remaining_size -= to_map; + current += to_map; + } + } + + xclose (fd); + + return (struct support_blob_repeat) + { + .start = target, + .size = total_size, + .use_malloc = false + }; +} + +struct support_blob_repeat +support_blob_repeat_allocate (const void *element, size_t element_size, + size_t count) +{ + size_t total_size; + if (__builtin_mul_overflow (element_size, count, &total_size)) + { + errno = EOVERFLOW; + return (struct support_blob_repeat) { 0 }; + } + if (total_size <= maximum_small_size) + return allocate_malloc (total_size, element, element_size, count); + else + return allocate_big (total_size, element, element_size, count); +} + +void +support_blob_repeat_free (struct support_blob_repeat *blob) +{ + if (blob->size > 0) + { + int saved_errno = errno; + if (blob->use_malloc) + free (blob->start); + else + xmunmap (blob->start, blob->size); + errno = saved_errno; + } + *blob = (struct support_blob_repeat) { 0 }; +} diff --git a/support/blob_repeat.h b/support/blob_repeat.h new file mode 100644 index 0000000000..8e9d7ff5f1 --- /dev/null +++ b/support/blob_repeat.h @@ -0,0 +1,44 @@ +/* Repeating a memory blob, with alias mapping optimization. + 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 + . */ + +#ifndef SUPPORT_BLOB_REPEAT_H +#define SUPPORT_BLOB_REPEAT_H + +#include +#include + +struct support_blob_repeat +{ + void *start; + size_t size; + bool use_malloc; +}; + +/* Return an allocation of COUNT elements, each of ELEMENT_SIZE bytes, + initialized with the bytes starting at ELEMENT. The memory is + writable (and thus counts towards the commit charge). In case of + on error, all members of the return struct are zero-initialized, + and errno is set accordingly. */ +struct support_blob_repeat support_blob_repeat_allocate (const void *element, + size_t element_size, + size_t count); + +/* Deallocate the blob created by support_blob_repeat_allocate. */ +void support_blob_repeat_free (struct support_blob_repeat *); + +#endif /* SUPPORT_BLOB_REPEAT_H */ diff --git a/support/tst-support_blob_repeat.c b/support/tst-support_blob_repeat.c new file mode 100644 index 0000000000..1978c14488 --- /dev/null +++ b/support/tst-support_blob_repeat.c @@ -0,0 +1,85 @@ +/* Tests for + 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 + . */ + +#include +#include +#include + +static int +do_test (void) +{ + struct support_blob_repeat repeat + = support_blob_repeat_allocate ("5", 1, 5); + TEST_COMPARE_BLOB (repeat.start, repeat.size, "55555", 5); + support_blob_repeat_free (&repeat); + + repeat = support_blob_repeat_allocate ("ABC", 3, 3); + TEST_COMPARE_BLOB (repeat.start, repeat.size, "ABCABCABC", 9); + support_blob_repeat_free (&repeat); + + repeat = support_blob_repeat_allocate ("abc", 4, 3); + TEST_COMPARE_BLOB (repeat.start, repeat.size, "abc\0abc\0abc", 12); + support_blob_repeat_free (&repeat); + + size_t gigabyte = 1U << 30; + repeat = support_blob_repeat_allocate ("X", 1, gigabyte + 1); + if (repeat.start == NULL) + puts ("warning: not enough memory for 1 GiB mapping"); + else + { + TEST_COMPARE (repeat.size, gigabyte + 1); + { + unsigned char *p = repeat.start; + for (size_t i = 0; i < gigabyte + 1; ++i) + if (p[i] != 'X') + FAIL_EXIT1 ("invalid byte 0x%02x at %zu", p[i], i); + + /* Check that there is no sharing across the mapping. */ + p[0] = 'Y'; + p[1U << 24] = 'Z'; + for (size_t i = 0; i < gigabyte + 1; ++i) + if (i == 0) + TEST_COMPARE (p[i], 'Y'); + else if (i == 1U << 24) + TEST_COMPARE (p[i], 'Z'); + else if (p[i] != 'X') + FAIL_EXIT1 ("invalid byte 0x%02x at %zu", p[i], i); + } + } + support_blob_repeat_free (&repeat); + + repeat = support_blob_repeat_allocate ("012345678", 9, 10 * 1000 * 1000); + if (repeat.start == NULL) + puts ("warning: not enough memory for large mapping"); + else + { + unsigned char *p = repeat.start; + for (int i = 0; i < 10 * 1000 * 1000; ++i) + for (int j = 0; j <= 8; ++j) + if (p[i * 9 + j] != '0' + j) + { + printf ("error: element %d index %d\n", i, j); + TEST_COMPARE (p[i * 9 + j], '0' + j); + } + } + support_blob_repeat_free (&repeat); + + return 0; +} + +#include commit 69dcd992a0efdb53bc2ea4948cfc6b13416b9636 Author: Florian Weimer Date: Tue Oct 30 13:56:40 2018 +0100 stdlib/test-bz22786: Avoid memory leaks in the test itself (cherry picked from commit 60708030536df82616c16aa2f14f533c4362b969) diff --git a/ChangeLog b/ChangeLog index 2043b21dde..a2a9fc3cc9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2018-10-30 Florian Weimer + + * stdlib/test-bz22786.c (do_test): Additional free calls to avoid + memory leaks. + 2018-10-30 Florian Weimer Avoid spurious test failures in stdlib/test-bz22786. diff --git a/stdlib/test-bz22786.c b/stdlib/test-bz22786.c index bb1e04f2de..8035e8a394 100644 --- a/stdlib/test-bz22786.c +++ b/stdlib/test-bz22786.c @@ -36,8 +36,8 @@ static int do_test (void) { - const char *dir = support_create_temp_directory ("bz22786."); - const char *lnk = xasprintf ("%s/symlink", dir); + char *dir = support_create_temp_directory ("bz22786."); + char *lnk = xasprintf ("%s/symlink", dir); const size_t path_len = (size_t) INT_MAX + strlen (lnk) + 1; struct support_blob_repeat repeat @@ -72,6 +72,8 @@ do_test (void) /* Cleanup. */ unlink (lnk); support_blob_repeat_free (&repeat); + free (lnk); + free (dir); return 0; } commit 6c2b6e9e2758b7491ce89920a8711c1b41100269 Author: Florian Weimer Date: Tue Oct 30 13:55:50 2018 +0100 support_blob_repeat: Call mkstemp directory for the backing file This avoids a warning during post-test cleanup. (cherry picked from commit a91e9301c47bb688f4e496a19cfc68261ff18293) diff --git a/ChangeLog b/ChangeLog index a2a9fc3cc9..b4c48644ae 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2018-10-30 Florian Weimer + + * support/blob_repeat.c (allocate_big): Call mkstemp directly. + 2018-10-30 Florian Weimer * stdlib/test-bz22786.c (do_test): Additional free calls to avoid diff --git a/support/blob_repeat.c b/support/blob_repeat.c index da4ca83043..16c1e448b9 100644 --- a/support/blob_repeat.c +++ b/support/blob_repeat.c @@ -23,8 +23,8 @@ #include #include #include +#include #include -#include #include #include #include @@ -155,13 +155,17 @@ allocate_big (size_t total_size, const void *element, size_t element_size, if (target == MAP_FAILED) return (struct support_blob_repeat) { 0 }; - /* Create the backing file for the repeated mapping. */ + /* Create the backing file for the repeated mapping. Call mkstemp + directly to remove the resources backing the temporary file + immediately, once support_blob_repeat_free is called. Using + create_temp_file would result in a warning during post-test + cleanup. */ int fd; { - char *temppath; - fd = create_temp_file ("support_blob_repeat-", &temppath); + char *temppath = xasprintf ("%s/support_blob_repeat-XXXXXX", test_dir); + fd = mkstemp (temppath); if (fd < 0) - FAIL_EXIT1 ("create_temp_file: %m"); + FAIL_EXIT1 ("mkstemp (\"%s\"): %m", temppath); xunlink (temppath); free (temppath); } commit e1af1df694603c0dcd5118c30eea2cdeb01a1a0b Author: Florian Weimer Date: Tue Oct 30 13:55:01 2018 +0100 stdlib/tst-strtod-overflow: Switch to support_blob_repeat This is another test with an avoidable large memory allocation. (cherry picked from commit 07da99aad93c9364acb7efdab47c27ba698f6313) diff --git a/ChangeLog b/ChangeLog index b4c48644ae..51a8f488d9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2018-10-30 Florian Weimer + + * stdlib/tst-strtod-overflow.c (do_test): Switch to + support_blob_repeat. + 2018-10-30 Florian Weimer * support/blob_repeat.c (allocate_big): Call mkstemp directly. diff --git a/stdlib/tst-strtod-overflow.c b/stdlib/tst-strtod-overflow.c index d14638d68e..dc53c1e521 100644 --- a/stdlib/tst-strtod-overflow.c +++ b/stdlib/tst-strtod-overflow.c @@ -19,6 +19,8 @@ #include #include #include +#include +#include #define EXPONENT "e-2147483649" #define SIZE 214748364 @@ -26,21 +28,23 @@ static int do_test (void) { - char *p = malloc (1 + SIZE + sizeof (EXPONENT)); - if (p == NULL) + struct support_blob_repeat repeat = support_blob_repeat_allocate + ("0", 1, 1 + SIZE + sizeof (EXPONENT)); + if (repeat.size == 0) { - puts ("malloc failed, cannot test for overflow"); - return 0; + puts ("warning: memory allocation failed, cannot test for overflow"); + return EXIT_UNSUPPORTED; } + char *p = repeat.start; p[0] = '1'; - memset (p + 1, '0', SIZE); memcpy (p + 1 + SIZE, EXPONENT, sizeof (EXPONENT)); double d = strtod (p, NULL); if (d != 0) { - printf ("strtod returned wrong value: %a\n", d); + printf ("error: strtod returned wrong value: %a\n", d); return 1; } + support_blob_repeat_free (&repeat); return 0; } commit 65010329f2c596bdd1204c1c9c9baac0193637af Author: Adhemerval Zanella Date: Fri Nov 2 10:56:00 2018 +0100 x86: Fix Haswell CPU string flags (BZ#23709) Th commit 'Disable TSX on some Haswell processors.' (2702856bf4) changed the default flags for Haswell models. Previously, new models were handled by the default switch path, which assumed a Core i3/i5/i7 if AVX is available. After the patch, Haswell models (0x3f, 0x3c, 0x45, 0x46) do not set the flags Fast_Rep_String, Fast_Unaligned_Load, Fast_Unaligned_Copy, and Prefer_PMINUB_for_stringop (only the TSX one). This patch fixes it by disentangle the TSX flag handling from the memory optimization ones. The strstr case cited on patch now selects the __strstr_sse2_unaligned as expected for the Haswell cpu. Checked on x86_64-linux-gnu. [BZ #23709] * sysdeps/x86/cpu-features.c (init_cpu_features): Set TSX bits independently of other flags. (cherry picked from commit c3d8dc45c9df199b8334599a6cbd98c9950dba62) diff --git a/ChangeLog b/ChangeLog index 51a8f488d9..d558df58af 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2018-10-23 Adhemerval Zanella + + [BZ #23709] + * sysdeps/x86/cpu-features.c (init_cpu_features): Set TSX bits + independently of other flags. + 2018-10-30 Florian Weimer * stdlib/tst-strtod-overflow.c (do_test): Switch to diff --git a/NEWS b/NEWS index 79b028008d..f3004915f2 100644 --- a/NEWS +++ b/NEWS @@ -19,6 +19,7 @@ The following bugs are resolved with this release: [23579] libc: Errors misreported in preadv2 [23606] Missing ENDBR32 in sysdeps/i386/start.S [23679] gethostid: Missing NULL check for gethostbyname_r result + [23709] Fix CPU string flags for Haswell-type CPUs [23717] Fix stack overflow in stdlib/tst-setcontext9 [23821] si_band in siginfo_t has wrong type long int on sparc64 [23822] ia64 static libm.a is missing exp2f, log2f and powf symbols diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c index ea0b64fdb9..4695ac80d4 100644 --- a/sysdeps/x86/cpu-features.c +++ b/sysdeps/x86/cpu-features.c @@ -316,7 +316,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) commit fc0e3393ff775aa795b523083bb0db7f18d3b91e Author: Andreas Schwab Date: Tue Nov 6 16:12:07 2018 +0100 libanl: properly cleanup if first helper thread creation failed (bug 22927) (cherry picked from commit bd3b0fbae33a9a4cc5e2daf049443d5cf03d4251) diff --git a/ChangeLog b/ChangeLog index d558df58af..db4ac3b76a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2018-11-05 Andreas Schwab + + [BZ #22927] + * resolv/gai_misc.c (__gai_enqueue_request): Don't crash if + creating the first helper thread failed. + 2018-10-23 Adhemerval Zanella [BZ #23709] diff --git a/NEWS b/NEWS index f3004915f2..b85be4a9c1 100644 --- a/NEWS +++ b/NEWS @@ -10,6 +10,7 @@ Version 2.28.1 The following bugs are resolved with this release: [20209] localedata: Spelling mistake for Sunday in Greenlandic kl_GL + [22927] libanl: properly cleanup if first helper thread creation failed [23400] stdlib/test-bz22786.c creates temporary files in glibc source tree [23497] readdir64@GLIBC_2.1 cannot parse the kernel directory stream [23521] nss_files aliases database file stream leak diff --git a/resolv/gai_misc.c b/resolv/gai_misc.c index e7c3b63cc5..80a2cff835 100644 --- a/resolv/gai_misc.c +++ b/resolv/gai_misc.c @@ -261,8 +261,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; commit 3e8d8dd5afba18a847ff7a80f473336f777cc329 Author: H.J. Lu Date: Thu Nov 8 10:06:58 2018 -0800 Check multiple NT_GNU_PROPERTY_TYPE_0 notes [BZ #23509] Linkers group input note sections with the same name into one output note section with the same name. One output note section is placed in one PT_NOTE segment. Since new linkers merge input .note.gnu.property sections into one output .note.gnu.property section, there is only one NT_GNU_PROPERTY_TYPE_0 note in one PT_NOTE segment with new linkers. Since older linkers treat input .note.gnu.property section as a generic note section and just concatenate all input .note.gnu.property sections into one output .note.gnu.property section without merging them, we may see multiple NT_GNU_PROPERTY_TYPE_0 notes in one PT_NOTE segment with older linkers. When an older linker is used to created the program on CET-enabled OS, the linker output has a single .note.gnu.property section with multiple NT_GNU_PROPERTY_TYPE_0 notes, some of which have IBT and SHSTK enable bits set even if the program isn't CET enabled. Such programs will crash on CET-enabled machines. This patch updates the note parser: 1. Skip note parsing if a NT_GNU_PROPERTY_TYPE_0 note has been processed. 2. Check multiple NT_GNU_PROPERTY_TYPE_0 notes. [BZ #23509] * sysdeps/x86/dl-prop.h (_dl_process_cet_property_note): Skip note parsing if a NT_GNU_PROPERTY_TYPE_0 note has been processed. Update the l_cet field when processing NT_GNU_PROPERTY_TYPE_0 note. Check multiple NT_GNU_PROPERTY_TYPE_0 notes. * sysdeps/x86/link_map.h (l_cet): Expand to 3 bits, Add lc_unknown. (cherry picked from commit d524fa6c35e675eedbd8fe6cdf4db0b49c658026) diff --git a/ChangeLog b/ChangeLog index db4ac3b76a..86bdf17989 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2018-11-08 H.J. Lu + + [BZ #23509] + * sysdeps/x86/dl-prop.h (_dl_process_cet_property_note): Skip + note parsing if a NT_GNU_PROPERTY_TYPE_0 note has been processed. + Update the l_cet field when processing NT_GNU_PROPERTY_TYPE_0 note. + Check multiple NT_GNU_PROPERTY_TYPE_0 notes. + * sysdeps/x86/link_map.h (l_cet): Expand to 3 bits, Add + lc_unknown. + 2018-11-05 Andreas Schwab [BZ #22927] diff --git a/NEWS b/NEWS index b85be4a9c1..e5ca5903ec 100644 --- a/NEWS +++ b/NEWS @@ -13,6 +13,7 @@ The following bugs are resolved with this release: [22927] libanl: properly cleanup if first helper thread creation failed [23400] stdlib/test-bz22786.c creates temporary files in glibc source tree [23497] readdir64@GLIBC_2.1 cannot parse the kernel directory stream + [23509] CET enabled glibc is incompatible with the older linker [23521] nss_files aliases database file stream leak [23538] pthread_cond_broadcast: Fix waiters-after-spinning case [23562] signal: Use correct type for si_band in siginfo_t diff --git a/sysdeps/x86/dl-prop.h b/sysdeps/x86/dl-prop.h index 26c3131ac5..9ab890d12b 100644 --- a/sysdeps/x86/dl-prop.h +++ b/sysdeps/x86/dl-prop.h @@ -49,6 +49,10 @@ _dl_process_cet_property_note (struct link_map *l, const ElfW(Addr) align) { #if CET_ENABLED + /* Skip if we have seen a NT_GNU_PROPERTY_TYPE_0 note before. */ + if (l->l_cet != lc_unknown) + return; + /* The NT_GNU_PROPERTY_TYPE_0 note must be aliged to 4 bytes in 32-bit objects and to 8 bytes in 64-bit objects. Skip notes with incorrect alignment. */ @@ -57,6 +61,9 @@ _dl_process_cet_property_note (struct link_map *l, const ElfW(Addr) start = (ElfW(Addr)) note; + unsigned int feature_1 = 0; + unsigned int last_type = 0; + while ((ElfW(Addr)) (note + 1) - start < size) { /* Find the NT_GNU_PROPERTY_TYPE_0 note. */ @@ -64,10 +71,18 @@ _dl_process_cet_property_note (struct link_map *l, && note->n_type == NT_GNU_PROPERTY_TYPE_0 && memcmp (note + 1, "GNU", 4) == 0) { + /* Stop if we see more than one GNU property note which may + be generated by the older linker. */ + if (l->l_cet != lc_unknown) + return; + + /* Check CET status now. */ + l->l_cet = lc_none; + /* Check for invalid property. */ if (note->n_descsz < 8 || (note->n_descsz % sizeof (ElfW(Addr))) != 0) - break; + return; /* Start and end of property array. */ unsigned char *ptr = (unsigned char *) (note + 1) + 4; @@ -78,9 +93,15 @@ _dl_process_cet_property_note (struct link_map *l, unsigned int type = *(unsigned int *) ptr; unsigned int datasz = *(unsigned int *) (ptr + 4); + /* Property type must be in ascending order. */ + if (type < last_type) + return; + ptr += 8; if ((ptr + datasz) > ptr_end) - break; + return; + + last_type = type; if (type == GNU_PROPERTY_X86_FEATURE_1_AND) { @@ -89,14 +110,18 @@ _dl_process_cet_property_note (struct link_map *l, we stop the search regardless if its size is correct or not. There is no point to continue if this note is ill-formed. */ - if (datasz == 4) - { - unsigned int feature_1 = *(unsigned int *) ptr; - if ((feature_1 & GNU_PROPERTY_X86_FEATURE_1_IBT)) - l->l_cet |= lc_ibt; - if ((feature_1 & GNU_PROPERTY_X86_FEATURE_1_SHSTK)) - l->l_cet |= lc_shstk; - } + if (datasz != 4) + return; + + feature_1 = *(unsigned int *) ptr; + + /* Keep searching for the next GNU property note + generated by the older linker. */ + break; + } + else if (type > GNU_PROPERTY_X86_FEATURE_1_AND) + { + /* Stop since property type is in ascending order. */ return; } @@ -112,6 +137,12 @@ _dl_process_cet_property_note (struct link_map *l, + ELF_NOTE_NEXT_OFFSET (note->n_namesz, note->n_descsz, align)); } + + /* We get here only if there is one or no GNU property note. */ + if ((feature_1 & GNU_PROPERTY_X86_FEATURE_1_IBT)) + l->l_cet |= lc_ibt; + if ((feature_1 & GNU_PROPERTY_X86_FEATURE_1_SHSTK)) + l->l_cet |= lc_shstk; #endif } diff --git a/sysdeps/x86/link_map.h b/sysdeps/x86/link_map.h index ef1206a9d2..9367ed0889 100644 --- a/sysdeps/x86/link_map.h +++ b/sysdeps/x86/link_map.h @@ -19,8 +19,9 @@ /* If this object is enabled with CET. */ enum { - lc_none = 0, /* Not enabled with CET. */ - lc_ibt = 1 << 0, /* Enabled with IBT. */ - lc_shstk = 1 << 1, /* Enabled with STSHK. */ + lc_unknown = 0, /* Unknown CET status. */ + lc_none = 1 << 0, /* Not enabled with CET. */ + lc_ibt = 1 << 1, /* Enabled with IBT. */ + lc_shstk = 1 << 2, /* Enabled with STSHK. */ lc_ibt_and_shstk = lc_ibt | lc_shstk /* Enabled with both. */ - } l_cet:2; + } l_cet:3; commit b21abc069f58da3f8e556ec730f0a387cfc91f5f Author: Alexandra Hájková Date: Fri Oct 19 13:30:44 2018 +0200 Add an additional test to resolv/tst-resolv-network.c Test for the infinite loop in getnetbyname, bug #17630. (cherry picked from commit ac8060265bcaca61568ef3a20b9a0140a270af54) diff --git a/ChangeLog b/ChangeLog index 86bdf17989..d020aff979 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2018-11-08 Alexandra Hájková + + [BZ #17630] + * resolv/tst-resolv-network.c: Add test for getnetbyname. + 2018-11-08 H.J. Lu [BZ #23509] diff --git a/resolv/tst-resolv-network.c b/resolv/tst-resolv-network.c index 4b862d57e6..735e38d0f8 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 @@ do_test (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, commit 168035056eab9db4ee0e5d7f62060e111b86a0a4 Author: Joseph Myers Date: Mon Aug 13 21:35:27 2018 +0000 Update syscall-names.list for Linux 4.18. This patch updates sysdeps/unix/sysv/linux/syscall-names.list for Linux 4.18. The io_pgetevents and rseq syscalls are added to the kernel on various architectures, so need to be mentioned in this file. Tested with build-many-glibcs.py. * sysdeps/unix/sysv/linux/syscall-names.list: Update kernel version to 4.18. (io_pgetevents): New syscall. (rseq): Likewise. (cherry picked from commit 17b26500f9bb926d85e86821d014f7c1bb88043c) diff --git a/ChangeLog b/ChangeLog index d020aff979..88814e6947 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2018-08-13 Joseph Myers + + * sysdeps/unix/sysv/linux/syscall-names.list: Update kernel + version to 4.18. + (io_pgetevents): New syscall. + (rseq): Likewise. + 2018-11-08 Alexandra Hájková [BZ #17630] diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list index 5306d538e6..9982a6334d 100644 --- a/sysdeps/unix/sysv/linux/syscall-names.list +++ b/sysdeps/unix/sysv/linux/syscall-names.list @@ -22,8 +22,8 @@ # names are only used if the installed kernel headers also provide # them. -# The list of system calls is current as of Linux 4.17. -kernel 4.17 +# The list of system calls is current as of Linux 4.18. +kernel 4.18 FAST_atomic_update FAST_cmpxchg @@ -186,6 +186,7 @@ inotify_rm_watch io_cancel io_destroy io_getevents +io_pgetevents io_setup io_submit ioctl @@ -431,6 +432,7 @@ renameat2 request_key restart_syscall rmdir +rseq rt_sigaction rt_sigpending rt_sigprocmask commit 510a25f2d208e3b0c86f54b053f61c5b647e4b9b Author: Pochang Chen Date: Thu Aug 16 15:24:24 2018 -0400 malloc: Verify size of top chunk. The House of Force is a well-known technique to exploit heap overflow. In essence, this exploit takes three steps: 1. Overwrite the size of top chunk with very large value (e.g. -1). 2. Request x bytes from top chunk. As the size of top chunk is corrupted, x can be arbitrarily large and top chunk will still be offset by x. 3. The next allocation from top chunk will thus be controllable. If we verify the size of top chunk at step 2, we can stop such attack. (cherry picked from commit 30a17d8c95fbfb15c52d1115803b63aaa73a285c) diff --git a/ChangeLog b/ChangeLog index 88814e6947..44795b2e61 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2018-08-16 Pochang Chen + + * malloc/malloc.c (_int_malloc.c): Verify size of top chunk. + 2018-08-13 Joseph Myers * sysdeps/unix/sysv/linux/syscall-names.list: Update kernel diff --git a/malloc/malloc.c b/malloc/malloc.c index e247c77b7d..9431108626 100644 --- a/malloc/malloc.c +++ b/malloc/malloc.c @@ -4076,6 +4076,9 @@ _int_malloc (mstate av, size_t bytes) victim = av->top; size = chunksize (victim); + if (__glibc_unlikely (size > av->system_mem)) + malloc_printerr ("malloc(): corrupted top size"); + if ((unsigned long) (size) >= (unsigned long) (nb + MINSIZE)) { remainder_size = size - nb; commit 7e40c3f804b5d5dbbc0519565b16101ab22fb899 Author: Moritz Eckert Date: Thu Aug 16 21:08:36 2018 -0400 malloc: Mitigate null-byte overflow attacks * malloc/malloc.c (_int_free): Check for corrupt prev_size vs size. (malloc_consolidate): Likewise. (cherry picked from commit d6db68e66dff25d12c3bc5641b60cbd7fb6ab44f) diff --git a/ChangeLog b/ChangeLog index 44795b2e61..e81991066e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2018-08-16 DJ Delorie + + * malloc/malloc.c (_int_free): Check for corrupt prev_size vs size. + (malloc_consolidate): Likewise. + 2018-08-16 Pochang Chen * malloc/malloc.c (_int_malloc.c): Verify size of top chunk. diff --git a/malloc/malloc.c b/malloc/malloc.c index 9431108626..7c8bf8413c 100644 --- a/malloc/malloc.c +++ b/malloc/malloc.c @@ -4281,6 +4281,8 @@ _int_free (mstate av, mchunkptr p, int have_lock) prevsize = prev_size (p); size += prevsize; p = chunk_at_offset(p, -((long) prevsize)); + if (__glibc_unlikely (chunksize(p) != prevsize)) + malloc_printerr ("corrupted size vs. prev_size while consolidating"); unlink(av, p, bck, fwd); } @@ -4442,6 +4444,8 @@ static void malloc_consolidate(mstate av) prevsize = prev_size (p); size += prevsize; p = chunk_at_offset(p, -((long) prevsize)); + if (__glibc_unlikely (chunksize(p) != prevsize)) + malloc_printerr ("corrupted size vs. prev_size in fastbins"); unlink(av, p, bck, fwd); } commit 53a7e59405cbbbd24c1cf64b0298a9e6212a82e2 Author: Istvan Kurucsai Date: Tue Jan 16 14:54:32 2018 +0100 malloc: Additional checks for unsorted bin integrity I. On Thu, Jan 11, 2018 at 3:50 PM, Florian Weimer wrote: > On 11/07/2017 04:27 PM, Istvan Kurucsai wrote: >> >> + next = chunk_at_offset (victim, size); > > > For new code, we prefer declarations with initializers. Noted. >> + if (__glibc_unlikely (chunksize_nomask (victim) <= 2 * SIZE_SZ) >> + || __glibc_unlikely (chunksize_nomask (victim) > >> av->system_mem)) >> + malloc_printerr("malloc(): invalid size (unsorted)"); >> + if (__glibc_unlikely (chunksize_nomask (next) < 2 * SIZE_SZ) >> + || __glibc_unlikely (chunksize_nomask (next) > >> av->system_mem)) >> + malloc_printerr("malloc(): invalid next size (unsorted)"); >> + if (__glibc_unlikely ((prev_size (next) & ~(SIZE_BITS)) != >> size)) >> + malloc_printerr("malloc(): mismatching next->prev_size >> (unsorted)"); > > > I think this check is redundant because prev_size (next) and chunksize > (victim) are loaded from the same memory location. I'm fairly certain that it compares mchunk_size of victim against mchunk_prev_size of the next chunk, i.e. the size of victim in its header and footer. >> + if (__glibc_unlikely (bck->fd != victim) >> + || __glibc_unlikely (victim->fd != unsorted_chunks (av))) >> + malloc_printerr("malloc(): unsorted double linked list >> corrupted"); >> + if (__glibc_unlikely (prev_inuse(next))) >> + malloc_printerr("malloc(): invalid next->prev_inuse >> (unsorted)"); > > > There's a missing space after malloc_printerr. Noted. > Why do you keep using chunksize_nomask? We never investigated why the > original code uses it. It may have been an accident. You are right, I don't think it makes a difference in these checks. So the size local can be reused for the checks against victim. For next, leaving it as such avoids the masking operation. > Again, for non-main arenas, the checks against av->system_mem could be made > tighter (against the heap size). Maybe you could put the condition into a > separate inline function? We could also do a chunk boundary check similar to what I proposed in the thread for the first patch in the series to be even more strict. I'll gladly try to implement either but believe that refining these checks would bring less benefits than in the case of the top chunk. Intra-arena or intra-heap overlaps would still be doable here with unsorted chunks and I don't see any way to counter that besides more generic measures like randomizing allocations and your metadata encoding patches. I've attached a revised version with the above comments incorporated but without the refined checks. Thanks, Istvan From a12d5d40fd7aed5fa10fc444dcb819947b72b315 Mon Sep 17 00:00:00 2001 From: Istvan Kurucsai Date: Tue, 16 Jan 2018 14:48:16 +0100 Subject: [PATCH v2 1/1] malloc: Additional checks for unsorted bin integrity I. Ensure the following properties of chunks encountered during binning: - victim chunk has reasonable size - next chunk has reasonable size - next->prev_size == victim->size - valid double linked list - PREV_INUSE of next chunk is unset * malloc/malloc.c (_int_malloc): Additional binning code checks. (cherry picked from commit b90ddd08f6dd688e651df9ee89ca3a69ff88cd0c) diff --git a/malloc/malloc.c b/malloc/malloc.c index 7c8bf8413c..47795601c8 100644 --- a/malloc/malloc.c +++ b/malloc/malloc.c @@ -3716,11 +3716,22 @@ _int_malloc (mstate av, size_t bytes) while ((victim = unsorted_chunks (av)->bk) != unsorted_chunks (av)) { bck = victim->bk; - if (__builtin_expect (chunksize_nomask (victim) <= 2 * SIZE_SZ, 0) - || __builtin_expect (chunksize_nomask (victim) - > av->system_mem, 0)) - malloc_printerr ("malloc(): memory corruption"); size = chunksize (victim); + mchunkptr next = chunk_at_offset (victim, size); + + if (__glibc_unlikely (size <= 2 * SIZE_SZ) + || __glibc_unlikely (size > av->system_mem)) + malloc_printerr ("malloc(): invalid size (unsorted)"); + if (__glibc_unlikely (chunksize_nomask (next) < 2 * SIZE_SZ) + || __glibc_unlikely (chunksize_nomask (next) > av->system_mem)) + malloc_printerr ("malloc(): invalid next size (unsorted)"); + if (__glibc_unlikely ((prev_size (next) & ~(SIZE_BITS)) != size)) + malloc_printerr ("malloc(): mismatching next->prev_size (unsorted)"); + if (__glibc_unlikely (bck->fd != victim) + || __glibc_unlikely (victim->fd != unsorted_chunks (av))) + malloc_printerr ("malloc(): unsorted double linked list corrupted"); + if (__glibc_unlikely (prev_inuse(next))) + malloc_printerr ("malloc(): invalid next->prev_inuse (unsorted)"); /* If a small request, try to use last remainder if it is the commit 7d174f53539bfbfa9cdfa41ead605573d3f219eb Author: Florian Weimer Date: Tue Aug 28 13:19:27 2018 +0200 nscd: Fix use-after-free in addgetnetgrentX [BZ #23520] addinnetgrX may use the heap-allocated buffer, so free the buffer in this function. (cherry picked from commit 745664bd798ec8fd50438605948eea594179fba1) diff --git a/ChangeLog b/ChangeLog index e81991066e..79d303e7b6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2018-08-28 Florian Weimer + + [BZ #23520] + nscd: Fix use-after-free in addgetnetgrentX and its callers. + * nscd/netgroupcache.c + (addgetnetgrentX): Add tofreep parameter. Do not free + heap-allocated buffer. + (addinnetgrX): Free buffer allocated bt addgetnetgrentX. + (addgetnetgrentX_ignore): New function. + (addgetnetgrent): Call it. + (readdgetnetgrent): Likewise. + 2018-08-16 DJ Delorie * malloc/malloc.c (_int_free): Check for corrupt prev_size vs size. diff --git a/nscd/netgroupcache.c b/nscd/netgroupcache.c index 2b35389cc8..87059fb280 100644 --- a/nscd/netgroupcache.c +++ b/nscd/netgroupcache.c @@ -113,7 +113,8 @@ do_notfound (struct database_dyn *db, int fd, request_header *req, static time_t addgetnetgrentX (struct database_dyn *db, int fd, request_header *req, const char *key, uid_t uid, struct hashentry *he, - struct datahead *dh, struct dataset **resultp) + struct datahead *dh, struct dataset **resultp, + void **tofreep) { if (__glibc_unlikely (debug_level > 0)) { @@ -139,6 +140,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req, size_t group_len = strlen (key) + 1; struct name_list *first_needed = alloca (sizeof (struct name_list) + group_len); + *tofreep = NULL; if (netgroup_database == NULL && __nss_database_lookup ("netgroup", NULL, NULL, &netgroup_database)) @@ -151,6 +153,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req, memset (&data, '\0', sizeof (data)); buffer = xmalloc (buflen); + *tofreep = buffer; first_needed->next = first_needed; memcpy (first_needed->name, key, group_len); data.needed_groups = first_needed; @@ -439,8 +442,6 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req, } out: - free (buffer); - *resultp = dataset; return timeout; @@ -477,8 +478,12 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req, group, group_len, db, uid); time_t timeout; + void *tofree; if (result != NULL) - timeout = result->head.timeout; + { + timeout = result->head.timeout; + tofree = NULL; + } else { request_header req_get = @@ -487,7 +492,7 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req, .key_len = group_len }; timeout = addgetnetgrentX (db, -1, &req_get, group, uid, NULL, NULL, - &result); + &result, &tofree); } struct indataset @@ -560,7 +565,7 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req, ++dh->nreloads; if (cacheable) pthread_rwlock_unlock (&db->lock); - return timeout; + goto out; } if (he == NULL) @@ -596,17 +601,30 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req, dh->usable = false; } + out: + free (tofree); return timeout; } +static time_t +addgetnetgrentX_ignore (struct database_dyn *db, int fd, request_header *req, + const char *key, uid_t uid, struct hashentry *he, + struct datahead *dh) +{ + struct dataset *ignore; + void *tofree; + time_t timeout = addgetnetgrentX (db, fd, req, key, uid, he, dh, + &ignore, &tofree); + free (tofree); + return timeout; +} + void addgetnetgrent (struct database_dyn *db, int fd, request_header *req, void *key, uid_t uid) { - struct dataset *ignore; - - addgetnetgrentX (db, fd, req, key, uid, NULL, NULL, &ignore); + addgetnetgrentX_ignore (db, fd, req, key, uid, NULL, NULL); } @@ -619,10 +637,8 @@ readdgetnetgrent (struct database_dyn *db, struct hashentry *he, .type = GETNETGRENT, .key_len = he->len }; - struct dataset *ignore; - - return addgetnetgrentX (db, -1, &req, db->data + he->key, he->owner, he, dh, - &ignore); + return addgetnetgrentX_ignore + (db, -1, &req, db->data + he->key, he->owner, he, dh); } commit 9071be6b3f78da905ab2b6403933fe14d4482e47 Author: Paul Pluzhnikov Date: Fri Aug 31 18:04:32 2018 -0700 [BZ #20271] Add newlines in __libc_fatal calls. (cherry picked from commit a6e8926f8d49a213a9abb1a61f6af964f612ab7f) diff --git a/ChangeLog b/ChangeLog index 79d303e7b6..5145768a45 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,25 @@ +2018-08-31 Paul Pluzhnikov + + [BZ #20271] + * include/stdio.h (__libc_fatal): Mention newline in comment. + * grp/initgroups.c (internal_getgrouplist): Add missing newline. + * nptl/pthread_cond_wait.c (__pthread_cond_wait_common): Likewise. + * nscd/initgrcache.c (addinitgroupsX): Likewise. + * nss/nsswitch.c (__nss_next2): Likewise. + * sysdeps/aarch64/dl-irel.h (elf_irela): Likewise. + * sysdeps/arm/dl-irel.h (elf_irel): Likewise. + * sysdeps/generic/unwind-dw2.c (execute_cfa_program): Likewise. + * sysdeps/i386/dl-irel.h (elf_irel): Likewise. + * sysdeps/powerpc/powerpc32/dl-irel.h (elf_irel): Likewise. + * sysdeps/powerpc/powerpc64/dl-irel.h (elf_irel): Likewise. + * sysdeps/s390/dl-irel.h (elf_irel): Likewise. + * sysdeps/sparc/sparc32/dl-irel.h (elf_irel): Likewise. + * sysdeps/sparc/sparc64/dl-irel.h (elf_irel): Likewise. + * sysdeps/x86_64/dl-irel.h (elf_irel): Likewise. + * sysdeps/nptl/futex-internal.h (futex_wake): Likewise. + * sysdeps/unix/sysv/linux/netlink_assert_response.c + (__netlink_assert_response): Likewise. + 2018-08-28 Florian Weimer [BZ #23520] diff --git a/grp/initgroups.c b/grp/initgroups.c index f056fbf5aa..93e7f5814d 100644 --- a/grp/initgroups.c +++ b/grp/initgroups.c @@ -128,7 +128,7 @@ internal_getgrouplist (const char *user, gid_t group, long int *size, /* This is really only for debugging. */ if (NSS_STATUS_TRYAGAIN > status || status > NSS_STATUS_RETURN) - __libc_fatal ("illegal status in internal_getgrouplist"); + __libc_fatal ("Illegal status in internal_getgrouplist.\n"); /* For compatibility reason we will continue to look for more entries using the next service even though data has already diff --git a/include/stdio.h b/include/stdio.h index 9162d4e247..7a5c09089f 100644 --- a/include/stdio.h +++ b/include/stdio.h @@ -98,7 +98,8 @@ enum __libc_message_action do_backtrace = 1 << 1 /* Backtrace. */ }; -/* Print out MESSAGE on the error output and abort. */ +/* Print out MESSAGE (which should end with a newline) on the error output + and abort. */ extern void __libc_fatal (const char *__message) __attribute__ ((__noreturn__)); extern void __libc_message (enum __libc_message_action action, diff --git a/nptl/pthread_cond_wait.c b/nptl/pthread_cond_wait.c index 3e11054182..ebf07ca82d 100644 --- a/nptl/pthread_cond_wait.c +++ b/nptl/pthread_cond_wait.c @@ -516,7 +516,7 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex, struct timespec rt; if (__clock_gettime (CLOCK_MONOTONIC, &rt) != 0) __libc_fatal ("clock_gettime does not support " - "CLOCK_MONOTONIC"); + "CLOCK_MONOTONIC\n"); /* Convert the absolute timeout value to a relative timeout. */ rt.tv_sec = abstime->tv_sec - rt.tv_sec; diff --git a/nscd/initgrcache.c b/nscd/initgrcache.c index 2c74951f57..4764f14a45 100644 --- a/nscd/initgrcache.c +++ b/nscd/initgrcache.c @@ -159,7 +159,7 @@ addinitgroupsX (struct database_dyn *db, int fd, request_header *req, /* This is really only for debugging. */ if (NSS_STATUS_TRYAGAIN > status || status > NSS_STATUS_RETURN) - __libc_fatal ("illegal status in internal_getgrouplist"); + __libc_fatal ("Illegal status in internal_getgrouplist.\n"); any_success |= status == NSS_STATUS_SUCCESS; diff --git a/nss/nsswitch.c b/nss/nsswitch.c index ee46f24424..3c48b4b85e 100644 --- a/nss/nsswitch.c +++ b/nss/nsswitch.c @@ -235,7 +235,7 @@ __nss_next2 (service_user **ni, const char *fct_name, const char *fct2_name, /* This is really only for debugging. */ if (__builtin_expect (NSS_STATUS_TRYAGAIN > status || status > NSS_STATUS_RETURN, 0)) - __libc_fatal ("illegal status in __nss_next"); + __libc_fatal ("Illegal status in __nss_next.\n"); if (nss_next_action (*ni, status) == NSS_ACTION_RETURN) return 1; diff --git a/sysdeps/aarch64/dl-irel.h b/sysdeps/aarch64/dl-irel.h index 5889ee187b..bef71ed0f3 100644 --- a/sysdeps/aarch64/dl-irel.h +++ b/sysdeps/aarch64/dl-irel.h @@ -47,7 +47,7 @@ elf_irela (const ElfW(Rela) *reloc) *reloc_addr = value; } else - __libc_fatal ("unexpected reloc type in static binary"); + __libc_fatal ("Unexpected reloc type in static binary.\n"); } #endif diff --git a/sysdeps/arm/dl-irel.h b/sysdeps/arm/dl-irel.h index a7b6456075..be6eb7743e 100644 --- a/sysdeps/arm/dl-irel.h +++ b/sysdeps/arm/dl-irel.h @@ -46,7 +46,7 @@ elf_irel (const Elf32_Rel *reloc) *reloc_addr = value; } else - __libc_fatal ("unexpected reloc type in static binary"); + __libc_fatal ("Unexpected reloc type in static binary.\n"); } #endif /* dl-irel.h */ diff --git a/sysdeps/generic/unwind-dw2.c b/sysdeps/generic/unwind-dw2.c index 082609b34a..724c16a7f0 100644 --- a/sysdeps/generic/unwind-dw2.c +++ b/sysdeps/generic/unwind-dw2.c @@ -843,7 +843,7 @@ execute_cfa_program (const unsigned char *insn_ptr, struct frame_state_reg_info *old_rs = fs->regs.prev; #ifdef _LIBC if (old_rs == NULL) - __libc_fatal ("invalid DWARF unwind data"); + __libc_fatal ("Invalid DWARF unwind data.\n"); else #endif { diff --git a/sysdeps/i386/dl-irel.h b/sysdeps/i386/dl-irel.h index 55303180c7..bcaf0668ac 100644 --- a/sysdeps/i386/dl-irel.h +++ b/sysdeps/i386/dl-irel.h @@ -45,7 +45,7 @@ elf_irel (const Elf32_Rel *reloc) *reloc_addr = value; } else - __libc_fatal ("unexpected reloc type in static binary"); + __libc_fatal ("Unexpected reloc type in static binary.\n"); } #endif /* dl-irel.h */ diff --git a/sysdeps/nptl/futex-internal.h b/sysdeps/nptl/futex-internal.h index 1a5624789d..6fd27f0df6 100644 --- a/sysdeps/nptl/futex-internal.h +++ b/sysdeps/nptl/futex-internal.h @@ -197,7 +197,7 @@ futex_wake (unsigned int* futex_word, int processes_to_wake, int private); static __always_inline __attribute__ ((__noreturn__)) void futex_fatal_error (void) { - __libc_fatal ("The futex facility returned an unexpected error code."); + __libc_fatal ("The futex facility returned an unexpected error code.\n"); } #endif /* futex-internal.h */ diff --git a/sysdeps/powerpc/powerpc32/dl-irel.h b/sysdeps/powerpc/powerpc32/dl-irel.h index a7368b2582..61d0e4cf61 100644 --- a/sysdeps/powerpc/powerpc32/dl-irel.h +++ b/sysdeps/powerpc/powerpc32/dl-irel.h @@ -46,7 +46,7 @@ elf_irela (const Elf32_Rela *reloc) *reloc_addr = value; } else - __libc_fatal ("unexpected reloc type in static binary"); + __libc_fatal ("Unexpected reloc type in static binary.\n"); } #endif /* dl-irel.h */ diff --git a/sysdeps/powerpc/powerpc64/dl-irel.h b/sysdeps/powerpc/powerpc64/dl-irel.h index ab13c04358..2fd0ee8a86 100644 --- a/sysdeps/powerpc/powerpc64/dl-irel.h +++ b/sysdeps/powerpc/powerpc64/dl-irel.h @@ -57,7 +57,7 @@ elf_irela (const Elf64_Rela *reloc) #endif } else - __libc_fatal ("unexpected reloc type in static binary"); + __libc_fatal ("Unexpected reloc type in static binary.\n"); } #endif /* dl-irel.h */ diff --git a/sysdeps/s390/dl-irel.h b/sysdeps/s390/dl-irel.h index d8ba7ba427..ecb24f0a9b 100644 --- a/sysdeps/s390/dl-irel.h +++ b/sysdeps/s390/dl-irel.h @@ -46,7 +46,7 @@ elf_irela (const ElfW(Rela) *reloc) *reloc_addr = value; } else - __libc_fatal ("unexpected reloc type in static binary"); + __libc_fatal ("Unexpected reloc type in static binary.\n"); } #endif /* dl-irel.h */ diff --git a/sysdeps/sparc/sparc32/dl-irel.h b/sysdeps/sparc/sparc32/dl-irel.h index ffca36864f..cf47cda834 100644 --- a/sysdeps/sparc/sparc32/dl-irel.h +++ b/sysdeps/sparc/sparc32/dl-irel.h @@ -56,7 +56,7 @@ elf_irela (const Elf32_Rela *reloc) else if (r_type == R_SPARC_NONE) ; else - __libc_fatal ("unexpected reloc type in static binary"); + __libc_fatal ("Unexpected reloc type in static binary.\n"); } #endif /* dl-irel.h */ diff --git a/sysdeps/sparc/sparc64/dl-irel.h b/sysdeps/sparc/sparc64/dl-irel.h index c5cd3057ac..446fed1836 100644 --- a/sysdeps/sparc/sparc64/dl-irel.h +++ b/sysdeps/sparc/sparc64/dl-irel.h @@ -59,7 +59,7 @@ elf_irela (const Elf64_Rela *reloc) else if (r_type == R_SPARC_NONE) ; else - __libc_fatal ("unexpected reloc type in static binary"); + __libc_fatal ("Unexpected reloc type in static binary.\n"); } #endif /* dl-irel.h */ diff --git a/sysdeps/unix/sysv/linux/netlink_assert_response.c b/sysdeps/unix/sysv/linux/netlink_assert_response.c index f31ccb52ff..6afc3a17ce 100644 --- a/sysdeps/unix/sysv/linux/netlink_assert_response.c +++ b/sysdeps/unix/sysv/linux/netlink_assert_response.c @@ -72,12 +72,12 @@ __netlink_assert_response (int fd, ssize_t result) char message[200]; if (family < 0) __snprintf (message, sizeof (message), - "Unexpected error %d on netlink descriptor %d", + "Unexpected error %d on netlink descriptor %d.\n", error_code, fd); else __snprintf (message, sizeof (message), "Unexpected error %d on netlink descriptor %d" - " (address family %d)", + " (address family %d).\n", error_code, fd, family); __libc_fatal (message); } diff --git a/sysdeps/x86_64/dl-irel.h b/sysdeps/x86_64/dl-irel.h index 6ecc50fb42..33f100d8b1 100644 --- a/sysdeps/x86_64/dl-irel.h +++ b/sysdeps/x86_64/dl-irel.h @@ -45,7 +45,7 @@ elf_irela (const ElfW(Rela) *reloc) *reloc_addr = value; } else - __libc_fatal ("unexpected reloc type in static binary"); + __libc_fatal ("Unexpected reloc type in static binary.\n"); } #endif /* dl-irel.h */ commit e7388e5134471ef965bd48bafc71ba71eb8bf017 Author: Paul Eggert Date: Tue Sep 18 15:02:10 2018 -0700 Fix tzfile low-memory assertion failure [BZ #21716] * time/tzfile.c (__tzfile_read): Check for memory exhaustion when registering time zone abbreviations. (cherry picked from commit e4e4fde51a309801af5eed72d3494cbf4b7737aa) diff --git a/ChangeLog b/ChangeLog index 5145768a45..788f3f41be 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2018-09-18 Paul Eggert + + Fix tzfile low-memory assertion failure + [BZ #21716] + * time/tzfile.c (__tzfile_read): Check for memory exhaustion + when registering time zone abbreviations. + 2018-08-31 Paul Pluzhnikov [BZ #20271] diff --git a/time/tzfile.c b/time/tzfile.c index 2a385b92bc..ea6e940303 100644 --- a/time/tzfile.c +++ b/time/tzfile.c @@ -410,7 +410,8 @@ __tzfile_read (const char *file, size_t extra, char **extrap) /* First "register" all timezone names. */ for (i = 0; i < num_types; ++i) - (void) __tzstring (&zone_names[types[i].idx]); + if (__tzstring (&zone_names[types[i].idx]) == NULL) + goto ret_free_transitions; /* Find the standard and daylight time offsets used by the rule file. We choose the offsets in the types of each flavor that are commit f44c2ca5eacd2df76fc38be75f9ebb8f0ff555eb Author: Joseph Myers Date: Mon Oct 22 23:26:37 2018 +0000 Update kernel version in syscall-names.list to 4.19. Linux 4.19 does not add any new syscalls (some existing ones are added to more architectures); this patch updates the version number in syscall-names.list to reflect that it's still current for 4.19. Tested with build-many-glibcs.py. * sysdeps/unix/sysv/linux/syscall-names.list: Update kernel version to 4.19. (cherry picked from commit 029ad711b8ad4cf0e5d98e0c138a35a23a376a74) diff --git a/ChangeLog b/ChangeLog index 788f3f41be..f2e0f1ffd7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2018-10-22 Joseph Myers + + * sysdeps/unix/sysv/linux/syscall-names.list: Update kernel + version to 4.19. + 2018-09-18 Paul Eggert Fix tzfile low-memory assertion failure diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list index 9982a6334d..f88001c9c3 100644 --- a/sysdeps/unix/sysv/linux/syscall-names.list +++ b/sysdeps/unix/sysv/linux/syscall-names.list @@ -22,8 +22,8 @@ # names are only used if the installed kernel headers also provide # them. -# The list of system calls is current as of Linux 4.18. -kernel 4.18 +# The list of system calls is current as of Linux 4.19. +kernel 4.19 FAST_atomic_update FAST_cmpxchg commit 10f1519f6a0acdc1fc45e962fa5c13312cc7b624 Author: Szabolcs Nagy Date: Tue Oct 9 14:31:28 2018 +0100 Increase timeout of libio/tst-readline Increase timeout from the default 20s to 100s. This test makes close to 20 million syscalls with distribution: 12327675 read 4143204 lseek 929475 close 929471 openat 92817 fstat 1431 write ... The default timeout assumes each can finish in 1us on average which is not true on slow machines. Reviewed-by: Carlos O'Donell * libio/tst-readline.c (TIMEOUT): Define. (cherry picked from commit ed643089cd3251038863d32e67ec47b94cd557f3) diff --git a/ChangeLog b/ChangeLog index f2e0f1ffd7..99462fa3d4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2018-10-09 Szabolcs Nagy + + * libio/tst-readline.c (TIMEOUT): Define. + 2018-10-22 Joseph Myers * sysdeps/unix/sysv/linux/syscall-names.list: Update kernel diff --git a/libio/tst-readline.c b/libio/tst-readline.c index 9322ef68da..63f5227760 100644 --- a/libio/tst-readline.c +++ b/libio/tst-readline.c @@ -232,5 +232,6 @@ do_test (void) return 0; } +#define TIMEOUT 100 #define PREPARE prepare #include commit 2c7078bfb9cc426433ac08d951e24c29c01b5f7d Author: Florian Weimer Date: Mon Nov 19 15:35:03 2018 +0100 support: Print timestamps in timeout handler This is sometimes useful to determine if a test truly got stuck, or if it was making progress (logging information to standard output) and was merely slow to finish. (cherry picked from commit 35e3fbc4512c880fccb35b8e3abd132d4be18480) diff --git a/ChangeLog b/ChangeLog index 99462fa3d4..8c92ee7764 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2018-11-19 Florian Weimer + + support: Print timestamps in timeout handler. + * support/support_test_main.c (print_timestamp): New function. + (signal_handler): Use it to print the termination time and the + time of the last write to standard output. + 2018-10-09 Szabolcs Nagy * libio/tst-readline.c (TIMEOUT): Define. diff --git a/support/support_test_main.c b/support/support_test_main.c index 23429779ac..fa3c2e06de 100644 --- a/support/support_test_main.c +++ b/support/support_test_main.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -86,6 +87,19 @@ static pid_t test_pid; /* The cleanup handler passed to test_main. */ static void (*cleanup_function) (void); +static void +print_timestamp (const char *what, struct timeval tv) +{ + struct tm tm; + if (gmtime_r (&tv.tv_sec, &tm) == NULL) + printf ("%s: %lld.%06d\n", + what, (long long int) tv.tv_sec, (int) tv.tv_usec); + else + printf ("%s: %04d-%02d-%02dT%02d:%02d:%02d.%06d\n", + what, 1900 + tm.tm_year, tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec, (int) tv.tv_usec); +} + /* Timeout handler. We kill the child and exit with an error. */ static void __attribute__ ((noreturn)) @@ -94,6 +108,13 @@ signal_handler (int sig) int killed; int status; + /* Do this first to avoid further interference from the + subprocess. */ + struct timeval now; + bool now_available = gettimeofday (&now, NULL) == 0; + struct stat64 st; + bool st_available = fstat64 (STDOUT_FILENO, &st) == 0 && st.st_mtime != 0; + assert (test_pid > 1); /* Kill the whole process group. */ kill (-test_pid, SIGKILL); @@ -144,6 +165,13 @@ signal_handler (int sig) printf ("Timed out: killed the child process but it exited %d\n", WEXITSTATUS (status)); + if (now_available) + print_timestamp ("Termination time", now); + if (st_available) + print_timestamp ("Last write to standard output", + (struct timeval) { st.st_mtim.tv_sec, + st.st_mtim.tv_nsec / 1000 }); + /* Exit with an error. */ exit (1); } commit 481a6cf0c24f02f251d7cd0b776c12d00e6b144f Author: DJ Delorie Date: Tue Nov 20 13:24:09 2018 -0500 malloc: tcache double free check * malloc/malloc.c (tcache_entry): Add key field. (tcache_put): Set it. (tcache_get): Likewise. (_int_free): Check for double free in tcache. * malloc/tst-tcfree1.c: New. * malloc/tst-tcfree2.c: New. * malloc/Makefile: Run the new tests. * manual/probes.texi: Document memory_tcache_double_free probe. * dlfcn/dlerror.c (check_free): Prevent double frees. diff --git a/ChangeLog b/ChangeLog index 8c92ee7764..1ef4b4abe0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2018-11-20 DJ Delorie + + * malloc/malloc.c (tcache_entry): Add key field. + (tcache_put): Set it. + (tcache_get): Likewise. + (_int_free): Check for double free in tcache. + * malloc/tst-tcfree1.c: New. + * malloc/tst-tcfree2.c: New. + * malloc/Makefile: Run the new tests. + * manual/probes.texi: Document memory_tcache_double_free probe. + + * dlfcn/dlerror.c (check_free): Prevent double frees. 2018-11-19 Florian Weimer support: Print timestamps in timeout handler. diff --git a/dlfcn/dlerror.c b/dlfcn/dlerror.c index 33574faab6..96bf925333 100644 --- a/dlfcn/dlerror.c +++ b/dlfcn/dlerror.c @@ -198,7 +198,10 @@ check_free (struct dl_action_result *rec) Dl_info info; if (_dl_addr (check_free, &info, &map, NULL) != 0 && map->l_ns == 0) #endif - free ((char *) rec->errstring); + { + free ((char *) rec->errstring); + rec->errstring = NULL; + } } } diff --git a/malloc/Makefile b/malloc/Makefile index 7d54bad866..e6dfbfc14c 100644 --- a/malloc/Makefile +++ b/malloc/Makefile @@ -38,6 +38,7 @@ tests := mallocbug tst-malloc tst-valloc tst-calloc tst-obstack \ tst-malloc_info \ tst-malloc-too-large \ tst-malloc-stats-cancellation \ + tst-tcfree1 tst-tcfree2 \ tests-static := \ tst-interpose-static-nothread \ diff --git a/malloc/malloc.c b/malloc/malloc.c index 47795601c8..6be2573868 100644 --- a/malloc/malloc.c +++ b/malloc/malloc.c @@ -2888,6 +2888,8 @@ mremap_chunk (mchunkptr p, size_t new_size) typedef struct tcache_entry { struct tcache_entry *next; + /* This field exists to detect double frees. */ + struct tcache_perthread_struct *key; } tcache_entry; /* There is one of these for each thread, which contains the @@ -2911,6 +2913,11 @@ tcache_put (mchunkptr chunk, size_t tc_idx) { tcache_entry *e = (tcache_entry *) chunk2mem (chunk); assert (tc_idx < TCACHE_MAX_BINS); + + /* Mark this chunk as "in the tcache" so the test in _int_free will + detect a double free. */ + e->key = tcache; + e->next = tcache->entries[tc_idx]; tcache->entries[tc_idx] = e; ++(tcache->counts[tc_idx]); @@ -2926,6 +2933,7 @@ tcache_get (size_t tc_idx) assert (tcache->entries[tc_idx] > 0); tcache->entries[tc_idx] = e->next; --(tcache->counts[tc_idx]); + e->key = NULL; return (void *) e; } @@ -4166,6 +4174,26 @@ _int_free (mstate av, mchunkptr p, int have_lock) { size_t tc_idx = csize2tidx (size); + /* Check to see if it's already in the tcache. */ + tcache_entry *e = (tcache_entry *) chunk2mem (p); + + /* This test succeeds on double free. However, we don't 100% + trust it (it also matches random payload data at a 1 in + 2^ chance), so verify it's not an unlikely coincidence + before aborting. */ + if (__glibc_unlikely (e->key == tcache && tcache)) + { + tcache_entry *tmp; + LIBC_PROBE (memory_tcache_double_free, 2, e, tc_idx); + for (tmp = tcache->entries[tc_idx]; + tmp; + tmp = tmp->next) + if (tmp == e) + malloc_printerr ("free(): double free detected in tcache 2"); + /* If we get here, it was a coincidence. We've wasted a few + cycles, but don't abort. */ + } + if (tcache && tc_idx < mp_.tcache_bins && tcache->counts[tc_idx] < mp_.tcache_count) diff --git a/malloc/tst-tcfree1.c b/malloc/tst-tcfree1.c new file mode 100644 index 0000000000..bc29375ce7 --- /dev/null +++ b/malloc/tst-tcfree1.c @@ -0,0 +1,42 @@ +/* Test that malloc tcache catches double free. + 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 + . */ + +#include +#include +#include +#include +#include +#include +#include + +static int +do_test (void) +{ + /* Do one allocation of any size that fits in tcache. */ + char * volatile x = malloc (32); + + free (x); // puts in tcache + free (x); // should abort + + printf("FAIL: tcache double free not detected\n"); + return 1; +} + +#define TEST_FUNCTION do_test +#define EXPECTED_SIGNAL SIGABRT +#include diff --git a/malloc/tst-tcfree2.c b/malloc/tst-tcfree2.c new file mode 100644 index 0000000000..17f06bacd4 --- /dev/null +++ b/malloc/tst-tcfree2.c @@ -0,0 +1,48 @@ +/* Test that malloc tcache catches double free. + 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 + . */ + +#include +#include +#include +#include +#include +#include +#include + +static int +do_test (void) +{ + char * volatile ptrs[20]; + int i; + + /* Allocate enough small chunks so that when we free them all, the tcache + is full, and the first one we freed is at the end of its linked list. */ +#define COUNT 20 + for (i=0; i diff --git a/manual/probes.texi b/manual/probes.texi index ab2a3102bb..0ea560ed78 100644 --- a/manual/probes.texi +++ b/manual/probes.texi @@ -243,6 +243,18 @@ This probe is triggered when the value of this tunable. @end deftp +@deftp Probe memory_tcache_double_free (void *@var{$arg1}, int @var{$arg2}) +This probe is triggered when @code{free} determines that the memory +being freed has probably already been freed, and resides in the +per-thread cache. Note that there is an extremely unlikely chance +that this probe will trigger due to random payload data remaining in +the allocated memory matching the key used to detect double frees. +This probe actually indicates that an expensive linear search of the +tcache, looking for a double free, has happened. Argument @var{$arg1} +is the memory location as passed to @code{free}, Argument @var{$arg2} +is the tcache bin it resides in. +@end deftp + @node Mathematical Function Probes @section Mathematical Function Probes commit f5cc21eaeea6afbdfd543c63d2a552f141a91781 Author: Florian Weimer Date: Thu Nov 22 22:05:57 2018 +0100 Revert "malloc: tcache double free check" [BZ #23907] This reverts commit 481a6cf0c24f02f251d7cd0b776c12d00e6b144f, the backport of commit bcdaad21d4635931d1bd3b54a7894276925d081d on the master branch. diff --git a/ChangeLog b/ChangeLog index 1ef4b4abe0..8c92ee7764 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,15 +1,3 @@ -2018-11-20 DJ Delorie - - * malloc/malloc.c (tcache_entry): Add key field. - (tcache_put): Set it. - (tcache_get): Likewise. - (_int_free): Check for double free in tcache. - * malloc/tst-tcfree1.c: New. - * malloc/tst-tcfree2.c: New. - * malloc/Makefile: Run the new tests. - * manual/probes.texi: Document memory_tcache_double_free probe. - - * dlfcn/dlerror.c (check_free): Prevent double frees. 2018-11-19 Florian Weimer support: Print timestamps in timeout handler. diff --git a/dlfcn/dlerror.c b/dlfcn/dlerror.c index 96bf925333..33574faab6 100644 --- a/dlfcn/dlerror.c +++ b/dlfcn/dlerror.c @@ -198,10 +198,7 @@ check_free (struct dl_action_result *rec) Dl_info info; if (_dl_addr (check_free, &info, &map, NULL) != 0 && map->l_ns == 0) #endif - { - free ((char *) rec->errstring); - rec->errstring = NULL; - } + free ((char *) rec->errstring); } } diff --git a/malloc/Makefile b/malloc/Makefile index e6dfbfc14c..7d54bad866 100644 --- a/malloc/Makefile +++ b/malloc/Makefile @@ -38,7 +38,6 @@ tests := mallocbug tst-malloc tst-valloc tst-calloc tst-obstack \ tst-malloc_info \ tst-malloc-too-large \ tst-malloc-stats-cancellation \ - tst-tcfree1 tst-tcfree2 \ tests-static := \ tst-interpose-static-nothread \ diff --git a/malloc/malloc.c b/malloc/malloc.c index 6be2573868..47795601c8 100644 --- a/malloc/malloc.c +++ b/malloc/malloc.c @@ -2888,8 +2888,6 @@ mremap_chunk (mchunkptr p, size_t new_size) typedef struct tcache_entry { struct tcache_entry *next; - /* This field exists to detect double frees. */ - struct tcache_perthread_struct *key; } tcache_entry; /* There is one of these for each thread, which contains the @@ -2913,11 +2911,6 @@ tcache_put (mchunkptr chunk, size_t tc_idx) { tcache_entry *e = (tcache_entry *) chunk2mem (chunk); assert (tc_idx < TCACHE_MAX_BINS); - - /* Mark this chunk as "in the tcache" so the test in _int_free will - detect a double free. */ - e->key = tcache; - e->next = tcache->entries[tc_idx]; tcache->entries[tc_idx] = e; ++(tcache->counts[tc_idx]); @@ -2933,7 +2926,6 @@ tcache_get (size_t tc_idx) assert (tcache->entries[tc_idx] > 0); tcache->entries[tc_idx] = e->next; --(tcache->counts[tc_idx]); - e->key = NULL; return (void *) e; } @@ -4174,26 +4166,6 @@ _int_free (mstate av, mchunkptr p, int have_lock) { size_t tc_idx = csize2tidx (size); - /* Check to see if it's already in the tcache. */ - tcache_entry *e = (tcache_entry *) chunk2mem (p); - - /* This test succeeds on double free. However, we don't 100% - trust it (it also matches random payload data at a 1 in - 2^ chance), so verify it's not an unlikely coincidence - before aborting. */ - if (__glibc_unlikely (e->key == tcache && tcache)) - { - tcache_entry *tmp; - LIBC_PROBE (memory_tcache_double_free, 2, e, tc_idx); - for (tmp = tcache->entries[tc_idx]; - tmp; - tmp = tmp->next) - if (tmp == e) - malloc_printerr ("free(): double free detected in tcache 2"); - /* If we get here, it was a coincidence. We've wasted a few - cycles, but don't abort. */ - } - if (tcache && tc_idx < mp_.tcache_bins && tcache->counts[tc_idx] < mp_.tcache_count) diff --git a/malloc/tst-tcfree1.c b/malloc/tst-tcfree1.c deleted file mode 100644 index bc29375ce7..0000000000 --- a/malloc/tst-tcfree1.c +++ /dev/null @@ -1,42 +0,0 @@ -/* Test that malloc tcache catches double free. - 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 - . */ - -#include -#include -#include -#include -#include -#include -#include - -static int -do_test (void) -{ - /* Do one allocation of any size that fits in tcache. */ - char * volatile x = malloc (32); - - free (x); // puts in tcache - free (x); // should abort - - printf("FAIL: tcache double free not detected\n"); - return 1; -} - -#define TEST_FUNCTION do_test -#define EXPECTED_SIGNAL SIGABRT -#include diff --git a/malloc/tst-tcfree2.c b/malloc/tst-tcfree2.c deleted file mode 100644 index 17f06bacd4..0000000000 --- a/malloc/tst-tcfree2.c +++ /dev/null @@ -1,48 +0,0 @@ -/* Test that malloc tcache catches double free. - 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 - . */ - -#include -#include -#include -#include -#include -#include -#include - -static int -do_test (void) -{ - char * volatile ptrs[20]; - int i; - - /* Allocate enough small chunks so that when we free them all, the tcache - is full, and the first one we freed is at the end of its linked list. */ -#define COUNT 20 - for (i=0; i diff --git a/manual/probes.texi b/manual/probes.texi index 0ea560ed78..ab2a3102bb 100644 --- a/manual/probes.texi +++ b/manual/probes.texi @@ -243,18 +243,6 @@ This probe is triggered when the value of this tunable. @end deftp -@deftp Probe memory_tcache_double_free (void *@var{$arg1}, int @var{$arg2}) -This probe is triggered when @code{free} determines that the memory -being freed has probably already been freed, and resides in the -per-thread cache. Note that there is an extremely unlikely chance -that this probe will trigger due to random payload data remaining in -the allocated memory matching the key used to detect double frees. -This probe actually indicates that an expensive linear search of the -tcache, looking for a double free, has happened. Argument @var{$arg1} -is the memory location as passed to @code{free}, Argument @var{$arg2} -is the tcache bin it resides in. -@end deftp - @node Mathematical Function Probes @section Mathematical Function Probes commit ce6ba630dbc96f49eb1f30366aa62261df4792f9 Author: Florian Weimer Date: Tue Nov 27 16:12:43 2018 +0100 CVE-2018-19591: if_nametoindex: Fix descriptor for overlong name [BZ #23927] (cherry picked from commit d527c860f5a3f0ed687bd03f0cb464612dc23408) diff --git a/ChangeLog b/ChangeLog index 8c92ee7764..a997003664 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2018-11-27 Florian Weimer + + [BZ #23927] + CVE-2018-19591 + * sysdeps/unix/sysv/linux/if_index.c (__if_nametoindex): Avoid + descriptor leak in case of ENODEV error. + 2018-11-19 Florian Weimer support: Print timestamps in timeout handler. diff --git a/NEWS b/NEWS index e5ca5903ec..5290e21da9 100644 --- a/NEWS +++ b/NEWS @@ -25,7 +25,13 @@ The following bugs are resolved with this release: [23717] Fix stack overflow in stdlib/tst-setcontext9 [23821] si_band in siginfo_t has wrong type long int on sparc64 [23822] ia64 static libm.a is missing exp2f, log2f and powf symbols + [23927] Linux if_nametoindex() does not close descriptor (CVE-2018-19591) +Security related changes: + + 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. Version 2.28 diff --git a/sysdeps/unix/sysv/linux/if_index.c b/sysdeps/unix/sysv/linux/if_index.c index e3d08982d9..782fc5e175 100644 --- a/sysdeps/unix/sysv/linux/if_index.c +++ b/sysdeps/unix/sysv/linux/if_index.c @@ -38,11 +38,6 @@ __if_nametoindex (const char *ifname) return 0; #else struct ifreq ifr; - int fd = __opensock (); - - if (fd < 0) - return 0; - if (strlen (ifname) >= IFNAMSIZ) { __set_errno (ENODEV); @@ -50,6 +45,12 @@ __if_nametoindex (const char *ifname) } strncpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); + + int fd = __opensock (); + + if (fd < 0) + return 0; + if (__ioctl (fd, SIOCGIFINDEX, &ifr) < 0) { int saved_errno = errno;