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