From c252c193e2583e4506b141d052df29a0987ac290 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Wed, 13 Apr 2016 14:07:58 -0500 Subject: malloc: Prevent arena free_list from turning cyclic [BZ #19048] [BZ# 19048] * malloc/malloc.c (struct malloc_state): Update comment. Add attached_threads member. (main_arena): Initialize attached_threads. * malloc/arena.c (list_lock): Update comment. (ptmalloc_lock_all, ptmalloc_unlock_all): Likewise. (ptmalloc_unlock_all2): Reinitialize arena reference counts. (deattach_arena): New function. (_int_new_arena): Initialize arena reference count and deattach replaced arena. (get_free_list, reused_arena): Update reference count and deattach replaced arena. (arena_thread_freeres): Update arena reference count and only put unreferenced arenas on the free list. (cherry picked from commit a62719ba90e2fa1728890ae7dc8df9e32a622e7b) --- ChangeLog | 17 ++++++++++++++ NEWS | 13 +++++++++-- malloc/arena.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++---- malloc/malloc.c | 11 +++++++-- 4 files changed, 104 insertions(+), 8 deletions(-) diff --git a/ChangeLog b/ChangeLog index f7664af..7032239 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,20 @@ +2016-04-13 Florian Weimer + + [BZ# 19048] + * malloc/malloc.c (struct malloc_state): Update comment. Add + attached_threads member. + (main_arena): Initialize attached_threads. + * malloc/arena.c (list_lock): Update comment. + (ptmalloc_lock_all, ptmalloc_unlock_all): Likewise. + (ptmalloc_unlock_all2): Reinitialize arena reference counts. + (deattach_arena): New function. + (_int_new_arena): Initialize arena reference count and deattach + replaced arena. + (get_free_list, reused_arena): Update reference count and deattach + replaced arena. + (arena_thread_freeres): Update arena reference count and only put + unreferenced arenas on the free list. + 2016-04-12 Paul E. Murphy [BZ #19853] diff --git a/NEWS b/NEWS index 2a43aec..7d6a7d6 100644 --- a/NEWS +++ b/NEWS @@ -24,8 +24,8 @@ Version 2.22.1 * The following bugs are resolved with this release: 17905, 18420, 18421, 18480, 18589, 18743, 18778, 18781, 18787, 18796, - 18870, 18887, 18921, 18928, 18969, 18985, 19003, 19018, 19058, 19174, - 19178, 19590, 19682, 19791, 19822, 19853, 19879. + 18870, 18887, 18921, 18928, 18969, 18985, 19003, 19018, 19048, 19058, + 19174, 19178, 19590, 19682, 19791, 19822, 19853, 19879. * The getnetbyname implementation in nss_dns had a potentially unbounded alloca call (in the form of a call to strdupa), leading to a stack @@ -34,6 +34,15 @@ Version 2.22.1 * The LD_POINTER_GUARD environment variable can no longer be used to disable the pointer guard feature. It is always enabled. + +* A defect in the malloc implementation, present since glibc 2.15 (2012) or + glibc 2.10 via --enable-experimental-malloc (2009), could result in the + unnecessary serialization of memory allocation requests across threads. + The defect is now corrected. Users should see a substantial increase in + the concurent throughput of allocation requests for applications which + trigger this bug. Affected applications typically create create and + destroy threads frequently. (Bug 19048 was reported and analyzed by + Ericsson.) Version 2.22 diff --git a/malloc/arena.c b/malloc/arena.c index 21ecc5a1..ca5b8a2 100644 --- a/malloc/arena.c +++ b/malloc/arena.c @@ -233,7 +233,10 @@ ptmalloc_lock_all (void) save_free_hook = __free_hook; __malloc_hook = malloc_atfork; __free_hook = free_atfork; - /* Only the current thread may perform malloc/free calls now. */ + /* Only the current thread may perform malloc/free calls now. + save_arena will be reattached to the current thread, in + ptmalloc_lock_all, so save_arena->attached_threads is not + updated. */ tsd_getspecific (arena_key, save_arena); tsd_setspecific (arena_key, ATFORK_ARENA_PTR); out: @@ -251,6 +254,9 @@ ptmalloc_unlock_all (void) if (--atfork_recursive_cntr != 0) return; + /* Replace ATFORK_ARENA_PTR with save_arena. + save_arena->attached_threads was not changed in ptmalloc_lock_all + and is still correct. */ tsd_setspecific (arena_key, save_arena); __malloc_hook = save_malloc_hook; __free_hook = save_free_hook; @@ -282,12 +288,19 @@ ptmalloc_unlock_all2 (void) tsd_setspecific (arena_key, save_arena); __malloc_hook = save_malloc_hook; __free_hook = save_free_hook; + + /* Push all arenas to the free list, except save_arena, which is + attached to the current thread. */ + if (save_arena != NULL) + ((mstate) save_arena)->attached_threads = 1; free_list = NULL; for (ar_ptr = &main_arena;; ) { mutex_init (&ar_ptr->mutex); if (ar_ptr != save_arena) { + /* This arena is no longer attached to any thread. */ + ar_ptr->attached_threads = 0; ar_ptr->next_free = free_list; free_list = ar_ptr; } @@ -721,6 +734,22 @@ heap_trim (heap_info *heap, size_t pad) /* Create a new arena with initial size "size". */ +/* If REPLACED_ARENA is not NULL, detach it from this thread. Must be + called while list_lock is held. */ +static void +detach_arena (mstate replaced_arena) +{ + if (replaced_arena != NULL) + { + assert (replaced_arena->attached_threads > 0); + /* The current implementation only detaches from main_arena in + case of allocation failure. This means that it is likely not + beneficial to put the arena on free_list even if the + reference count reaches zero. */ + --replaced_arena->attached_threads; + } +} + static mstate _int_new_arena (size_t size) { @@ -742,6 +771,7 @@ _int_new_arena (size_t size) } a = h->ar_ptr = (mstate) (h + 1); malloc_init_state (a); + a->attached_threads = 1; /*a->next = NULL;*/ a->system_mem = a->max_system_mem = h->size; arena_mem += h->size; @@ -755,12 +785,16 @@ _int_new_arena (size_t size) set_head (top (a), (((char *) h + h->size) - ptr) | PREV_INUSE); LIBC_PROBE (memory_arena_new, 2, a, size); + mstate replaced_arena; + tsd_getspecific (arena_key, replaced_arena); tsd_setspecific (arena_key, (void *) a); mutex_init (&a->mutex); (void) mutex_lock (&a->mutex); (void) mutex_lock (&list_lock); + detach_arena (replaced_arena); + /* Add the new arena to the global list. */ a->next = main_arena.next; atomic_write_barrier (); @@ -775,13 +809,26 @@ _int_new_arena (size_t size) static mstate get_free_list (void) { + mstate replaced_arena; mstate result = free_list; + + tsd_getspecific (arena, replaced_arena); + if (result != NULL) { (void) mutex_lock (&list_lock); result = free_list; if (result != NULL) - free_list = result->next_free; + { + free_list = result->next_free; + + /* Arenas on the free list are not attached to any thread. */ + assert (result->attached_threads == 0); + /* But the arena will now be attached to this thread. */ + result->attached_threads = 1; + + detach_arena (replaced_arena); + } (void) mutex_unlock (&list_lock); if (result != NULL) @@ -840,6 +887,16 @@ reused_arena (mstate avoid_arena) (void) mutex_lock (&result->mutex); out: + { + mstate replaced_arena; + + tsd_getspecific (arena, replaced_arena); + (void) mutex_lock (&list_lock); + detach_arena (replaced_arena); + ++result->attached_threads; + (void) mutex_unlock (&list_lock); + } + LIBC_PROBE (memory_arena_reuse, 2, result, avoid_arena); tsd_setspecific (arena_key, (void *) result); next_to_use = result->next; @@ -933,8 +990,14 @@ arena_thread_freeres (void) if (a != NULL) { (void) mutex_lock (&list_lock); - a->next_free = free_list; - free_list = a; + /* If this was the last attached thread for this arena, put the + arena on the free list. */ + assert (a->attached_threads > 0); + if (--a->attached_threads == 0) + { + a->next_free = free_list; + free_list = a; + } (void) mutex_unlock (&list_lock); } } diff --git a/malloc/malloc.c b/malloc/malloc.c index 452f036..037d4ff 100644 --- a/malloc/malloc.c +++ b/malloc/malloc.c @@ -1709,9 +1709,15 @@ struct malloc_state /* Linked list */ struct malloc_state *next; - /* Linked list for free arenas. */ + /* Linked list for free arenas. Access to this field is serialized + by list_lock in arena.c. */ struct malloc_state *next_free; + /* Number of threads attached to this arena. 0 if the arena is on + the free list. Access to this field is serialized by list_lock + in arena.c. */ + INTERNAL_SIZE_T attached_threads; + /* Memory allocated from the system in this arena. */ INTERNAL_SIZE_T system_mem; INTERNAL_SIZE_T max_system_mem; @@ -1755,7 +1761,8 @@ struct malloc_par static struct malloc_state main_arena = { .mutex = MUTEX_INITIALIZER, - .next = &main_arena + .next = &main_arena, + .attached_threads = 1 }; /* There is only one instance of the malloc parameters. */ -- cgit v1.1 From 00cd4dad175f648783f808aef681d16c10fc34fa Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Wed, 13 Apr 2016 14:08:24 -0500 Subject: malloc: Fix attached thread reference count handling [BZ #19243] reused_arena can increase the attached thread count of arenas on the free list. This means that the assertion that the reference count is zero is incorrect. In this case, the reference count initialization is incorrect as well and could cause arenas to be put on the free list too early (while they still have attached threads). * malloc/arena.c (get_free_list): Remove assert and adjust reference count handling. Add comment about reused_arena interaction. (reused_arena): Add comments abount get_free_list interaction. * malloc/tst-malloc-thread-exit.c: New file. * malloc/Makefile (tests): Add tst-malloc-thread-exit. (tst-malloc-thread-exit): Link against libpthread. (cherry picked from commit 3da825ce483903e3a881a016113b3e59fd4041de) --- ChangeLog | 11 ++ NEWS | 2 +- malloc/Makefile | 4 +- malloc/arena.c | 12 ++- malloc/tst-malloc-thread-exit.c | 217 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 240 insertions(+), 6 deletions(-) create mode 100644 malloc/tst-malloc-thread-exit.c diff --git a/ChangeLog b/ChangeLog index 7032239..fde59f1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,16 @@ 2016-04-13 Florian Weimer + [BZ #19243] + * malloc/arena.c (get_free_list): Remove assert and adjust + reference count handling. Add comment about reused_arena + interaction. + (reused_arena): Add comments abount get_free_list interaction. + * malloc/tst-malloc-thread-exit.c: New file. + * malloc/Makefile (tests): Add tst-malloc-thread-exit. + (tst-malloc-thread-exit): Link against libpthread. + +2016-04-13 Florian Weimer + [BZ# 19048] * malloc/malloc.c (struct malloc_state): Update comment. Add attached_threads member. diff --git a/NEWS b/NEWS index 7d6a7d6..21c85ca 100644 --- a/NEWS +++ b/NEWS @@ -25,7 +25,7 @@ Version 2.22.1 17905, 18420, 18421, 18480, 18589, 18743, 18778, 18781, 18787, 18796, 18870, 18887, 18921, 18928, 18969, 18985, 19003, 19018, 19048, 19058, - 19174, 19178, 19590, 19682, 19791, 19822, 19853, 19879. + 19174, 19178, 19243, 19590, 19682, 19791, 19822, 19853, 19879. * The getnetbyname implementation in nss_dns had a potentially unbounded alloca call (in the form of a call to strdupa), leading to a stack diff --git a/malloc/Makefile b/malloc/Makefile index 67ed293..aa0579c 100644 --- a/malloc/Makefile +++ b/malloc/Makefile @@ -28,7 +28,7 @@ tests := mallocbug tst-malloc tst-valloc tst-calloc tst-obstack \ tst-mallocstate tst-mcheck tst-mallocfork tst-trim1 \ tst-malloc-usable tst-realloc tst-posix_memalign \ tst-pvalloc tst-memalign tst-mallopt tst-scratch_buffer \ - tst-malloc-backtrace + tst-malloc-backtrace tst-malloc-thread-exit test-srcs = tst-mtrace routines = malloc morecore mcheck mtrace obstack \ @@ -47,6 +47,8 @@ libmemusage-inhibit-o = $(filter-out .os,$(object-suffixes)) $(objpfx)tst-malloc-backtrace: $(common-objpfx)nptl/libpthread.so \ $(common-objpfx)nptl/libpthread_nonshared.a +$(objpfx)tst-malloc-thread-exit: $(common-objpfx)nptl/libpthread.so \ + $(common-objpfx)nptl/libpthread_nonshared.a # These should be removed by `make clean'. extra-objs = mcheck-init.o libmcheck.a diff --git a/malloc/arena.c b/malloc/arena.c index ca5b8a2..f05c502 100644 --- a/malloc/arena.c +++ b/malloc/arena.c @@ -806,6 +806,8 @@ _int_new_arena (size_t size) } +/* Remove an arena from free_list. The arena may be in use because it + was attached concurrently to a thread by reused_arena below. */ static mstate get_free_list (void) { @@ -822,10 +824,8 @@ get_free_list (void) { free_list = result->next_free; - /* Arenas on the free list are not attached to any thread. */ - assert (result->attached_threads == 0); - /* But the arena will now be attached to this thread. */ - result->attached_threads = 1; + /* The arena will be attached to this thread. */ + ++result->attached_threads; detach_arena (replaced_arena); } @@ -853,6 +853,8 @@ reused_arena (mstate avoid_arena) if (next_to_use == NULL) next_to_use = &main_arena; + /* Iterate over all arenas (including those linked from + free_list). */ result = next_to_use; do { @@ -887,6 +889,8 @@ reused_arena (mstate avoid_arena) (void) mutex_lock (&result->mutex); out: + /* Attach the arena to the current thread. Note that we may have + selected an arena which was on free_list. */ { mstate replaced_arena; diff --git a/malloc/tst-malloc-thread-exit.c b/malloc/tst-malloc-thread-exit.c new file mode 100644 index 0000000..da7297e --- /dev/null +++ b/malloc/tst-malloc-thread-exit.c @@ -0,0 +1,217 @@ +/* Test malloc with concurrent thread termination. + Copyright (C) 2015 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 thread spawns a number of outer threads, equal to the arena + limit. The outer threads run a loop which start and join two + different kinds of threads: the first kind allocates (attaching an + arena to the thread; malloc_first_thread) and waits, the second + kind waits and allocates (wait_first_threads). Both kinds of + threads exit immediately after waiting. The hope is that this will + exhibit races in thread termination and arena management, + particularly related to the arena free list. */ + +#include +#include +#include +#include +#include +#include + +#define TIMEOUT 7 + +static bool termination_requested; +static int inner_thread_count = 4; +static size_t malloc_size = 32; + +static void +__attribute__ ((noinline, noclone)) +unoptimized_free (void *ptr) +{ + free (ptr); +} + +static void * +malloc_first_thread (void * closure) +{ + pthread_barrier_t *barrier = closure; + void *ptr = malloc (malloc_size); + if (ptr == NULL) + { + printf ("error: malloc: %m\n"); + abort (); + } + int ret = pthread_barrier_wait (barrier); + if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD) + { + errno = ret; + printf ("error: pthread_barrier_wait: %m\n"); + abort (); + } + unoptimized_free (ptr); + return NULL; +} + +static void * +wait_first_thread (void * closure) +{ + pthread_barrier_t *barrier = closure; + int ret = pthread_barrier_wait (barrier); + if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD) + { + errno = ret; + printf ("error: pthread_barrier_wait: %m\n"); + abort (); + } + void *ptr = malloc (malloc_size); + if (ptr == NULL) + { + printf ("error: malloc: %m\n"); + abort (); + } + unoptimized_free (ptr); + return NULL; +} + +static void * +outer_thread (void *closure) +{ + pthread_t *threads = calloc (sizeof (*threads), inner_thread_count); + if (threads == NULL) + { + printf ("error: calloc: %m\n"); + abort (); + } + + while (!__atomic_load_n (&termination_requested, __ATOMIC_RELAXED)) + { + pthread_barrier_t barrier; + int ret = pthread_barrier_init (&barrier, NULL, inner_thread_count + 1); + if (ret != 0) + { + errno = ret; + printf ("pthread_barrier_init: %m\n"); + abort (); + } + for (int i = 0; i < inner_thread_count; ++i) + { + void *(*func) (void *); + if ((i % 2) == 0) + func = malloc_first_thread; + else + func = wait_first_thread; + ret = pthread_create (threads + i, NULL, func, &barrier); + if (ret != 0) + { + errno = ret; + printf ("error: pthread_create: %m\n"); + abort (); + } + } + ret = pthread_barrier_wait (&barrier); + if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD) + { + errno = ret; + printf ("pthread_wait: %m\n"); + abort (); + } + for (int i = 0; i < inner_thread_count; ++i) + { + ret = pthread_join (threads[i], NULL); + if (ret != 0) + { + ret = errno; + printf ("error: pthread_join: %m\n"); + abort (); + } + } + ret = pthread_barrier_destroy (&barrier); + if (ret != 0) + { + ret = errno; + printf ("pthread_barrier_destroy: %m\n"); + abort (); + } + } + + free (threads); + + return NULL; +} + +static int +do_test (void) +{ + /* The number of top-level threads should be equal to the number of + arenas. See arena_get2. */ + long outer_thread_count = sysconf (_SC_NPROCESSORS_ONLN); + if (outer_thread_count >= 1) + { + /* See NARENAS_FROM_NCORES in malloc.c. */ + if (sizeof (long) == 4) + outer_thread_count *= 2; + else + outer_thread_count *= 8; + } + + /* Leave some room for shutting down all threads gracefully. */ + int timeout = TIMEOUT - 2; + + pthread_t *threads = calloc (sizeof (*threads), outer_thread_count); + if (threads == NULL) + { + printf ("error: calloc: %m\n"); + abort (); + } + + for (long i = 0; i < outer_thread_count; ++i) + { + int ret = pthread_create (threads + i, NULL, outer_thread, NULL); + if (ret != 0) + { + errno = ret; + printf ("error: pthread_create: %m\n"); + abort (); + } + } + + struct timespec ts = {timeout, 0}; + if (nanosleep (&ts, NULL)) + { + printf ("error: error: nanosleep: %m\n"); + abort (); + } + + __atomic_store_n (&termination_requested, true, __ATOMIC_RELAXED); + + for (long i = 0; i < outer_thread_count; ++i) + { + int ret = pthread_join (threads[i], NULL); + if (ret != 0) + { + errno = ret; + printf ("error: pthread_join: %m\n"); + abort (); + } + } + free (threads); + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" -- cgit v1.1 From eb8c932bac2e6c1273107b8a2721f382575b002a Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Wed, 13 Apr 2016 14:10:49 -0500 Subject: malloc: Fix list_lock/arena lock deadlock [BZ #19182] * malloc/arena.c (list_lock): Document lock ordering requirements. (free_list_lock): New lock. (ptmalloc_lock_all): Comment on free_list_lock. (ptmalloc_unlock_all2): Reinitialize free_list_lock. (detach_arena): Update comment. free_list_lock is now needed. (_int_new_arena): Use free_list_lock around detach_arena call. Acquire arena lock after list_lock. Add comment, including FIXME about incorrect synchronization. (get_free_list): Switch to free_list_lock. (reused_arena): Acquire free_list_lock around detach_arena call and attached threads counter update. Add two FIXMEs about incorrect synchronization. (arena_thread_freeres): Switch to free_list_lock. * malloc/malloc.c (struct malloc_state): Update comments to mention free_list_lock. (cherry picked from commit 90c400bd4904b0240a148f0b357a5cbc36179239) --- ChangeLog | 19 +++++++++++++++++ NEWS | 2 +- malloc/arena.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++---------- malloc/malloc.c | 6 +++--- 4 files changed, 75 insertions(+), 15 deletions(-) diff --git a/ChangeLog b/ChangeLog index fde59f1..e0cb376 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,24 @@ 2016-04-13 Florian Weimer + [BZ #19182] + * malloc/arena.c (list_lock): Document lock ordering requirements. + (free_list_lock): New lock. + (ptmalloc_lock_all): Comment on free_list_lock. + (ptmalloc_unlock_all2): Reinitialize free_list_lock. + (detach_arena): Update comment. free_list_lock is now needed. + (_int_new_arena): Use free_list_lock around detach_arena call. + Acquire arena lock after list_lock. Add comment, including FIXME + about incorrect synchronization. + (get_free_list): Switch to free_list_lock. + (reused_arena): Acquire free_list_lock around detach_arena call + and attached threads counter update. Add two FIXMEs about + incorrect synchronization. + (arena_thread_freeres): Switch to free_list_lock. + * malloc/malloc.c (struct malloc_state): Update comments to + mention free_list_lock. + +2016-04-13 Florian Weimer + [BZ #19243] * malloc/arena.c (get_free_list): Remove assert and adjust reference count handling. Add comment about reused_arena diff --git a/NEWS b/NEWS index 21c85ca..7b13178 100644 --- a/NEWS +++ b/NEWS @@ -25,7 +25,7 @@ Version 2.22.1 17905, 18420, 18421, 18480, 18589, 18743, 18778, 18781, 18787, 18796, 18870, 18887, 18921, 18928, 18969, 18985, 19003, 19018, 19048, 19058, - 19174, 19178, 19243, 19590, 19682, 19791, 19822, 19853, 19879. + 19174, 19178, 19182, 19243, 19590, 19682, 19791, 19822, 19853, 19879. * The getnetbyname implementation in nss_dns had a potentially unbounded alloca call (in the form of a call to strdupa), leading to a stack diff --git a/malloc/arena.c b/malloc/arena.c index f05c502..463d31d 100644 --- a/malloc/arena.c +++ b/malloc/arena.c @@ -67,10 +67,29 @@ extern int sanity_check_heap_info_alignment[(sizeof (heap_info) /* Thread specific data */ static tsd_key_t arena_key; -static mutex_t list_lock = MUTEX_INITIALIZER; + +/* Arena free list. free_list_lock synchronizes access to the + free_list variable below, and the next_free and attached_threads + members of struct malloc_state objects. No other locks must be + acquired after free_list_lock has been acquired. */ + +static mutex_t free_list_lock = MUTEX_INITIALIZER; static size_t narenas = 1; static mstate free_list; +/* list_lock prevents concurrent writes to the next member of struct + malloc_state objects. + + Read access to the next member is supposed to synchronize with the + atomic_write_barrier and the write to the next member in + _int_new_arena. This suffers from data races; see the FIXME + comments in _int_new_arena and reused_arena. + + list_lock also prevents concurrent forks. When list_lock is + acquired, no arena lock must be acquired, but it is permitted to + acquire arena locks after list_lock. */ +static mutex_t list_lock = MUTEX_INITIALIZER; + /* Mapped memory in non-main arenas (reliable only for NO_THREADS). */ static unsigned long arena_mem; @@ -210,6 +229,9 @@ ptmalloc_lock_all (void) if (__malloc_initialized < 1) return; + /* We do not acquire free_list_lock here because we completely + reconstruct free_list in ptmalloc_unlock_all2. */ + if (mutex_trylock (&list_lock)) { void *my_arena; @@ -291,6 +313,7 @@ ptmalloc_unlock_all2 (void) /* Push all arenas to the free list, except save_arena, which is attached to the current thread. */ + mutex_init (&free_list_lock); if (save_arena != NULL) ((mstate) save_arena)->attached_threads = 1; free_list = NULL; @@ -308,6 +331,7 @@ ptmalloc_unlock_all2 (void) if (ar_ptr == &main_arena) break; } + mutex_init (&list_lock); atfork_recursive_cntr = 0; } @@ -735,7 +759,7 @@ heap_trim (heap_info *heap, size_t pad) /* Create a new arena with initial size "size". */ /* If REPLACED_ARENA is not NULL, detach it from this thread. Must be - called while list_lock is held. */ + called while free_list_lock is held. */ static void detach_arena (mstate replaced_arena) { @@ -789,19 +813,34 @@ _int_new_arena (size_t size) tsd_getspecific (arena_key, replaced_arena); tsd_setspecific (arena_key, (void *) a); mutex_init (&a->mutex); - (void) mutex_lock (&a->mutex); (void) mutex_lock (&list_lock); - detach_arena (replaced_arena); - /* Add the new arena to the global list. */ a->next = main_arena.next; + /* FIXME: The barrier is an attempt to synchronize with read access + in reused_arena, which does not acquire list_lock while + traversing the list. */ atomic_write_barrier (); main_arena.next = a; (void) mutex_unlock (&list_lock); + (void) mutex_lock (&free_list_lock); + detach_arena (replaced_arena); + (void) mutex_unlock (&free_list_lock); + + /* Lock this arena. NB: Another thread may have been attached to + this arena because the arena is now accessible from the + main_arena.next list and could have been picked by reused_arena. + This can only happen for the last arena created (before the arena + limit is reached). At this point, some arena has to be attached + to two threads. We could acquire the arena lock before list_lock + to make it less likely that reused_arena picks this new arena, + but this could result in a deadlock with ptmalloc_lock_all. */ + + (void) mutex_lock (&a->mutex); + return a; } @@ -818,7 +857,7 @@ get_free_list (void) if (result != NULL) { - (void) mutex_lock (&list_lock); + (void) mutex_lock (&free_list_lock); result = free_list; if (result != NULL) { @@ -829,7 +868,7 @@ get_free_list (void) detach_arena (replaced_arena); } - (void) mutex_unlock (&list_lock); + (void) mutex_unlock (&free_list_lock); if (result != NULL) { @@ -849,6 +888,7 @@ static mstate reused_arena (mstate avoid_arena) { mstate result; + /* FIXME: Access to next_to_use suffers from data races. */ static mstate next_to_use; if (next_to_use == NULL) next_to_use = &main_arena; @@ -861,6 +901,7 @@ reused_arena (mstate avoid_arena) if (!arena_is_corrupt (result) && !mutex_trylock (&result->mutex)) goto out; + /* FIXME: This is a data race, see _int_new_arena. */ result = result->next; } while (result != next_to_use); @@ -895,10 +936,10 @@ out: mstate replaced_arena; tsd_getspecific (arena, replaced_arena); - (void) mutex_lock (&list_lock); + (void) mutex_lock (&free_list_lock); detach_arena (replaced_arena); ++result->attached_threads; - (void) mutex_unlock (&list_lock); + (void) mutex_unlock (&free_list_lock); } LIBC_PROBE (memory_arena_reuse, 2, result, avoid_arena); @@ -993,7 +1034,7 @@ arena_thread_freeres (void) if (a != NULL) { - (void) mutex_lock (&list_lock); + (void) mutex_lock (&free_list_lock); /* If this was the last attached thread for this arena, put the arena on the free list. */ assert (a->attached_threads > 0); @@ -1002,7 +1043,7 @@ arena_thread_freeres (void) a->next_free = free_list; free_list = a; } - (void) mutex_unlock (&list_lock); + (void) mutex_unlock (&free_list_lock); } } text_set_element (__libc_thread_subfreeres, arena_thread_freeres); diff --git a/malloc/malloc.c b/malloc/malloc.c index 037d4ff..5c84e62 100644 --- a/malloc/malloc.c +++ b/malloc/malloc.c @@ -1710,12 +1710,12 @@ struct malloc_state struct malloc_state *next; /* Linked list for free arenas. Access to this field is serialized - by list_lock in arena.c. */ + by free_list_lock in arena.c. */ struct malloc_state *next_free; /* Number of threads attached to this arena. 0 if the arena is on - the free list. Access to this field is serialized by list_lock - in arena.c. */ + the free list. Access to this field is serialized by + free_list_lock in arena.c. */ INTERNAL_SIZE_T attached_threads; /* Memory allocated from the system in this arena. */ -- cgit v1.1 From 13a601a0dfb468552c1eebf5c225392260f0bda2 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Wed, 13 Apr 2016 14:11:27 -0500 Subject: tst-malloc-thread-exit: Use fewer system resources (cherry picked from commit 2a38688932243b5b16fb12d84c7ac1138ce50363) --- ChangeLog | 7 +++++++ malloc/tst-malloc-thread-exit.c | 29 +++++++++++++++-------------- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/ChangeLog b/ChangeLog index e0cb376..d97ce5a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,12 @@ 2016-04-13 Florian Weimer + * malloc/tst-malloc-thread-exit.c: Include test-skeleton.c early. + (do_test): Limit the number of arenas, so that we can use fewer + outer threads. Limit timeout to 3 seconds, in preparation for a + larger TIMEOUT value. + +2016-04-13 Florian Weimer + [BZ #19182] * malloc/arena.c (list_lock): Document lock ordering requirements. (free_list_lock): New lock. diff --git a/malloc/tst-malloc-thread-exit.c b/malloc/tst-malloc-thread-exit.c index da7297e..7bce012 100644 --- a/malloc/tst-malloc-thread-exit.c +++ b/malloc/tst-malloc-thread-exit.c @@ -26,13 +26,17 @@ particularly related to the arena free list. */ #include +#include #include #include #include #include #include -#define TIMEOUT 7 +static int do_test (void); + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" static bool termination_requested; static int inner_thread_count = 4; @@ -156,20 +160,20 @@ outer_thread (void *closure) static int do_test (void) { - /* The number of top-level threads should be equal to the number of - arenas. See arena_get2. */ - long outer_thread_count = sysconf (_SC_NPROCESSORS_ONLN); - if (outer_thread_count >= 1) + /* The number of threads should be smaller than the number of + arenas, so that there will be some free arenas to add to the + arena free list. */ + enum { outer_thread_count = 2 }; + if (mallopt (M_ARENA_MAX, 8) == 0) { - /* See NARENAS_FROM_NCORES in malloc.c. */ - if (sizeof (long) == 4) - outer_thread_count *= 2; - else - outer_thread_count *= 8; + printf ("error: mallopt (M_ARENA_MAX) failed\n"); + return 1; } /* Leave some room for shutting down all threads gracefully. */ - int timeout = TIMEOUT - 2; + int timeout = 3; + if (timeout > TIMEOUT) + timeout = TIMEOUT - 1; pthread_t *threads = calloc (sizeof (*threads), outer_thread_count); if (threads == NULL) @@ -212,6 +216,3 @@ do_test (void) return 0; } - -#define TEST_FUNCTION do_test () -#include "../test-skeleton.c" -- cgit v1.1 From f95984beb2d3d61c71c14c10cdc5ab8fda321dec Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Wed, 13 Apr 2016 14:11:42 -0500 Subject: malloc: Update comment for list_lock (cherry picked from commit 7962541a32eff5597bc4207e781cfac8d1bb0d87) --- ChangeLog | 4 ++++ malloc/arena.c | 7 ++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index d97ce5a..fa02ac9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2016-04-13 Florian Weimer + * malloc/arena.c (list_lock): Update comment. + +2016-04-13 Florian Weimer + * malloc/tst-malloc-thread-exit.c: Include test-skeleton.c early. (do_test): Limit the number of arenas, so that we can use fewer outer threads. Limit timeout to 3 seconds, in preparation for a diff --git a/malloc/arena.c b/malloc/arena.c index 463d31d..f03dcb2 100644 --- a/malloc/arena.c +++ b/malloc/arena.c @@ -85,9 +85,10 @@ static mstate free_list; _int_new_arena. This suffers from data races; see the FIXME comments in _int_new_arena and reused_arena. - list_lock also prevents concurrent forks. When list_lock is - acquired, no arena lock must be acquired, but it is permitted to - acquire arena locks after list_lock. */ + list_lock also prevents concurrent forks. At the time list_lock is + acquired, no arena lock must have been acquired, but it is + permitted to acquire arena locks subsequently, while list_lock is + acquired. */ static mutex_t list_lock = MUTEX_INITIALIZER; /* Mapped memory in non-main arenas (reliable only for NO_THREADS). */ -- cgit v1.1 From d14837f6edd39d5c79c4cda7f7775c8f5e0ca20a Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Fri, 29 Apr 2016 09:33:07 +0200 Subject: glob: Simplify the interface for the GLOB_ALTDIRFUNC callback gl_readdir Previously, application code had to set up the d_namlen member if the target supported it, involving conditional compilation. After this change, glob will use the length of the string in d_name instead of d_namlen to determine the file name length. All glibc targets provide the d_type and d_ino members, and setting them as needed for gl_readdir is straightforward. Changing the behavior with regards to d_ino is left to a future cleanup. (cherry picked from commit 137fe72eca6923a00381a3ca9f0e7672c1f85e3f) --- ChangeLog | 15 +++++++++++++++ manual/examples/mkdirent.c | 42 ++++++++++++++++++++++++++++++++++++++++++ manual/pattern.texi | 39 ++++++++++++++++++++++++++++++++++++++- posix/bug-glob2.c | 2 +- posix/glob.c | 24 +++--------------------- posix/tst-gnuglob.c | 2 +- 6 files changed, 100 insertions(+), 24 deletions(-) create mode 100644 manual/examples/mkdirent.c diff --git a/ChangeLog b/ChangeLog index fa02ac9..be69ce3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +2016-04-29 Florian Weimer + + glob: Simplify and document the interface for the GLOB_ALTDIRFUNC + callback function gl_readdir. + * posix/glob.c (NAMELEN, CONVERT_D_NAMLEN): Remove. + (CONVERT_DIRENT_DIRENT64): Use strcpy instead of memcpy. + (glob_in_dir): Remove len. Use strdup instead of malloc and + memcpy to copy the name. + * manual/pattern.texi (Calling Glob): Document requirements for + implementations of the gl_readdir callback function. + * manual/examples/mkdirent.c: New example. + * posix/bug-glob2.c (my_readdir): Set d_ino to 1 unconditionally, + per the manual guidance. + * posix/tst-gnuglob.c (my_readdir): Likewise. + 2016-04-13 Florian Weimer * malloc/arena.c (list_lock): Update comment. diff --git a/manual/examples/mkdirent.c b/manual/examples/mkdirent.c new file mode 100644 index 0000000..f8400f4 --- /dev/null +++ b/manual/examples/mkdirent.c @@ -0,0 +1,42 @@ +/* Example for creating a struct dirent object for use with glob. + Copyright (C) 2016 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, if not, see . +*/ + +#include +#include +#include +#include +#include + +struct dirent * +mkdirent (const char *name) +{ + size_t dirent_size = offsetof (struct dirent, d_name) + 1; + size_t name_length = strlen (name); + size_t total_size = dirent_size + name_length; + if (total_size < dirent_size) + { + errno = ENOMEM; + return NULL; + } + struct dirent *result = malloc (total_size); + if (result == NULL) + return NULL; + result->d_type = DT_UNKNOWN; + result->d_ino = 1; /* Do not skip this entry. */ + memcpy (result->d_name, name, name_length + 1); + return result; +} diff --git a/manual/pattern.texi b/manual/pattern.texi index d1b9275..565e7eb 100644 --- a/manual/pattern.texi +++ b/manual/pattern.texi @@ -237,7 +237,44 @@ function used to read the contents of a directory. It is used if the @code{GLOB_ALTDIRFUNC} bit is set in the flag parameter. The type of this field is @w{@code{struct dirent *(*) (void *)}}. -This is a GNU extension. +An implementation of @code{gl_readdir} needs to initialize the following +members of the @code{struct dirent} object: + +@table @code +@item d_type +This member should be set to the file type of the entry if it is known. +Otherwise, the value @code{DT_UNKNOWN} can be used. The @code{glob} +function may use the specified file type to avoid callbacks in cases +where the file type indicates that the data is not required. + +@item d_ino +This member needs to be non-zero, otherwise @code{glob} may skip the +current entry and call the @code{gl_readdir} callback function again to +retrieve another entry. + +@item d_name +This member must be set to the name of the entry. It must be +null-terminated. +@end table + +The example below shows how to allocate a @code{struct dirent} object +containing a given name. + +@smallexample +@include mkdirent.c.texi +@end smallexample + +The @code{glob} function reads the @code{struct dirent} members listed +above and makes a copy of the file name in the @code{d_name} member +immediately after the @code{gl_readdir} callback function returns. +Future invocations of any of the callback functions may dealloacte or +reuse the buffer. It is the responsibility of the caller of the +@code{glob} function to allocate and deallocate the buffer, around the +call to @code{glob} or using the callback functions. For example, an +application could allocate the buffer in the @code{gl_readdir} callback +function, and deallocate it in the @code{gl_closedir} callback function. + +The @code{gl_readdir} member is a GNU extension. @item gl_opendir The address of an alternative implementation of the @code{opendir} diff --git a/posix/bug-glob2.c b/posix/bug-glob2.c index 1f302fe..ac8d79a 100644 --- a/posix/bug-glob2.c +++ b/posix/bug-glob2.c @@ -193,7 +193,7 @@ my_readdir (void *gdir) return NULL; } - dir->d.d_ino = dir->idx; + dir->d.d_ino = 1; /* glob should not skip this entry. */ #ifdef _DIRENT_HAVE_D_TYPE dir->d.d_type = filesystem[dir->idx].type; diff --git a/posix/glob.c b/posix/glob.c index d65e55d..56aa910 100644 --- a/posix/glob.c +++ b/posix/glob.c @@ -57,10 +57,8 @@ #if defined HAVE_DIRENT_H || defined __GNU_LIBRARY__ # include -# define NAMLEN(dirent) strlen((dirent)->d_name) #else # define dirent direct -# define NAMLEN(dirent) (dirent)->d_namlen # ifdef HAVE_SYS_NDIR_H # include # endif @@ -76,12 +74,6 @@ #endif -/* In GNU systems, defines this macro for us. */ -#ifdef _D_NAMLEN -# undef NAMLEN -# define NAMLEN(d) _D_NAMLEN(d) -#endif - /* When used in the GNU libc the symbol _DIRENT_HAVE_D_TYPE is available if the `d_type' member for `struct dirent' is available. HAVE_STRUCT_DIRENT_D_TYPE plays the same role in GNULIB. */ @@ -105,12 +97,6 @@ /* If the system has the `struct dirent64' type we use it internally. */ #if defined _LIBC && !defined COMPILE_GLOB64 -# if defined HAVE_DIRENT_H || defined __GNU_LIBRARY__ -# define CONVERT_D_NAMLEN(d64, d32) -# else -# define CONVERT_D_NAMLEN(d64, d32) \ - (d64)->d_namlen = (d32)->d_namlen; -# endif # if (defined POSIX || defined WINDOWS32) && !defined __GNU_LIBRARY__ # define CONVERT_D_INO(d64, d32) @@ -127,8 +113,7 @@ # endif # define CONVERT_DIRENT_DIRENT64(d64, d32) \ - memcpy ((d64)->d_name, (d32)->d_name, NAMLEN (d32) + 1); \ - CONVERT_D_NAMLEN (d64, d32) \ + strcpy ((d64)->d_name, (d32)->d_name); \ CONVERT_D_INO (d64, d32) \ CONVERT_D_TYPE (d64, d32) #endif @@ -1562,7 +1547,6 @@ glob_in_dir (const char *pattern, const char *directory, int flags, while (1) { const char *name; - size_t len; #if defined _LIBC && !defined COMPILE_GLOB64 struct dirent64 *d; union @@ -1630,12 +1614,10 @@ glob_in_dir (const char *pattern, const char *directory, int flags, names = newnames; cur = 0; } - len = NAMLEN (d); - names->name[cur] = (char *) malloc (len + 1); + names->name[cur] = strdup (d->d_name); if (names->name[cur] == NULL) goto memory_error; - *((char *) mempcpy (names->name[cur++], name, len)) - = '\0'; + ++cur; ++nfound; } } diff --git a/posix/tst-gnuglob.c b/posix/tst-gnuglob.c index d444999..b8cc042 100644 --- a/posix/tst-gnuglob.c +++ b/posix/tst-gnuglob.c @@ -211,7 +211,7 @@ my_readdir (void *gdir) return NULL; } - dir->d.d_ino = dir->idx; + dir->d.d_ino = 1; /* glob should not skip this entry. */ #ifdef _DIRENT_HAVE_D_TYPE dir->d.d_type = filesystem[dir->idx].type; -- cgit v1.1 From 46329bea58c143887c7109926d03901c0ccf81ed Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Wed, 4 May 2016 12:09:35 +0200 Subject: CVE-2016-1234: glob: Do not copy d_name field of struct dirent [BZ #19779] Instead, we store the data we need from the return value of readdir in an object of the new type struct readdir_result. This type is independent of the layout of struct dirent. (cherry picked from commit 5171f3079f2cc53e0548fc4967361f4d1ce9d7ea) --- ChangeLog | 21 ++++ NEWS | 7 +- posix/bug-glob2.c | 14 ++- posix/glob.c | 223 +++++++++++++++++++--------------- sysdeps/unix/sysv/linux/i386/glob64.c | 22 ++++ 5 files changed, 186 insertions(+), 101 deletions(-) diff --git a/ChangeLog b/ChangeLog index be69ce3..0471430 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,24 @@ +2016-05-04 Florian Weimer + + [BZ #19779] + CVE-2016-1234 + Avoid copying names of directory entries. + * posix/glob.c (DIRENT_MUST_BE, DIRENT_MIGHT_BE_SYMLINK) + (DIRENT_MIGHT_BE_DIR, CONVERT_D_INO, CONVERT_D_TYPE) + (CONVERT_DIRENT_DIRENT64, REAL_DIR_ENTRY): Remove macros. + (struct readdir_result): New type. + (D_TYPE_TO_RESULT, D_INO_TO_RESULT, READDIR_RESULT_INITIALIZER) + (GL_READDIR): New macros. + (readdir_result_might_be_symlink, readdir_result_might_be_dir) + (convert_dirent, convert_dirent64): New functions. + (glob_in_dir): Use struct readdir_result. Call convert_dirent or + convert_dirent64. Adjust references to the readdir result. + * sysdeps/unix/sysv/linux/i386/glob64.c: + (convert_dirent, GL_READDIR): Redefine for second file inclusion. + * posix/bug-glob2.c (LONG_NAME): Define. + (filesystem): Add LONG_NAME. + (my_DIR): Increase the size of room_for_dirent. + 2016-04-29 Florian Weimer glob: Simplify and document the interface for the GLOB_ALTDIRFUNC diff --git a/NEWS b/NEWS index 7b13178..fe7ce0f 100644 --- a/NEWS +++ b/NEWS @@ -25,7 +25,8 @@ Version 2.22.1 17905, 18420, 18421, 18480, 18589, 18743, 18778, 18781, 18787, 18796, 18870, 18887, 18921, 18928, 18969, 18985, 19003, 19018, 19048, 19058, - 19174, 19178, 19182, 19243, 19590, 19682, 19791, 19822, 19853, 19879. + 19174, 19178, 19182, 19243, 19590, 19682, 19791, 19822, 19853, 19879, + 19779. * The getnetbyname implementation in nss_dns had a potentially unbounded alloca call (in the form of a call to strdupa), leading to a stack @@ -43,6 +44,10 @@ Version 2.22.1 trigger this bug. Affected applications typically create create and destroy threads frequently. (Bug 19048 was reported and analyzed by Ericsson.) + +* The glob function suffered from a stack-based buffer overflow when it was + called with the GLOB_ALTDIRFUNC flag and encountered a long file name. + Reported by Alexander Cherepanov. (CVE-2016-1234) Version 2.22 diff --git a/posix/bug-glob2.c b/posix/bug-glob2.c index ac8d79a..e2964b2 100644 --- a/posix/bug-glob2.c +++ b/posix/bug-glob2.c @@ -40,6 +40,17 @@ # define PRINTF(fmt, args...) #endif +#define LONG_NAME \ + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \ + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \ + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \ + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \ + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \ + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \ + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \ + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \ + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \ + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" static struct { @@ -58,6 +69,7 @@ static struct { ".", 3, DT_DIR, 0755 }, { "..", 3, DT_DIR, 0755 }, { "a", 3, DT_REG, 0644 }, + { LONG_NAME, 3, DT_REG, 0644 }, { "unreadable", 2, DT_DIR, 0111 }, { ".", 3, DT_DIR, 0111 }, { "..", 3, DT_DIR, 0755 }, @@ -75,7 +87,7 @@ typedef struct int level; int idx; struct dirent d; - char room_for_dirent[NAME_MAX]; + char room_for_dirent[sizeof (LONG_NAME)]; } my_DIR; diff --git a/posix/glob.c b/posix/glob.c index 56aa910..60fa6c5 100644 --- a/posix/glob.c +++ b/posix/glob.c @@ -24,7 +24,9 @@ #include #include #include +#include #include +#include /* Outcomment the following line for production quality code. */ /* #define NDEBUG 1 */ @@ -73,69 +75,8 @@ # endif /* HAVE_VMSDIR_H */ #endif - -/* When used in the GNU libc the symbol _DIRENT_HAVE_D_TYPE is available - if the `d_type' member for `struct dirent' is available. - HAVE_STRUCT_DIRENT_D_TYPE plays the same role in GNULIB. */ -#if defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE -/* True if the directory entry D must be of type T. */ -# define DIRENT_MUST_BE(d, t) ((d)->d_type == (t)) - -/* True if the directory entry D might be a symbolic link. */ -# define DIRENT_MIGHT_BE_SYMLINK(d) \ - ((d)->d_type == DT_UNKNOWN || (d)->d_type == DT_LNK) - -/* True if the directory entry D might be a directory. */ -# define DIRENT_MIGHT_BE_DIR(d) \ - ((d)->d_type == DT_DIR || DIRENT_MIGHT_BE_SYMLINK (d)) - -#else /* !HAVE_D_TYPE */ -# define DIRENT_MUST_BE(d, t) false -# define DIRENT_MIGHT_BE_SYMLINK(d) true -# define DIRENT_MIGHT_BE_DIR(d) true -#endif /* HAVE_D_TYPE */ - -/* If the system has the `struct dirent64' type we use it internally. */ -#if defined _LIBC && !defined COMPILE_GLOB64 - -# if (defined POSIX || defined WINDOWS32) && !defined __GNU_LIBRARY__ -# define CONVERT_D_INO(d64, d32) -# else -# define CONVERT_D_INO(d64, d32) \ - (d64)->d_ino = (d32)->d_ino; -# endif - -# ifdef _DIRENT_HAVE_D_TYPE -# define CONVERT_D_TYPE(d64, d32) \ - (d64)->d_type = (d32)->d_type; -# else -# define CONVERT_D_TYPE(d64, d32) -# endif - -# define CONVERT_DIRENT_DIRENT64(d64, d32) \ - strcpy ((d64)->d_name, (d32)->d_name); \ - CONVERT_D_INO (d64, d32) \ - CONVERT_D_TYPE (d64, d32) -#endif - - -#if (defined POSIX || defined WINDOWS32) && !defined __GNU_LIBRARY__ -/* Posix does not require that the d_ino field be present, and some - systems do not provide it. */ -# define REAL_DIR_ENTRY(dp) 1 -#else -# define REAL_DIR_ENTRY(dp) (dp->d_ino != 0) -#endif /* POSIX */ - #include #include - -/* NAME_MAX is usually defined in or . */ -#include -#ifndef NAME_MAX -# define NAME_MAX (sizeof (((struct dirent *) 0)->d_name)) -#endif - #include #ifdef _LIBC @@ -180,8 +121,111 @@ static const char *next_brace_sub (const char *begin, int flags) __THROWNL; +/* A representation of a directory entry which does not depend on the + layout of struct dirent, or the size of ino_t. */ +struct readdir_result +{ + const char *name; +# if defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE + uint8_t type; +# endif + bool skip_entry; +}; + +# if defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE +/* Initializer based on the d_type member of struct dirent. */ +# define D_TYPE_TO_RESULT(source) (source)->d_type, + +/* True if the directory entry D might be a symbolic link. */ +static bool +readdir_result_might_be_symlink (struct readdir_result d) +{ + return d.type == DT_UNKNOWN || d.type == DT_LNK; +} + +/* True if the directory entry D might be a directory. */ +static bool +readdir_result_might_be_dir (struct readdir_result d) +{ + return d.type == DT_DIR || readdir_result_might_be_symlink (d); +} +# else /* defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE */ +# define D_TYPE_TO_RESULT(source) + +/* If we do not have type information, symbolic links and directories + are always a possibility. */ + +static bool +readdir_result_might_be_symlink (struct readdir_result d) +{ + return true; +} + +static bool +readdir_result_might_be_dir (struct readdir_result d) +{ + return true; +} + +# endif /* defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE */ + +# if (defined POSIX || defined WINDOWS32) && !defined __GNU_LIBRARY__ +/* Initializer for skip_entry. POSIX does not require that the d_ino + field be present, and some systems do not provide it. */ +# define D_INO_TO_RESULT(source) false, +# else +# define D_INO_TO_RESULT(source) (source)->d_ino == 0, +# endif + +/* Construct an initializer for a struct readdir_result object from a + struct dirent *. No copy of the name is made. */ +#define READDIR_RESULT_INITIALIZER(source) \ + { \ + source->d_name, \ + D_TYPE_TO_RESULT (source) \ + D_INO_TO_RESULT (source) \ + } + #endif /* !defined _LIBC || !defined GLOB_ONLY_P */ +/* Call gl_readdir on STREAM. This macro can be overridden to reduce + type safety if an old interface version needs to be supported. */ +#ifndef GL_READDIR +# define GL_READDIR(pglob, stream) ((pglob)->gl_readdir (stream)) +#endif + +/* Extract name and type from directory entry. No copy of the name is + made. If SOURCE is NULL, result name is NULL. Keep in sync with + convert_dirent64 below. */ +static struct readdir_result +convert_dirent (const struct dirent *source) +{ + if (source == NULL) + { + struct readdir_result result = { NULL, }; + return result; + } + struct readdir_result result = READDIR_RESULT_INITIALIZER (source); + return result; +} + +#ifndef COMPILE_GLOB64 +/* Like convert_dirent, but works on struct dirent64 instead. Keep in + sync with convert_dirent above. */ +static struct readdir_result +convert_dirent64 (const struct dirent64 *source) +{ + if (source == NULL) + { + struct readdir_result result = { NULL, }; + return result; + } + struct readdir_result result = READDIR_RESULT_INITIALIZER (source); + return result; +} +#endif + + #ifndef attribute_hidden # define attribute_hidden #endif @@ -1546,55 +1590,36 @@ glob_in_dir (const char *pattern, const char *directory, int flags, while (1) { - const char *name; -#if defined _LIBC && !defined COMPILE_GLOB64 - struct dirent64 *d; - union - { - struct dirent64 d64; - char room [offsetof (struct dirent64, d_name[0]) - + NAME_MAX + 1]; - } - d64buf; - - if (__glibc_unlikely (flags & GLOB_ALTDIRFUNC)) - { - struct dirent *d32 = (*pglob->gl_readdir) (stream); - if (d32 != NULL) - { - CONVERT_DIRENT_DIRENT64 (&d64buf.d64, d32); - d = &d64buf.d64; - } - else - d = NULL; - } - else - d = __readdir64 (stream); + struct readdir_result d; + { + if (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)) + d = convert_dirent (GL_READDIR (pglob, stream)); + else + { +#ifdef COMPILE_GLOB64 + d = convert_dirent (__readdir (stream)); #else - struct dirent *d = (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0) - ? ((struct dirent *) - (*pglob->gl_readdir) (stream)) - : __readdir (stream)); + d = convert_dirent64 (__readdir64 (stream)); #endif - if (d == NULL) + } + } + if (d.name == NULL) break; - if (! REAL_DIR_ENTRY (d)) + if (d.skip_entry) continue; /* If we shall match only directories use the information provided by the dirent call if possible. */ - if ((flags & GLOB_ONLYDIR) && !DIRENT_MIGHT_BE_DIR (d)) + if ((flags & GLOB_ONLYDIR) && !readdir_result_might_be_dir (d)) continue; - name = d->d_name; - - if (fnmatch (pattern, name, fnm_flags) == 0) + if (fnmatch (pattern, d.name, fnm_flags) == 0) { /* If the file we found is a symlink we have to make sure the target file exists. */ - if (!DIRENT_MIGHT_BE_SYMLINK (d) - || link_exists_p (dfd, directory, dirlen, name, pglob, - flags)) + if (!readdir_result_might_be_symlink (d) + || link_exists_p (dfd, directory, dirlen, d.name, + pglob, flags)) { if (cur == names->count) { @@ -1614,7 +1639,7 @@ glob_in_dir (const char *pattern, const char *directory, int flags, names = newnames; cur = 0; } - names->name[cur] = strdup (d->d_name); + names->name[cur] = strdup (d.name); if (names->name[cur] == NULL) goto memory_error; ++cur; diff --git a/sysdeps/unix/sysv/linux/i386/glob64.c b/sysdeps/unix/sysv/linux/i386/glob64.c index b4fcd1a..802c957 100644 --- a/sysdeps/unix/sysv/linux/i386/glob64.c +++ b/sysdeps/unix/sysv/linux/i386/glob64.c @@ -1,3 +1,21 @@ +/* Two glob variants with 64-bit support, for dirent64 and __olddirent64. + Copyright (C) 1998-2016 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 @@ -38,11 +56,15 @@ int __old_glob64 (const char *__pattern, int __flags, #undef dirent #define dirent __old_dirent64 +#undef GL_READDIR +# define GL_READDIR(pglob, stream) \ + ((struct __old_dirent64 *) (pglob)->gl_readdir (stream)) #undef __readdir #define __readdir(dirp) __old_readdir64 (dirp) #undef glob #define glob(pattern, flags, errfunc, pglob) \ __old_glob64 (pattern, flags, errfunc, pglob) +#define convert_dirent __old_convert_dirent #define glob_in_dir __old_glob_in_dir #define GLOB_ATTRIBUTE attribute_compat_text_section -- cgit v1.1 From 9d4fe83c8ccf2a4dcc87f905b474d3053c6c42b7 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Fri, 29 Apr 2016 10:35:34 +0200 Subject: CVE-2016-3706: getaddrinfo: stack overflow in hostent conversion [BZ #20010] When converting a struct hostent response to struct gaih_addrtuple, the gethosts macro (which is called from gaih_inet) used alloca, without malloc fallback for large responses. This commit changes this code to use calloc unconditionally. This commit also consolidated a second hostent-to-gaih_addrtuple conversion loop (in gaih_inet) to use the new conversion function. (cherry picked from commit 4ab2ab03d4351914ee53248dc5aef4a8c88ff8b9) --- ChangeLog | 10 ++++ NEWS | 7 ++- sysdeps/posix/getaddrinfo.c | 130 +++++++++++++++++++++++--------------------- 3 files changed, 85 insertions(+), 62 deletions(-) diff --git a/ChangeLog b/ChangeLog index 0471430..6dfe41a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2016-04-29 Florian Weimer + + [BZ #20010] + CVE-2016-3706 + * sysdeps/posix/getaddrinfo.c + (convert_hostent_to_gaih_addrtuple): New function. + (gethosts): Call convert_hostent_to_gaih_addrtuple. + (gaih_inet): Use convert_hostent_to_gaih_addrtuple to convert + AF_INET data. + 2016-05-04 Florian Weimer [BZ #19779] diff --git a/NEWS b/NEWS index fe7ce0f..99ff28a 100644 --- a/NEWS +++ b/NEWS @@ -26,7 +26,7 @@ Version 2.22.1 17905, 18420, 18421, 18480, 18589, 18743, 18778, 18781, 18787, 18796, 18870, 18887, 18921, 18928, 18969, 18985, 19003, 19018, 19048, 19058, 19174, 19178, 19182, 19243, 19590, 19682, 19791, 19822, 19853, 19879, - 19779. + 19779, 20010. * The getnetbyname implementation in nss_dns had a potentially unbounded alloca call (in the form of a call to strdupa), leading to a stack @@ -48,6 +48,11 @@ Version 2.22.1 * The glob function suffered from a stack-based buffer overflow when it was called with the GLOB_ALTDIRFUNC flag and encountered a long file name. Reported by Alexander Cherepanov. (CVE-2016-1234) + +* Previously, getaddrinfo copied large amounts of address data to the stack, + even after the fix for CVE-2013-4458 has been applied, potentially + resulting in a stack overflow. getaddrinfo now uses a heap allocation + instead. Reported by Michael Petlan. (CVE-2016-3706) Version 2.22 diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c index 31bb7e6..715e858 100644 --- a/sysdeps/posix/getaddrinfo.c +++ b/sysdeps/posix/getaddrinfo.c @@ -168,9 +168,58 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp, return 0; } +/* Convert struct hostent to a list of struct gaih_addrtuple objects. + h_name is not copied, and the struct hostent object must not be + deallocated prematurely. *RESULT must be NULL or a pointer to an + object allocated using malloc, which is freed. */ +static bool +convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, + int family, + struct hostent *h, + struct gaih_addrtuple **result) +{ + free (*result); + *result = NULL; + + /* Count the number of addresses in h->h_addr_list. */ + size_t count = 0; + for (char **p = h->h_addr_list; *p != NULL; ++p) + ++count; + + /* Report no data if no addresses are available, or if the incoming + address size is larger than what we can store. */ + if (count == 0 || h->h_length > sizeof (((struct gaih_addrtuple) {}).addr)) + return true; + + struct gaih_addrtuple *array = calloc (count, sizeof (*array)); + if (array == NULL) + return false; + + for (size_t i = 0; i < count; ++i) + { + if (family == AF_INET && req->ai_family == AF_INET6) + { + /* Perform address mapping. */ + array[i].family = AF_INET6; + memcpy(array[i].addr + 3, h->h_addr_list[i], sizeof (uint32_t)); + array[i].addr[2] = htonl (0xffff); + } + else + { + array[i].family = family; + memcpy (array[i].addr, h->h_addr_list[i], h->h_length); + } + array[i].next = array + i + 1; + } + array[0].name = h->h_name; + array[count - 1].next = NULL; + + *result = array; + return true; +} + #define gethosts(_family, _type) \ { \ - int i; \ int herrno; \ struct hostent th; \ struct hostent *h; \ @@ -219,36 +268,23 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp, } \ else if (h != NULL) \ { \ - for (i = 0; h->h_addr_list[i]; i++) \ + /* Make sure that addrmem can be freed. */ \ + if (!malloc_addrmem) \ + addrmem = NULL; \ + if (!convert_hostent_to_gaih_addrtuple (req, _family,h, &addrmem)) \ { \ - if (*pat == NULL) \ - { \ - *pat = __alloca (sizeof (struct gaih_addrtuple)); \ - (*pat)->scopeid = 0; \ - } \ - uint32_t *addr = (*pat)->addr; \ - (*pat)->next = NULL; \ - (*pat)->name = i == 0 ? strdupa (h->h_name) : NULL; \ - if (_family == AF_INET && req->ai_family == AF_INET6) \ - { \ - (*pat)->family = AF_INET6; \ - addr[3] = *(uint32_t *) h->h_addr_list[i]; \ - addr[2] = htonl (0xffff); \ - addr[1] = 0; \ - addr[0] = 0; \ - } \ - else \ - { \ - (*pat)->family = _family; \ - memcpy (addr, h->h_addr_list[i], sizeof(_type)); \ - } \ - pat = &((*pat)->next); \ + _res.options |= old_res_options & RES_USE_INET6; \ + result = -EAI_SYSTEM; \ + goto free_and_return; \ } \ + *pat = addrmem; \ + /* The conversion uses malloc unconditionally. */ \ + malloc_addrmem = true; \ \ if (localcanon != NULL && canon == NULL) \ canon = strdupa (localcanon); \ \ - if (_family == AF_INET6 && i > 0) \ + if (_family == AF_INET6 && *pat != NULL) \ got_ipv6 = true; \ } \ } @@ -612,44 +648,16 @@ gaih_inet (const char *name, const struct gaih_service *service, { if (h != NULL) { - int i; - /* We found data, count the number of addresses. */ - for (i = 0; h->h_addr_list[i]; ++i) - ; - if (i > 0 && *pat != NULL) - --i; - - if (__libc_use_alloca (alloca_used - + i * sizeof (struct gaih_addrtuple))) - addrmem = alloca_account (i * sizeof (struct gaih_addrtuple), - alloca_used); - else - { - addrmem = malloc (i - * sizeof (struct gaih_addrtuple)); - if (addrmem == NULL) - { - result = -EAI_MEMORY; - goto free_and_return; - } - malloc_addrmem = true; - } - - /* Now convert it into the list. */ - struct gaih_addrtuple *addrfree = addrmem; - for (i = 0; h->h_addr_list[i]; ++i) + /* We found data, convert it. */ + if (!convert_hostent_to_gaih_addrtuple + (req, AF_INET, h, &addrmem)) { - if (*pat == NULL) - { - *pat = addrfree++; - (*pat)->scopeid = 0; - } - (*pat)->next = NULL; - (*pat)->family = AF_INET; - memcpy ((*pat)->addr, h->h_addr_list[i], - h->h_length); - pat = &((*pat)->next); + result = -EAI_MEMORY; + goto free_and_return; } + *pat = addrmem; + /* The conversion uses malloc unconditionally. */ + malloc_addrmem = true; } } else -- cgit v1.1 From ccc3d71b28c2928df0b12bbed01f88a9e3e1f6f0 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Mon, 2 May 2016 12:07:09 +0200 Subject: hesiod: Remove RCS keywords (cherry picked from commit dbdc657dc0b962ef3ac61585c81e0828d8da42ee) --- ChangeLog | 6 ++++++ hesiod/hesiod.c | 4 ---- hesiod/hesiod.h | 4 ---- hesiod/hesiod_p.h | 4 ---- 4 files changed, 6 insertions(+), 12 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6dfe41a..97b120e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2016-05-02 Florian Weimer + + * hesiod/hesiod.h: Remove RCS keyword. + * hesiod/hesiod_p.h: Likewise. + * hesiod/hesiod.c: Likewise. + 2016-04-29 Florian Weimer [BZ #20010] diff --git a/hesiod/hesiod.c b/hesiod/hesiod.c index 657dabe..76b9bef 100644 --- a/hesiod/hesiod.c +++ b/hesiod/hesiod.c @@ -1,7 +1,3 @@ -#if defined(LIBC_SCCS) && !defined(lint) -static const char rcsid[] = "$BINDId: hesiod.c,v 1.21 2000/02/28 14:51:08 vixie Exp $"; -#endif - /* * Copyright (c) 1996,1999 by Internet Software Consortium. * diff --git a/hesiod/hesiod.h b/hesiod/hesiod.h index 82fce30..cb742b0 100644 --- a/hesiod/hesiod.h +++ b/hesiod/hesiod.h @@ -19,10 +19,6 @@ * This file is primarily maintained by and . */ -/* - * $BINDId: hesiod.h,v 1.7 1999/01/08 19:22:45 vixie Exp $ - */ - #ifndef _HESIOD_H_INCLUDED #define _HESIOD_H_INCLUDED diff --git a/hesiod/hesiod_p.h b/hesiod/hesiod_p.h index 5010d71..7bd2919 100644 --- a/hesiod/hesiod_p.h +++ b/hesiod/hesiod_p.h @@ -20,10 +20,6 @@ */ /* - * $BINDId: hesiod_p.h,v 1.9 1999/01/08 19:24:39 vixie Exp $ - */ - -/* * hesiod_p.h -- private definitions for the hesiod library */ -- cgit v1.1 From a64be6fb2f1317ce7039a4bb8638bd0c30c31e28 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Mon, 2 May 2016 15:25:20 +0200 Subject: hesiod: Always use thread-local resolver state [BZ #19573] The Hesiod implementation imported into glibc was enhanced to support caller-supplied resolver states. But its only consumer is nss_hesiod, and it supplies the thread-local resolver state. Therefore, this commit changes the Hesiod implementation to use the thread-local resolver state (_res) directly. This fixes bug 19573 because the Hesiod implementation no longer has to initialize and free any resolver state. To avoid any risk of interposition of ABI-incompatible Hesiod function implementations, this commit marks the Hesiod functions as hidden. (They were already hidden using a linker version script.) (cherry picked from commit 5018f16c6205404ba3aa7298dc8a3d45fbd46bfc) --- ChangeLog | 25 +++++++++++ NEWS | 4 +- hesiod/Makefile | 2 +- hesiod/hesiod.c | 85 +++++++++----------------------------- hesiod/hesiod.h | 30 ++++++++++---- hesiod/hesiod_p.h | 22 +++++++--- hesiod/nss_hesiod/hesiod-grp.c | 8 +--- hesiod/nss_hesiod/hesiod-init.c | 38 ----------------- hesiod/nss_hesiod/hesiod-proto.c | 5 +-- hesiod/nss_hesiod/hesiod-pwd.c | 5 +-- hesiod/nss_hesiod/hesiod-service.c | 5 +-- hesiod/nss_hesiod/nss_hesiod.h | 20 --------- 12 files changed, 91 insertions(+), 158 deletions(-) delete mode 100644 hesiod/nss_hesiod/hesiod-init.c delete mode 100644 hesiod/nss_hesiod/nss_hesiod.h diff --git a/ChangeLog b/ChangeLog index 97b120e..62794f2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,30 @@ 2016-05-02 Florian Weimer + [BZ #19573] + * hesiod/Makefile (libnss_hesiod-routines): Remove hesiod-init. + * hesiod/nss_hesiod/hesiod-init.c: Remove file. + * hesiod/nss_hesiod/nss_hesiod.h: Likewise. + * hesiod/hesiod.h (__hesiod_res_get, __hesiod_res_set): Remove. + (hesiod_init, hesiod_end, hesiod_to_bind, hesiod_resolve) + (hesiod_free_list): Mark as hidden. + * hesiod/hesiod_p (struct hesiod_p): Remove res, free_res, + res_set, res_get. + * hesiod/hesiod.c: Remove unnecessary forward declarations. + (init, __hesiod_res_get, __hesiod_res_set): Remove. + (hesiod_init): Remove obsolete res_ninit call. + (hesiod_end): Do not free resolver state. Do not invoke callback. + (hesiod_bind): Do not call init. + (get_txt_records): Use res_mkquery, res_send instead of + res_nmkquery, res_nsend. + * hesiod/nss_hesiod/hesiod-grp.c (lookup): Call hesiod_init + instead of _nss_hesiod_init. + (_nss_hesiod_initgroups_dyn): Likewise. + * hesiod/nss_hesiod/hesiod-proto.c (lookup): Likewise. + * hesiod/nss_hesiod/hesiod-pwd.c (lookup): Likewise. + * hesiod/nss_hesiod/hesiod-service.c (lookup): Likewise. + +2016-05-02 Florian Weimer + * hesiod/hesiod.h: Remove RCS keyword. * hesiod/hesiod_p.h: Likewise. * hesiod/hesiod.c: Likewise. diff --git a/NEWS b/NEWS index 99ff28a..94b731f 100644 --- a/NEWS +++ b/NEWS @@ -25,8 +25,8 @@ Version 2.22.1 17905, 18420, 18421, 18480, 18589, 18743, 18778, 18781, 18787, 18796, 18870, 18887, 18921, 18928, 18969, 18985, 19003, 19018, 19048, 19058, - 19174, 19178, 19182, 19243, 19590, 19682, 19791, 19822, 19853, 19879, - 19779, 20010. + 19174, 19178, 19182, 19243, 19573, 19590, 19682, 19791, 19822, 19853, + 19879, 19779, 20010. * The getnetbyname implementation in nss_dns had a potentially unbounded alloca call (in the form of a call to strdupa), leading to a stack diff --git a/hesiod/Makefile b/hesiod/Makefile index ac0bc01..cdd7730 100644 --- a/hesiod/Makefile +++ b/hesiod/Makefile @@ -28,7 +28,7 @@ extra-libs-others = $(extra-libs) subdir-dirs = nss_hesiod vpath %.c nss_hesiod -libnss_hesiod-routines := hesiod hesiod-grp hesiod-init hesiod-proto \ +libnss_hesiod-routines := hesiod hesiod-grp hesiod-proto \ hesiod-pwd hesiod-service # Build only shared library libnss_hesiod-inhibit-o = $(filter-out .os,$(object-suffixes)) diff --git a/hesiod/hesiod.c b/hesiod/hesiod.c index 76b9bef..5b13b3f 100644 --- a/hesiod/hesiod.c +++ b/hesiod/hesiod.c @@ -1,3 +1,20 @@ +/* Copyright (C) 1997-2016 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 + . */ + /* * Copyright (c) 1996,1999 by Internet Software Consortium. * @@ -48,18 +65,9 @@ /* Forward */ -int hesiod_init(void **context); -void hesiod_end(void *context); -char * hesiod_to_bind(void *context, const char *name, - const char *type); -char ** hesiod_resolve(void *context, const char *name, - const char *type); -void hesiod_free_list(void *context, char **list); - static int parse_config_file(struct hesiod_p *ctx, const char *filename); static char ** get_txt_records(struct hesiod_p *ctx, int class, const char *name); -static int init(struct hesiod_p *ctx); /* Public */ @@ -78,7 +86,6 @@ hesiod_init(void **context) { ctx->LHS = NULL; ctx->RHS = NULL; - ctx->res = NULL; /* Set default query classes. */ ctx->classes[0] = C_IN; ctx->classes[1] = C_HS; @@ -127,11 +134,6 @@ hesiod_init(void **context) { goto cleanup; } -#if 0 - if (res_ninit(ctx->res) < 0) - goto cleanup; -#endif - *context = ctx; return (0); @@ -148,12 +150,8 @@ hesiod_end(void *context) { struct hesiod_p *ctx = (struct hesiod_p *) context; int save_errno = errno; - if (ctx->res) - res_nclose(ctx->res); free(ctx->RHS); free(ctx->LHS); - if (ctx->res && ctx->free_res) - (*ctx->free_res)(ctx->res); free(ctx); __set_errno(save_errno); } @@ -228,10 +226,6 @@ hesiod_resolve(void *context, const char *name, const char *type) { if (bindname == NULL) return (NULL); - if (init(ctx) == -1) { - free(bindname); - return (NULL); - } retvec = get_txt_records(ctx, ctx->classes[0], bindname); @@ -361,13 +355,13 @@ get_txt_records(struct hesiod_p *ctx, int class, const char *name) { /* * Construct the query and send it. */ - n = res_nmkquery(ctx->res, QUERY, name, class, T_TXT, NULL, 0, + n = res_mkquery(QUERY, name, class, T_TXT, NULL, 0, NULL, qbuf, MAX_HESRESP); if (n < 0) { __set_errno(EMSGSIZE); return (NULL); } - n = res_nsend(ctx->res, qbuf, n, abuf, MAX_HESRESP); + n = res_send(qbuf, n, abuf, MAX_HESRESP); if (n < 0) { __set_errno(ECONNREFUSED); return (NULL); @@ -460,44 +454,3 @@ get_txt_records(struct hesiod_p *ctx, int class, const char *name) { free(list); return (NULL); } - -struct __res_state * -__hesiod_res_get(void *context) { - struct hesiod_p *ctx = context; - - if (!ctx->res) { - struct __res_state *res; - res = (struct __res_state *)calloc(1, sizeof *res); - if (res == NULL) - return (NULL); - __hesiod_res_set(ctx, res, free); - } - - return (ctx->res); -} - -void -__hesiod_res_set(void *context, struct __res_state *res, - void (*free_res)(void *)) { - struct hesiod_p *ctx = context; - - if (ctx->res && ctx->free_res) { - res_nclose(ctx->res); - (*ctx->free_res)(ctx->res); - } - - ctx->res = res; - ctx->free_res = free_res; -} - -static int -init(struct hesiod_p *ctx) { - - if (!ctx->res && !__hesiod_res_get(ctx)) - return (-1); - - if (__res_maybe_init (ctx->res, 0) == -1) - return (-1); - - return (0); -} diff --git a/hesiod/hesiod.h b/hesiod/hesiod.h index cb742b0..c4f5356 100644 --- a/hesiod/hesiod.h +++ b/hesiod/hesiod.h @@ -1,3 +1,20 @@ +/* Copyright (C) 1997-2016 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 + . */ + /* * Copyright (c) 1996,1999 by Internet Software Consortium. * @@ -22,15 +39,12 @@ #ifndef _HESIOD_H_INCLUDED #define _HESIOD_H_INCLUDED -int hesiod_init (void **context); -void hesiod_end (void *context); +int hesiod_init (void **context) attribute_hidden; +void hesiod_end (void *context) attribute_hidden; char * hesiod_to_bind (void *context, const char *name, - const char *type); + const char *type) attribute_hidden; char ** hesiod_resolve (void *context, const char *name, - const char *type); -void hesiod_free_list (void *context, char **list); -struct __res_state * __hesiod_res_get (void *context); -void __hesiod_res_set (void *context, struct __res_state *, - void (*)(void *)); + const char *type) attribute_hidden; +void hesiod_free_list (void *context, char **list) attribute_hidden; #endif /*_HESIOD_H_INCLUDED*/ diff --git a/hesiod/hesiod_p.h b/hesiod/hesiod_p.h index 7bd2919..1d6d826 100644 --- a/hesiod/hesiod_p.h +++ b/hesiod/hesiod_p.h @@ -1,3 +1,20 @@ +/* Copyright (C) 1997-2016 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 + . */ + /* * Copyright (c) 1996,1999 by Internet Software Consortium. * @@ -32,11 +49,6 @@ struct hesiod_p { char * LHS; /* normally ".ns" */ char * RHS; /* AKA the default hesiod domain */ - struct __res_state * res; /* resolver context */ - void (*free_res)(void *); - void (*res_set)(struct hesiod_p *, struct __res_state *, - void (*)(void *)); - struct __res_state * (*res_get)(struct hesiod_p *); int classes[2]; /* The class search order. */ }; diff --git a/hesiod/nss_hesiod/hesiod-grp.c b/hesiod/nss_hesiod/hesiod-grp.c index 0909a85..6ccb3bb 100644 --- a/hesiod/nss_hesiod/hesiod-grp.c +++ b/hesiod/nss_hesiod/hesiod-grp.c @@ -26,8 +26,6 @@ #include #include -#include "nss_hesiod.h" - /* Get the declaration of the parser function. */ #define ENTNAME grent #define STRUCTURE group @@ -58,8 +56,7 @@ lookup (const char *name, const char *type, struct group *grp, size_t len; int olderr = errno; - context = _nss_hesiod_init (); - if (context == NULL) + if (hesiod_init (&context) < 0) return NSS_STATUS_UNAVAIL; list = hesiod_resolve (context, name, type); @@ -179,8 +176,7 @@ _nss_hesiod_initgroups_dyn (const char *user, gid_t group, long int *start, gid_t *groups = *groupsp; int save_errno; - context = _nss_hesiod_init (); - if (context == NULL) + if (hesiod_init (&context) < 0) return NSS_STATUS_UNAVAIL; list = hesiod_resolve (context, user, "grplist"); diff --git a/hesiod/nss_hesiod/hesiod-init.c b/hesiod/nss_hesiod/hesiod-init.c deleted file mode 100644 index 755d3ad..0000000 --- a/hesiod/nss_hesiod/hesiod-init.c +++ /dev/null @@ -1,38 +0,0 @@ -/* Copyright (C) 2000-2015 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Mark Kettenis , 2000. - - 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 /* Needs to come before . */ -#include -#include -#include - -#include "nss_hesiod.h" - -void * -_nss_hesiod_init (void) -{ - void *context; - - if (hesiod_init (&context) == -1) - return NULL; - - /* Use the default (per-thread) resolver state. */ - __hesiod_res_set (context, &_res, NULL); - - return context; -} diff --git a/hesiod/nss_hesiod/hesiod-proto.c b/hesiod/nss_hesiod/hesiod-proto.c index 4073ee3..fcb09d1 100644 --- a/hesiod/nss_hesiod/hesiod-proto.c +++ b/hesiod/nss_hesiod/hesiod-proto.c @@ -25,8 +25,6 @@ #include #include -#include "nss_hesiod.h" - /* Declare a parser for Hesiod protocol entries. Although the format of the entries is identical to those in /etc/protocols, here is no predefined parser for us to use. */ @@ -68,8 +66,7 @@ lookup (const char *name, const char *type, struct protoent *proto, int found; int olderr = errno; - context = _nss_hesiod_init (); - if (context == NULL) + if (hesiod_init (&context) < 0) return NSS_STATUS_UNAVAIL; list = hesiod_resolve (context, name, type); diff --git a/hesiod/nss_hesiod/hesiod-pwd.c b/hesiod/nss_hesiod/hesiod-pwd.c index 94a8666..948a575 100644 --- a/hesiod/nss_hesiod/hesiod-pwd.c +++ b/hesiod/nss_hesiod/hesiod-pwd.c @@ -24,8 +24,6 @@ #include #include -#include "nss_hesiod.h" - /* Get the declaration of the parser function. */ #define ENTNAME pwent #define STRUCTURE passwd @@ -56,8 +54,7 @@ lookup (const char *name, const char *type, struct passwd *pwd, size_t len; int olderr = errno; - context = _nss_hesiod_init (); - if (context == NULL) + if (hesiod_init (&context) < 0) return NSS_STATUS_UNAVAIL; list = hesiod_resolve (context, name, type); diff --git a/hesiod/nss_hesiod/hesiod-service.c b/hesiod/nss_hesiod/hesiod-service.c index 0e53b77..dc89c2d 100644 --- a/hesiod/nss_hesiod/hesiod-service.c +++ b/hesiod/nss_hesiod/hesiod-service.c @@ -25,8 +25,6 @@ #include #include -#include "nss_hesiod.h" - /* Hesiod uses a format for service entries that differs from the traditional format. We therefore declare our own parser. */ @@ -69,8 +67,7 @@ lookup (const char *name, const char *type, const char *protocol, int found; int olderr = errno; - context = _nss_hesiod_init (); - if (context == NULL) + if (hesiod_init (&context) < 0) return NSS_STATUS_UNAVAIL; list = hesiod_resolve (context, name, type); diff --git a/hesiod/nss_hesiod/nss_hesiod.h b/hesiod/nss_hesiod/nss_hesiod.h deleted file mode 100644 index 79115e0..0000000 --- a/hesiod/nss_hesiod/nss_hesiod.h +++ /dev/null @@ -1,20 +0,0 @@ -/* Copyright (C) 2000-2015 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Mark Kettenis , 2000. - - 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 - . */ - -/* Initialize a Hesiod context. */ -extern void *_nss_hesiod_init (void); -- cgit v1.1 From 444fb8c27d9b0d1671ce1a441faf52b24305a332 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Mon, 23 May 2016 20:18:34 +0200 Subject: CVE-2016-4429: sunrpc: Do not use alloca in clntudp_call [BZ #20112] The call is technically in a loop, and under certain circumstances (which are quite difficult to reproduce in a test case), alloca can be invoked repeatedly during a single call to clntudp_call. As a result, the available stack space can be exhausted (even though individual alloca sizes are bounded implicitly by what can fit into a UDP packet, as a side effect of the earlier successful send operation). (cherry picked from commit bc779a1a5b3035133024b21e2f339fe4219fb11c) --- ChangeLog | 7 +++++++ NEWS | 6 +++++- sunrpc/clnt_udp.c | 10 +++++++++- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 62794f2..123274c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2016-05-23 Florian Weimer + + CVE-2016-4429 + [BZ #20112] + * sunrpc/clnt_udp.c (clntudp_call): Use malloc/free for the error + payload. + 2016-05-02 Florian Weimer [BZ #19573] diff --git a/NEWS b/NEWS index 94b731f..b0b981b 100644 --- a/NEWS +++ b/NEWS @@ -26,7 +26,7 @@ Version 2.22.1 17905, 18420, 18421, 18480, 18589, 18743, 18778, 18781, 18787, 18796, 18870, 18887, 18921, 18928, 18969, 18985, 19003, 19018, 19048, 19058, 19174, 19178, 19182, 19243, 19573, 19590, 19682, 19791, 19822, 19853, - 19879, 19779, 20010. + 19879, 19779, 20010, 20112. * The getnetbyname implementation in nss_dns had a potentially unbounded alloca call (in the form of a call to strdupa), leading to a stack @@ -53,6 +53,10 @@ Version 2.22.1 even after the fix for CVE-2013-4458 has been applied, potentially resulting in a stack overflow. getaddrinfo now uses a heap allocation instead. Reported by Michael Petlan. (CVE-2016-3706) + +* The Sun RPC UDP client could exhaust all available stack space when + flooded with crafted ICMP and UDP messages. Reported by Aldy Hernandez' + alloca plugin for GCC. (CVE-2016-4429) Version 2.22 diff --git a/sunrpc/clnt_udp.c b/sunrpc/clnt_udp.c index 6ffa5f2..c818caf 100644 --- a/sunrpc/clnt_udp.c +++ b/sunrpc/clnt_udp.c @@ -420,9 +420,15 @@ send_again: struct sock_extended_err *e; struct sockaddr_in err_addr; struct iovec iov; - char *cbuf = (char *) alloca (outlen + 256); + char *cbuf = malloc (outlen + 256); int ret; + if (cbuf == NULL) + { + cu->cu_error.re_errno = errno; + return (cu->cu_error.re_status = RPC_CANTRECV); + } + iov.iov_base = cbuf + 256; iov.iov_len = outlen; msg.msg_name = (void *) &err_addr; @@ -447,10 +453,12 @@ send_again: cmsg = CMSG_NXTHDR (&msg, cmsg)) if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_RECVERR) { + free (cbuf); e = (struct sock_extended_err *) CMSG_DATA(cmsg); cu->cu_error.re_errno = e->ee_errno; return (cu->cu_error.re_status = RPC_CANTRECV); } + free (cbuf); } #endif do -- cgit v1.1 From a79b262c1e68098701da6ac34bd1ba8ca8413961 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Wed, 1 Jun 2016 07:14:42 +0200 Subject: fork in libpthread cannot use IFUNC resolver [BZ #19861] This commit only addresses the fork case, the vfork case has to be a tail call, which is why the generic code needs an IFUNC resolver there. (cherry picked from commit f06f3f05b48c72e2c9b0fa78671f94fd22d67da8) --- ChangeLog | 9 +++++++++ nptl/pt-fork.c | 43 ++++++++++--------------------------------- 2 files changed, 19 insertions(+), 33 deletions(-) diff --git a/ChangeLog b/ChangeLog index 123274c..b09e88f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2016-06-01 Florian Weimer + + [BZ #19861] + Do not use IFUNC resolver with potentially unrelocated symbol. + * nptl/pt-fork.c [HAVE_IFUNC]: Remove. + (DEFINE_FORK): Remove macro and inline definition. + (fork_alias): Renamed from fork_ifunc. + (__fork_alias): Renamed from __fork_ifunc. + 2016-05-23 Florian Weimer CVE-2016-4429 diff --git a/nptl/pt-fork.c b/nptl/pt-fork.c index fd6544b..325ff2b6 100644 --- a/nptl/pt-fork.c +++ b/nptl/pt-fork.c @@ -25,33 +25,14 @@ the historical ABI requires it. For static linking, there is no need to provide anything here--the libc version will be linked in. For shared library ABI compatibility, there must be __fork and fork symbols in - libpthread.so; so we define them using IFUNC to redirect to the libc - function. */ + libpthread.so. -#if SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_22) - -# if HAVE_IFUNC - -static __typeof (fork) * -__attribute__ ((used)) -fork_resolve (void) -{ - return &__libc_fork; -} + With an IFUNC resolver, it would be possible to avoid the + indirection, but the IFUNC resolver might run before the + __libc_fork symbol has been relocated, in which case the IFUNC + resolver would not be able to provide the correct address. */ -# ifdef HAVE_ASM_SET_DIRECTIVE -# define DEFINE_FORK(name) \ - asm (".set " #name ", fork_resolve\n" \ - ".globl " #name "\n" \ - ".type " #name ", %gnu_indirect_function"); -# else -# define DEFINE_FORK(name) \ - asm (#name " = fork_resolve\n" \ - ".globl " #name "\n" \ - ".type " #name ", %gnu_indirect_function"); -# endif - -# else /* !HAVE_IFUNC */ +#if SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_22) static pid_t __attribute__ ((used)) fork_compat (void) @@ -59,14 +40,10 @@ fork_compat (void) return __libc_fork (); } -# define DEFINE_FORK(name) strong_alias (fork_compat, name) - -# endif /* HAVE_IFUNC */ - -DEFINE_FORK (fork_ifunc) -compat_symbol (libpthread, fork_ifunc, fork, GLIBC_2_0); +strong_alias (fork_compat, fork_alias) +compat_symbol (libpthread, fork_alias, fork, GLIBC_2_0); -DEFINE_FORK (__fork_ifunc) -compat_symbol (libpthread, __fork_ifunc, __fork, GLIBC_2_0); +strong_alias (fork_compat, __fork_alias) +compat_symbol (libpthread, __fork_alias, __fork, GLIBC_2_0); #endif -- cgit v1.1 From 861a38359832548ffed4e38dc5f7fecd0a5a0264 Mon Sep 17 00:00:00 2001 From: Yvan Roux Date: Fri, 15 Apr 2016 13:29:26 +0200 Subject: Suppress GCC 6 warning about ambiguous 'else' with -Wparentheses (cherry picked from commit df1cf48777fe4cd81ad7fb09ecbe5b31432b7c1c) --- ChangeLog | 5 +++++ nis/nis_call.c | 20 +++++++++++--------- stdlib/setenv.c | 26 ++++++++++++++------------ 3 files changed, 30 insertions(+), 21 deletions(-) diff --git a/ChangeLog b/ChangeLog index b09e88f..ad4640b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2016-04-15 Yvan Roux + + * stdlib/setenv.c (unsetenv): Fix ambiguous 'else'. + * nis/nis_call.c (nis_server_cache_add): Likewise. + 2016-06-01 Florian Weimer [BZ #19861] diff --git a/nis/nis_call.c b/nis/nis_call.c index 970415b..d98c385 100644 --- a/nis/nis_call.c +++ b/nis/nis_call.c @@ -680,16 +680,18 @@ nis_server_cache_add (const_nis_name name, int search_parent, /* Choose which entry should be evicted from the cache. */ loc = &nis_server_cache[0]; if (*loc != NULL) - for (i = 1; i < 16; ++i) - if (nis_server_cache[i] == NULL) - { + { + for (i = 1; i < 16; ++i) + if (nis_server_cache[i] == NULL) + { + loc = &nis_server_cache[i]; + break; + } + else if ((*loc)->uses > nis_server_cache[i]->uses + || ((*loc)->uses == nis_server_cache[i]->uses + && (*loc)->expires > nis_server_cache[i]->expires)) loc = &nis_server_cache[i]; - break; - } - else if ((*loc)->uses > nis_server_cache[i]->uses - || ((*loc)->uses == nis_server_cache[i]->uses - && (*loc)->expires > nis_server_cache[i]->expires)) - loc = &nis_server_cache[i]; + } old = *loc; *loc = new; diff --git a/stdlib/setenv.c b/stdlib/setenv.c index b9e0ba8..7a87d64 100644 --- a/stdlib/setenv.c +++ b/stdlib/setenv.c @@ -289,18 +289,20 @@ unsetenv (name) ep = __environ; if (ep != NULL) while (*ep != NULL) - if (!strncmp (*ep, name, len) && (*ep)[len] == '=') - { - /* Found it. Remove this pointer by moving later ones back. */ - char **dp = ep; - - do - dp[0] = dp[1]; - while (*dp++); - /* Continue the loop in case NAME appears again. */ - } - else - ++ep; + { + if (!strncmp (*ep, name, len) && (*ep)[len] == '=') + { + /* Found it. Remove this pointer by moving later ones back. */ + char **dp = ep; + + do + dp[0] = dp[1]; + while (*dp++); + /* Continue the loop in case NAME appears again. */ + } + else + ++ep; + } UNLOCK; -- cgit v1.1 From b5714a32f8d81c1e9834af8a4e12572e8d59195e Mon Sep 17 00:00:00 2001 From: Wilco Dijkstra Date: Fri, 18 Sep 2015 20:27:20 +0100 Subject: Fix several build failures with GCC6 due to unused static variables. 2015-09-18 Wilco Dijkstra * resolv/base64.c (rcsid): Remove unused static. * sysdeps/ieee754/dbl-64/atnat2.h (qpi1): Remove unused static. (tqpi1): Likewise. * sysdeps/ieee754/dbl-64/uexp.h (one): Likewise. * sysdeps/ieee754/dbl-64/upow.h (sqrt_2): Likewise. * sysdeps/ieee754/flt-32/e_log10f.c (one): Likewise. * sysdeps/ieee754/flt-32/s_cosf.c (one): Likewise. * sysdeps/ieee754/ldbl-128/e_lgammal_r.c (zero): Likewise. * sysdeps/ieee754/ldbl-128/s_erfl.c (half): Likewise. * sysdeps/ieee754/ldbl-128/s_log1pl.c (maxlog): Likewise. * timezone/private.h (time_t_min): Likewise. (time_t_max): Likewise. (cherry picked from commit 6565fcb6e189d67b5a3f321453daebb805056d73) --- ChangeLog | 15 +++++++++++++++ resolv/base64.c | 4 ---- sysdeps/ieee754/dbl-64/atnat2.h | 4 ---- sysdeps/ieee754/dbl-64/uexp.h | 2 +- sysdeps/ieee754/dbl-64/upow.h | 2 -- sysdeps/ieee754/flt-32/e_log10f.c | 2 -- sysdeps/ieee754/flt-32/s_cosf.c | 2 -- sysdeps/ieee754/ldbl-128/e_lgammal_r.c | 1 - sysdeps/ieee754/ldbl-128/s_erfl.c | 1 - sysdeps/ieee754/ldbl-128/s_log1pl.c | 1 - timezone/private.h | 10 ---------- 11 files changed, 16 insertions(+), 28 deletions(-) diff --git a/ChangeLog b/ChangeLog index ad4640b..d0cfdde 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +2015-09-18 Wilco Dijkstra + + * resolv/base64.c (rcsid): Remove unused static. + * sysdeps/ieee754/dbl-64/atnat2.h (qpi1): Remove unused + static. (tqpi1): Likewise. + * sysdeps/ieee754/dbl-64/uexp.h (one): Likewise. + * sysdeps/ieee754/dbl-64/upow.h (sqrt_2): Likewise. + * sysdeps/ieee754/flt-32/e_log10f.c (one): Likewise. + * sysdeps/ieee754/flt-32/s_cosf.c (one): Likewise. + * sysdeps/ieee754/ldbl-128/e_lgammal_r.c (zero): Likewise. + * sysdeps/ieee754/ldbl-128/s_erfl.c (half): Likewise. + * sysdeps/ieee754/ldbl-128/s_log1pl.c (maxlog): Likewise. + * timezone/private.h (time_t_min): Likewise. (time_t_max): + Likewise. + 2016-04-15 Yvan Roux * stdlib/setenv.c (unsetenv): Fix ambiguous 'else'. diff --git a/resolv/base64.c b/resolv/base64.c index ea584ed..519e5d2 100644 --- a/resolv/base64.c +++ b/resolv/base64.c @@ -40,10 +40,6 @@ * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. */ -#if !defined(LINT) && !defined(CODECENTER) -static const char rcsid[] = "$BINDId: base64.c,v 8.7 1999/10/13 16:39:33 vixie Exp $"; -#endif /* not lint */ - #include #include #include diff --git a/sysdeps/ieee754/dbl-64/atnat2.h b/sysdeps/ieee754/dbl-64/atnat2.h index e0d65af..82943f9 100644 --- a/sysdeps/ieee754/dbl-64/atnat2.h +++ b/sysdeps/ieee754/dbl-64/atnat2.h @@ -65,10 +65,8 @@ /**/ hpi1 = {{0x3c91a626, 0x33145c07} }, /* pi/2-hpi */ /**/ mhpi = {{0xbff921fb, 0x54442d18} }, /* -pi/2 */ /**/ qpi = {{0x3fe921fb, 0x54442d18} }, /* pi/4 */ -/**/ qpi1 = {{0x3c81a626, 0x33145c07} }, /* pi/4-qpi */ /**/ mqpi = {{0xbfe921fb, 0x54442d18} }, /* -pi/4 */ /**/ tqpi = {{0x4002d97c, 0x7f3321d2} }, /* 3pi/4 */ -/**/ tqpi1 = {{0x3c9a7939, 0x4c9e8a0a} }, /* 3pi/4-tqpi */ /**/ mtqpi = {{0xc002d97c, 0x7f3321d2} }, /* -3pi/4 */ /**/ u1 = {{0x3c314c2a, 0x00000000} }, /* 9.377e-19 */ /**/ u2 = {{0x3bf955e4, 0x00000000} }, /* 8.584e-20 */ @@ -129,10 +127,8 @@ /**/ hpi1 = {{0x33145c07, 0x3c91a626} }, /* pi/2-hpi */ /**/ mhpi = {{0x54442d18, 0xbff921fb} }, /* -pi/2 */ /**/ qpi = {{0x54442d18, 0x3fe921fb} }, /* pi/4 */ -/**/ qpi1 = {{0x33145c07, 0x3c81a626} }, /* pi/4-qpi */ /**/ mqpi = {{0x54442d18, 0xbfe921fb} }, /* -pi/4 */ /**/ tqpi = {{0x7f3321d2, 0x4002d97c} }, /* 3pi/4 */ -/**/ tqpi1 = {{0x4c9e8a0a, 0x3c9a7939} }, /* 3pi/4-tqpi */ /**/ mtqpi = {{0x7f3321d2, 0xc002d97c} }, /* -3pi/4 */ /**/ u1 = {{0x00000000, 0x3c314c2a} }, /* 9.377e-19 */ /**/ u2 = {{0x00000000, 0x3bf955e4} }, /* 8.584e-20 */ diff --git a/sysdeps/ieee754/dbl-64/uexp.h b/sysdeps/ieee754/dbl-64/uexp.h index 6817eaf..42b21f2 100644 --- a/sysdeps/ieee754/dbl-64/uexp.h +++ b/sysdeps/ieee754/dbl-64/uexp.h @@ -29,7 +29,7 @@ #include "mydefs.h" -const static double one = 1.0, zero = 0.0, hhuge = 1.0e300, tiny = 1.0e-300, +const static double zero = 0.0, hhuge = 1.0e300, tiny = 1.0e-300, err_0 = 1.000014, err_1 = 0.000016; const static int4 bigint = 0x40862002, badint = 0x40876000,smallint = 0x3C8fffff; diff --git a/sysdeps/ieee754/dbl-64/upow.h b/sysdeps/ieee754/dbl-64/upow.h index c8569a9..b4911e5 100644 --- a/sysdeps/ieee754/dbl-64/upow.h +++ b/sysdeps/ieee754/dbl-64/upow.h @@ -34,7 +34,6 @@ /**/ nZERO = {{0x80000000, 0}}, /* -0.0 */ /**/ INF = {{0x7ff00000, 0x00000000}}, /* INF */ /**/ nINF = {{0xfff00000, 0x00000000}}, /* -INF */ -/**/ sqrt_2 = {{0x3ff6a09e, 0x667f3bcc}}, /* sqrt(2) */ /**/ ln2a = {{0x3fe62e42, 0xfefa3800}}, /* ln(2) 43 bits */ /**/ ln2b = {{0x3d2ef357, 0x93c76730}}, /* ln(2)-ln2a */ /**/ bigu = {{0x4297ffff, 0xfffffd2c}}, /* 1.5*2**42 -724*2**-10 */ @@ -48,7 +47,6 @@ /**/ nZERO = {{0, 0x80000000}}, /* -0.0 */ /**/ INF = {{0x00000000, 0x7ff00000}}, /* INF */ /**/ nINF = {{0x00000000, 0xfff00000}}, /* -INF */ -/**/ sqrt_2 = {{0x667f3bcc, 0x3ff6a09e}}, /* sqrt(2) */ /**/ ln2a = {{0xfefa3800, 0x3fe62e42}}, /* ln(2) 43 bits */ /**/ ln2b = {{0x93c76730, 0x3d2ef357}}, /* ln(2)-ln2a */ /**/ bigu = {{0xfffffd2c, 0x4297ffff}}, /* 1.5*2**42 -724*2**-10 */ diff --git a/sysdeps/ieee754/flt-32/e_log10f.c b/sysdeps/ieee754/flt-32/e_log10f.c index 96f0e81..1daeef7 100644 --- a/sysdeps/ieee754/flt-32/e_log10f.c +++ b/sysdeps/ieee754/flt-32/e_log10f.c @@ -22,8 +22,6 @@ ivln10 = 4.3429449201e-01, /* 0x3ede5bd9 */ log10_2hi = 3.0102920532e-01, /* 0x3e9a2080 */ log10_2lo = 7.9034151668e-07; /* 0x355427db */ -static const float zero = 0.0; - float __ieee754_log10f(float x) { diff --git a/sysdeps/ieee754/flt-32/s_cosf.c b/sysdeps/ieee754/flt-32/s_cosf.c index 864ab27..0affd40 100644 --- a/sysdeps/ieee754/flt-32/s_cosf.c +++ b/sysdeps/ieee754/flt-32/s_cosf.c @@ -21,8 +21,6 @@ static char rcsid[] = "$NetBSD: s_cosf.c,v 1.4 1995/05/10 20:47:03 jtc Exp $"; #include #include -static const float one=1.0; - #ifndef COSF # define COSF_FUNC __cosf #else diff --git a/sysdeps/ieee754/ldbl-128/e_lgammal_r.c b/sysdeps/ieee754/ldbl-128/e_lgammal_r.c index d8a5e5b..c5c59ae 100644 --- a/sysdeps/ieee754/ldbl-128/e_lgammal_r.c +++ b/sysdeps/ieee754/ldbl-128/e_lgammal_r.c @@ -82,7 +82,6 @@ DIAG_IGNORE_NEEDS_COMMENT (4.6, "-Woverflow"); static const long double MAXLGM = 1.0485738685148938358098967157129705071571E4928L; DIAG_POP_NEEDS_COMMENT; static const long double one = 1.0L; -static const long double zero = 0.0L; static const long double huge = LDBL_MAX; /* log gamma(x) = ( x - 0.5 ) * log(x) - x + LS2PI + 1/x P(1/x^2) diff --git a/sysdeps/ieee754/ldbl-128/s_erfl.c b/sysdeps/ieee754/ldbl-128/s_erfl.c index fa4609f..08c80a3 100644 --- a/sysdeps/ieee754/ldbl-128/s_erfl.c +++ b/sysdeps/ieee754/ldbl-128/s_erfl.c @@ -140,7 +140,6 @@ deval (long double x, const long double *p, int n) static const long double tiny = 1e-4931L, - half = 0.5L, one = 1.0L, two = 2.0L, /* 2/sqrt(pi) - 1 */ diff --git a/sysdeps/ieee754/ldbl-128/s_log1pl.c b/sysdeps/ieee754/ldbl-128/s_log1pl.c index ff759bc..9609550 100644 --- a/sysdeps/ieee754/ldbl-128/s_log1pl.c +++ b/sysdeps/ieee754/ldbl-128/s_log1pl.c @@ -117,7 +117,6 @@ static const long double C2 = 1.428606820309417232121458176568075500134E-6L; static const long double sqrth = 0.7071067811865475244008443621048490392848L; /* ln (2^16384 * (1 - 2^-113)) */ -static const long double maxlog = 1.1356523406294143949491931077970764891253E4L; static const long double zero = 0.0L; long double diff --git a/timezone/private.h b/timezone/private.h index 4e8f4ae..ed19e06 100644 --- a/timezone/private.h +++ b/timezone/private.h @@ -326,16 +326,6 @@ const char * scheck(const char * string, const char * format); #define TYPE_SIGNED(type) (((type) -1) < 0) #endif /* !defined TYPE_SIGNED */ -/* The minimum and maximum finite time values. */ -static time_t const time_t_min = - (TYPE_SIGNED(time_t) - ? (time_t) -1 << (CHAR_BIT * sizeof (time_t) - 1) - : 0); -static time_t const time_t_max = - (TYPE_SIGNED(time_t) - ? - (~ 0 < 0) - ((time_t) -1 << (CHAR_BIT * sizeof (time_t) - 1)) - : -1); - #ifndef INT_STRLEN_MAXIMUM /* ** 302 / 1000 is log10(2.0) rounded up. -- cgit v1.1 From ee55e3c8fbc1b24aa725b5d6e6fe8c838bc92696 Mon Sep 17 00:00:00 2001 From: Steve Ellcey Date: Fri, 11 Dec 2015 09:19:37 -0800 Subject: Fix indentation. * sysdeps/ieee754/flt-32/k_rem_pio2f.c (__kernel_rem_pio2f): Fix indentation. (cherry picked from commit 976ef870542580cf5fed896c2c652b3e1a95f9da) --- ChangeLog | 5 +++++ sysdeps/ieee754/flt-32/k_rem_pio2f.c | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index d0cfdde..961fc2a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2015-12-11 Steve Ellcey + + * sysdeps/ieee754/flt-32/k_rem_pio2f.c (__kernel_rem_pio2f): + Fix indentation. + 2015-09-18 Wilco Dijkstra * resolv/base64.c (rcsid): Remove unused static. diff --git a/sysdeps/ieee754/flt-32/k_rem_pio2f.c b/sysdeps/ieee754/flt-32/k_rem_pio2f.c index 6f14d5b..153ebca 100644 --- a/sysdeps/ieee754/flt-32/k_rem_pio2f.c +++ b/sysdeps/ieee754/flt-32/k_rem_pio2f.c @@ -65,7 +65,9 @@ int __kernel_rem_pio2f(float *x, float *y, int e0, int nx, int prec, const int32 /* compute q[0],q[1],...q[jk] */ for (i=0;i<=jk;i++) { - for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j]; q[i] = fw; + for(j=0,fw=0.0;j<=jx;j++) + fw += x[j]*f[jx+i-j]; + q[i] = fw; } jz = jk; -- cgit v1.1 From bfb83ebd8f23971100d832b5343d0f7cf3b94353 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Thu, 2 Jun 2016 13:21:30 +0200 Subject: sysdeps/unix/sysv/linux/dl-openat64.c: Convert to ISO definition Partial backport of commit 9dd346ff431fc761f1b748bd4da8bb59f7652094. --- ChangeLog | 5 +++++ sysdeps/unix/sysv/linux/dl-openat64.c | 5 +---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index 961fc2a..2433fc2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2016-06-02 Florian Weimer + + * sysdeps/unix/sysv/linux/dl-openat64.c (openat64): Convert to + ISO-style variadic function definition. + 2015-12-11 Steve Ellcey * sysdeps/ieee754/flt-32/k_rem_pio2f.c (__kernel_rem_pio2f): diff --git a/sysdeps/unix/sysv/linux/dl-openat64.c b/sysdeps/unix/sysv/linux/dl-openat64.c index 732097d..ae15e3a 100644 --- a/sysdeps/unix/sysv/linux/dl-openat64.c +++ b/sysdeps/unix/sysv/linux/dl-openat64.c @@ -23,10 +23,7 @@ int -openat64 (dfd, file, oflag) - int dfd; - const char *file; - int oflag; +openat64 (int dfd, const char *file, int oflag, ...) { assert (!__OPEN_NEEDS_MODE (oflag)); -- cgit v1.1 From 6c45453cd52156c7d3ce5d2047753b70e72104d3 Mon Sep 17 00:00:00 2001 From: Torvald Riegel Date: Thu, 17 Dec 2015 23:30:03 +0100 Subject: Remove unused variable in math/atest-exp2.c. (cherry picked from commit 794950ed1d29853158d783d57f72260f5665afe5) --- ChangeLog | 4 ++++ math/atest-exp2.c | 5 ----- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2433fc2..fa21cd7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2015-12-18 Torvald Riegel + + * math/atest-exp2.c (mp_exp_m1): Remove. + 2016-06-02 Florian Weimer * sysdeps/unix/sysv/linux/dl-openat64.c (openat64): Convert to diff --git a/math/atest-exp2.c b/math/atest-exp2.c index 307c741..ffa73b1 100644 --- a/math/atest-exp2.c +++ b/math/atest-exp2.c @@ -53,11 +53,6 @@ static const mp1 mp_exp1 = { a784d904, 5190cfef, 324e7738, 926cfbe5, f4bf8d8d, 8c31d763) }; -static const mp1 mp_exp_m1 = { - CONSTSZ (0, 5e2d58d8, b3bcdf1a, badec782, 9054f90d, da9805aa, b56c7733, - 3024b9d0, a507daed, b16400bf, 472b4215, b8245b66, 9d90d27a) -}; - static const mp1 mp_log2 = { CONSTSZ (0, b17217f7, d1cf79ab, c9e3b398, 03f2f6af, 40f34326, 7298b62d, 8a0d175b, 8baafa2b, e7b87620, 6debac98, 559552fb, 4afa1b10) -- cgit v1.1 From cf3a189a0767e08a64f0a45e14d29d613ff1f5cc Mon Sep 17 00:00:00 2001 From: Stefan Liebler Date: Mon, 25 Jan 2016 12:44:46 +0100 Subject: S390: Fix build failure in test string/tst-endian.c with gcc 6. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Building string/tst-endian.c with gcc 6 produces an build warning/error on s390 (big endian machine): gcc tst-endian.c -c -std=gnu11 -fgnu89-inline -O2 or -O3 ... tst-endian.c: In function ‘do_test’: tst-endian.c:16:30: error: self-comparison always evaluates to false [-Werror=tautological-compare] if (htobe16 (be16toh (i)) != i) ^~ ... See definitions of htobexx, bexxtoh in string/endian.h: ... This patch silences these warnings with DIAG_* macros if build with gcc 6 and newer. The same warnings occur on little endian machines with the "htoleXX (leXXtoh (i)) != i" if-statements. ChangeLog: * string/tst-endian.c: Include . (do_test): Ignore tautological-compare warnings around "htobeXX (beXXtoh (i)) != i" and "htoleXX (leXXtoh (i)) != i" if-statements. (cherry picked from commit f69f887092914f6e1abcc2d622e4f5e56a6e1645) --- ChangeLog | 7 +++++++ string/tst-endian.c | 23 +++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/ChangeLog b/ChangeLog index fa21cd7..2d55a22 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2016-01-22 Stefan Liebler + + * string/tst-endian.c: Include . + (do_test): Ignore tautological-compare warnings around + "htobeXX (beXXtoh (i)) != i" and + "htoleXX (leXXtoh (i)) != i" if-statements. + 2015-12-18 Torvald Riegel * math/atest-exp2.c (mp_exp_m1): Remove. diff --git a/string/tst-endian.c b/string/tst-endian.c index 8684bb2..7d39131 100644 --- a/string/tst-endian.c +++ b/string/tst-endian.c @@ -3,6 +3,20 @@ #include #include #include +#include + +#if __GNUC_PREREQ (6, 0) +/* GCC 6.0 warns on big endian systems about: + htobeXX (beXXtoh (i)) != i + warning: self-comparison always evaluates to false [-Wtautological-compare] + because htobeXX(x) and beXXtoh(x) is defined to (x) + in string/endian.h on big endian systems. + The same applies to htoleXX/leXXtoh on little endian systems. */ +# define DIAG_IGNORE_NEEDS_COMMENT_TAUTOLOGICAL_COMPARE() \ + DIAG_IGNORE_NEEDS_COMMENT (6, "-Wtautological-compare") +#else +# define DIAG_IGNORE_NEEDS_COMMENT_TAUTOLOGICAL_COMPARE() +#endif static int do_test (void) @@ -13,6 +27,8 @@ do_test (void) { if (i < UINT64_C (65536)) { + DIAG_PUSH_NEEDS_COMMENT; + DIAG_IGNORE_NEEDS_COMMENT_TAUTOLOGICAL_COMPARE (); if (htobe16 (be16toh (i)) != i) { printf ("htobe16 (be16toh (%" PRIx64 ")) == %" PRIx16 "\n", @@ -25,6 +41,7 @@ do_test (void) i, (uint16_t) htole16 (le16toh (i))); result = 1; } + DIAG_POP_NEEDS_COMMENT; uint16_t n[2]; n[__BYTE_ORDER == __LITTLE_ENDIAN] = bswap_16 (i); @@ -45,6 +62,8 @@ do_test (void) if (i < UINT64_C (4294967296)) { + DIAG_PUSH_NEEDS_COMMENT; + DIAG_IGNORE_NEEDS_COMMENT_TAUTOLOGICAL_COMPARE (); if (htobe32 (be32toh (i)) != i) { printf ("htobe32 (be32toh (%" PRIx64 ")) == %" PRIx32 "\n", @@ -57,6 +76,7 @@ do_test (void) i, (uint32_t) htole32 (le32toh (i))); result = 1; } + DIAG_POP_NEEDS_COMMENT; uint32_t n[2]; n[__BYTE_ORDER == __LITTLE_ENDIAN] = bswap_32 (i); @@ -75,6 +95,8 @@ do_test (void) } } + DIAG_PUSH_NEEDS_COMMENT; + DIAG_IGNORE_NEEDS_COMMENT_TAUTOLOGICAL_COMPARE (); if (htobe64 (be64toh (i)) != i) { printf ("htobe64 (be64toh (%" PRIx64 ")) == %" PRIx64 "\n", @@ -87,6 +109,7 @@ do_test (void) i, htole64 (le64toh (i))); result = 1; } + DIAG_POP_NEEDS_COMMENT; uint64_t n[2]; n[__BYTE_ORDER == __LITTLE_ENDIAN] = bswap_64 (i); -- cgit v1.1 From 65ecfefc66f800f7ac881eb6048d5b2a8da79012 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Sat, 18 Jun 2016 19:11:23 +0200 Subject: MIPS, SPARC: fix wrong vfork aliases in libpthread.so With recent binutils versions the GNU libc fails to build on at least MISP and SPARC, with this kind of error: /home/aurel32/glibc/glibc-build/nptl/libpthread.so:(*IND*+0x0): multiple definition of `vfork@GLIBC_2.0' /home/aurel32/glibc/glibc-build/nptl/libpthread.so::(.text+0xee50): first defined here It appears that on these architectures pt-vfork.S includes vfork.S (through the alpha version of pt-vfork.S) and that the __vfork aliases are not conditionalized on IS_IN (libc) like on other architectures. Therefore the aliases are also wrongly included in libpthread.so. Fix this by properly conditionalizing the aliases like on other architectures. Changelog: * sysdeps/unix/sysv/linux/mips/vfork.S (__vfork): Conditionalize hidden_def, weak_alias and strong_alias on [IS_IN (libc)]. * sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S: Likewise. * sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S: Likewise. (cherry picked from commit 43c2948756bb6e144c7b871e827bba37d61ad3a3) --- ChangeLog | 7 +++++++ sysdeps/unix/sysv/linux/mips/vfork.S | 2 ++ sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S | 2 ++ sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S | 2 ++ 4 files changed, 13 insertions(+) diff --git a/ChangeLog b/ChangeLog index 2d55a22..0d3a802 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2016-06-18 Aurelien Jarno + + * sysdeps/unix/sysv/linux/mips/vfork.S (__vfork): Conditionalize + hidden_def, weak_alias and strong_alias on [IS_IN (libc)]. + * sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S: Likewise. + * sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S: Likewise. + 2016-01-22 Stefan Liebler * string/tst-endian.c: Include . diff --git a/sysdeps/unix/sysv/linux/mips/vfork.S b/sysdeps/unix/sysv/linux/mips/vfork.S index 8915bea..60a9131 100644 --- a/sysdeps/unix/sysv/linux/mips/vfork.S +++ b/sysdeps/unix/sysv/linux/mips/vfork.S @@ -106,6 +106,8 @@ L(error): #endif END(__vfork) +#if IS_IN (libc) libc_hidden_def(__vfork) weak_alias (__vfork, vfork) strong_alias (__vfork, __libc_vfork) +#endif diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S b/sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S index e71ecbc..3727877 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S @@ -44,6 +44,8 @@ ENTRY(__vfork) nop END(__vfork) +#if IS_IN (libc) libc_hidden_def (__vfork) weak_alias (__vfork, vfork) strong_alias (__vfork, __libc_vfork) +#endif diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S b/sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S index 6939ba3..7bf5165 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S @@ -44,6 +44,8 @@ ENTRY(__vfork) nop END(__vfork) +#if IS_IN (libc) libc_hidden_def (__vfork) weak_alias (__vfork, vfork) strong_alias (__vfork, __libc_vfork) +#endif -- cgit v1.1 From 19e9aaec52a4b61d208ace8ca952216b7d5c7175 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Tue, 21 Jun 2016 23:59:37 +0200 Subject: MIPS, SPARC: more fixes to the vfork aliases in libpthread.so Commit 43c29487 tried to fix the vfork aliases in libpthread.so on MIPS and SPARC, but failed to do it correctly, introducing an ABI change. This patch does the remaining changes needed to align the MIPS and SPARC vfork implementations with the other architectures. That way the the alpha version of pt-vfork.S works correctly for MIPS and SPARC. The changes for alpha were done in 82aab97c. Changelog: * sysdeps/unix/sysv/linux/mips/vfork.S (__vfork): Rename into __libc_vfork. (__vfork) [IS_IN (libc)]: Remove alias. (__libc_vfork) [IS_IN (libc)]: Define as an alias. * sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S: Likewise. * sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S: Likewise. (cherry picked from commit b87c1ec3fa398646f042a68f0ce0f7d09c1348c7) --- ChangeLog | 9 +++++++++ sysdeps/unix/sysv/linux/mips/vfork.S | 12 ++++++------ sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S | 8 ++++---- sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S | 8 ++++---- 4 files changed, 23 insertions(+), 14 deletions(-) diff --git a/ChangeLog b/ChangeLog index 0d3a802..32e3164 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2016-06-21 Aurelien Jarno + + * sysdeps/unix/sysv/linux/mips/vfork.S (__vfork): Rename into + __libc_vfork. + (__vfork) [IS_IN (libc)]: Remove alias. + (__libc_vfork) [IS_IN (libc)]: Define as an alias. + * sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S: Likewise. + * sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S: Likewise. + 2016-06-18 Aurelien Jarno * sysdeps/unix/sysv/linux/mips/vfork.S (__vfork): Conditionalize diff --git a/sysdeps/unix/sysv/linux/mips/vfork.S b/sysdeps/unix/sysv/linux/mips/vfork.S index 60a9131..e06c4e9 100644 --- a/sysdeps/unix/sysv/linux/mips/vfork.S +++ b/sysdeps/unix/sysv/linux/mips/vfork.S @@ -31,13 +31,13 @@ LOCALSZ= 1 FRAMESZ= (((NARGSAVE+LOCALSZ)*SZREG)+ALSZ)&ALMASK GPOFF= FRAMESZ-(1*SZREG) -NESTED(__vfork,FRAMESZ,sp) +NESTED(__libc_vfork,FRAMESZ,sp) #ifdef __PIC__ SETUP_GP #endif PTR_SUBU sp, FRAMESZ cfi_adjust_cfa_offset (FRAMESZ) - SETUP_GP64_REG (a5, __vfork) + SETUP_GP64_REG (a5, __libc_vfork) #ifdef __PIC__ SAVE_GP (GPOFF) #endif @@ -104,10 +104,10 @@ L(error): RESTORE_GP64_REG j __syscall_error #endif - END(__vfork) + END(__libc_vfork) #if IS_IN (libc) -libc_hidden_def(__vfork) -weak_alias (__vfork, vfork) -strong_alias (__vfork, __libc_vfork) +weak_alias (__libc_vfork, vfork) +strong_alias (__libc_vfork, __vfork) +libc_hidden_def (__vfork) #endif diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S b/sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S index 3727877..c42ba9b 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S @@ -21,7 +21,7 @@ .text .globl __syscall_error -ENTRY(__vfork) +ENTRY(__libc_vfork) ld [%g7 + PID], %o5 cmp %o5, 0 bne 1f @@ -42,10 +42,10 @@ ENTRY(__vfork) st %o5, [%g7 + PID] 1: retl nop -END(__vfork) +END(__libc_vfork) #if IS_IN (libc) +weak_alias (__libc_vfork, vfork) +strong_alias (__libc_vfork, __vfork) libc_hidden_def (__vfork) -weak_alias (__vfork, vfork) -strong_alias (__vfork, __libc_vfork) #endif diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S b/sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S index 7bf5165..506490c 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S @@ -21,7 +21,7 @@ .text .globl __syscall_error -ENTRY(__vfork) +ENTRY(__libc_vfork) ld [%g7 + PID], %o5 sethi %hi(0x80000000), %o3 cmp %o5, 0 @@ -42,10 +42,10 @@ ENTRY(__vfork) st %o5, [%g7 + PID] 1: retl nop -END(__vfork) +END(__libc_vfork) #if IS_IN (libc) +weak_alias (__libc_vfork, vfork) +strong_alias (__libc_vfork, __vfork) libc_hidden_def (__vfork) -weak_alias (__vfork, vfork) -strong_alias (__vfork, __libc_vfork) #endif -- cgit v1.1 From 4b59550eadd3692e4d327363328a41aa5da89af1 Mon Sep 17 00:00:00 2001 From: John David Anglin Date: Tue, 21 Jun 2016 18:35:22 -0400 Subject: hppa: fix loading of global pointer in _start [BZ #20277] The patched change fixes a regression for executables compiled with the -p option and linked with gcrt1.o. The executables crash on startup. This regression was introduced in 2.22 and was noticed in the gcc testsuite. (cherry picked from commit 9765ffa71030efd8bb4f2ea4ed6e020fcb4bb714) --- ChangeLog | 6 ++++++ NEWS | 2 +- sysdeps/hppa/start.S | 2 ++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 32e3164..320cf00 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2016-06-30 John David Anglin + + [BZ #20277] + * sysdeps/hppa/start.S (_start): Correct loading of global pointer + when SHARED is defined. + 2016-06-21 Aurelien Jarno * sysdeps/unix/sysv/linux/mips/vfork.S (__vfork): Rename into diff --git a/NEWS b/NEWS index b0b981b..923468d 100644 --- a/NEWS +++ b/NEWS @@ -26,7 +26,7 @@ Version 2.22.1 17905, 18420, 18421, 18480, 18589, 18743, 18778, 18781, 18787, 18796, 18870, 18887, 18921, 18928, 18969, 18985, 19003, 19018, 19048, 19058, 19174, 19178, 19182, 19243, 19573, 19590, 19682, 19791, 19822, 19853, - 19879, 19779, 20010, 20112. + 19879, 19779, 20010, 20112, 20277. * The getnetbyname implementation in nss_dns had a potentially unbounded alloca call (in the form of a call to strdupa), leading to a stack diff --git a/sysdeps/hppa/start.S b/sysdeps/hppa/start.S index cc4f243..d20caba 100644 --- a/sysdeps/hppa/start.S +++ b/sysdeps/hppa/start.S @@ -131,8 +131,10 @@ _start: stw %sp, -60(%sp) #ifdef SHARED + /* load global */ addil LT'.Lp__global, %r19 ldw RT'.Lp__global(%r1), %dp + ldw 0(%dp), %dp #else /* load global */ ldil L%$global$, %dp -- cgit v1.1 From b2c32b05c698b421081e1f9319603341956f2887 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Tue, 2 Aug 2016 12:24:50 +0200 Subject: malloc: Preserve arena free list/thread count invariant [BZ #20370] It is necessary to preserve the invariant that if an arena is on the free list, it has thread attach count zero. Otherwise, when arena_thread_freeres sees the zero attach count, it will add it, and without the invariant, an arena could get pushed to the list twice, resulting in a cycle. One possible execution trace looks like this: Thread 1 examines free list and observes it as empty. Thread 2 exits and adds its arena to the free list, with attached_threads == 0). Thread 1 selects this arena in reused_arena (not from the free list). Thread 1 increments attached_threads and attaches itself. (The arena remains on the free list.) Thread 1 exits, decrements attached_threads, and adds the arena to the free list. The final step creates a cycle in the usual way (by overwriting the next_free member with the former list head, while there is another list item pointing to the arena structure). tst-malloc-thread-exit exhibits this issue, but it was only visible with a debugger because the incorrect fix in bug 19243 removed the assert from get_free_list. (cherry picked from commit f88aab5d508c13ae4a88124e65773d7d827cd47b) --- ChangeLog | 8 ++++++++ malloc/arena.c | 41 ++++++++++++++++++++++++++++++++++++----- 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index 320cf00..3800353 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2016-08-02 Florian Weimer + + [BZ #20370] + * malloc/arena.c (get_free_list): Update comment. Assert that + arenas on the free list have no attached threads. + (remove_from_free_list): New function. + (reused_arena): Call it. + 2016-06-30 John David Anglin [BZ #20277] diff --git a/malloc/arena.c b/malloc/arena.c index f03dcb2..7c52633 100644 --- a/malloc/arena.c +++ b/malloc/arena.c @@ -846,8 +846,7 @@ _int_new_arena (size_t size) } -/* Remove an arena from free_list. The arena may be in use because it - was attached concurrently to a thread by reused_arena below. */ +/* Remove an arena from free_list. */ static mstate get_free_list (void) { @@ -865,7 +864,8 @@ get_free_list (void) free_list = result->next_free; /* The arena will be attached to this thread. */ - ++result->attached_threads; + assert (result->attached_threads == 0); + result->attached_threads = 1; detach_arena (replaced_arena); } @@ -882,6 +882,26 @@ get_free_list (void) return result; } +/* Remove the arena from the free list (if it is present). + free_list_lock must have been acquired by the caller. */ +static void +remove_from_free_list (mstate arena) +{ + mstate *previous = &free_list; + for (mstate p = free_list; p != NULL; p = p->next_free) + { + assert (p->attached_threads == 0); + if (p == arena) + { + /* Remove the requested arena from the list. */ + *previous = p->next_free; + break; + } + else + previous = &p->next_free; + } +} + /* Lock and return an arena that can be reused for memory allocation. Avoid AVOID_ARENA as we have already failed to allocate memory in it and it is currently locked. */ @@ -931,15 +951,26 @@ reused_arena (mstate avoid_arena) (void) mutex_lock (&result->mutex); out: - /* Attach the arena to the current thread. Note that we may have - selected an arena which was on free_list. */ + /* Attach the arena to the current thread. */ { mstate replaced_arena; tsd_getspecific (arena, replaced_arena); (void) mutex_lock (&free_list_lock); detach_arena (replaced_arena); + + /* We may have picked up an arena on the free list. We need to + preserve the invariant that no arena on the free list has a + positive attached_threads counter (otherwise, + arena_thread_freeres cannot use the counter to determine if the + arena needs to be put on the free list). We unconditionally + remove the selected arena from the free list. The caller of + reused_arena checked the free list and observed it to be empty, + so the list is very short. */ + remove_from_free_list (result); + ++result->attached_threads; + (void) mutex_unlock (&free_list_lock); } -- cgit v1.1 From 21ed68033a6732e4478926de06dd091ee7f1d4c1 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Wed, 17 Aug 2016 14:57:00 +0200 Subject: Do not override objects in libc.a in other static libraries [BZ #20452] With this change, we no longer add sysdep.o and similar objects which are present in libc.a to other static libraries. (cherry picked from commit d9067fca40b8aac156d73cfa44d6875813555a6c) --- ChangeLog | 34 +++++++++++++++++++++++++++++ sysdeps/ia64/nptl/Makefile | 1 + sysdeps/mips/Makefile | 1 + sysdeps/mips/nptl/Makefile | 1 + sysdeps/s390/nptl/Makefile | 1 + sysdeps/unix/alpha/Makefile | 1 + sysdeps/unix/sysv/linux/alpha/Makefile | 1 + sysdeps/unix/sysv/linux/i386/Makefile | 1 + sysdeps/unix/sysv/linux/ia64/Makefile | 1 + sysdeps/unix/sysv/linux/microblaze/Makefile | 3 ++- sysdeps/unix/sysv/linux/powerpc/Makefile | 2 ++ sysdeps/unix/sysv/linux/s390/Makefile | 1 + sysdeps/unix/sysv/linux/sparc/Makefile | 2 ++ sysdeps/unix/sysv/linux/tile/Makefile | 1 + 14 files changed, 50 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 3800353..c048c1a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,37 @@ +2016-08-17 Florian Weimer + + [BZ #20452] + Avoid additional copies of objects in libc.a in static libraries. + * sysdeps/ia64/nptl/Makefile (libpthread-shared-only-routines): + Add ptw-sysdep, ptw-sigblock, ptw-sigprocmask. + * sysdeps/mips/Makefile (librt-shared-only-routines): Add + rt-sysdep. + * sysdeps/mips/nptl/Makefile (libpthread-shared-only-routines): + Add nptl-sysdep. + * sysdeps/s390/nptl/Makefile (libpthread-shared-only-routines): + Add ptw-sysdep. + * sysdeps/unix/alpha/Makefile (librt-shared-only-routines): Add + rt-sysdep. + * sysdeps/unix/sysv/linux/alpha/Makefile + (libpthread-shared-only-routines): Add ptw-sysdep, + ptw-sigprocmask, ptw-rt_sigaction. + * sysdeps/unix/sysv/linux/ia64/Makefile + (librt-shared-only-routines): Add rt-sysdep. + * sysdeps/unix/sysv/linux/i386/Makefile + (libpthread-shared-only-routines): Add libc-do-syscall. + * sysdeps/unix/sysv/linux/microblaze/Makefile + (libpthread-shared-only-routines): Add sysdep. + * sysdeps/unix/sysv/linux/powerpc/Makefile + (librt-shared-only-routines): Add rt-sysdep. + (libpthread-shared-only-routines): Add sysdep. + * sysdeps/unix/sysv/linux/s390/Makefile + (librt-shared-only-routines): Add rt-sysdep. + * sysdeps/unix/sysv/linux/sparc/Makefile + (librt-shared-only-routines): Add rt-sysdep. + (libpthread-shared-only-routines): Add sysdep. + * sysdeps/unix/sysv/linux/tile/Makefile + (libpthread-shared-only-routines): Likewise. + 2016-08-02 Florian Weimer [BZ #20370] diff --git a/sysdeps/ia64/nptl/Makefile b/sysdeps/ia64/nptl/Makefile index fd8abbc..84e0b8b 100644 --- a/sysdeps/ia64/nptl/Makefile +++ b/sysdeps/ia64/nptl/Makefile @@ -21,4 +21,5 @@ endif ifeq ($(subdir),nptl) libpthread-routines += ptw-sysdep ptw-sigblock ptw-sigprocmask +libpthread-shared-only-routines += ptw-sysdep ptw-sigblock ptw-sigprocmask endif diff --git a/sysdeps/mips/Makefile b/sysdeps/mips/Makefile index 463b121..4dfaaa8 100644 --- a/sysdeps/mips/Makefile +++ b/sysdeps/mips/Makefile @@ -9,6 +9,7 @@ endif ifeq ($(subdir),rt) librt-sysdep_routines += rt-sysdep +librt-shared-only-routines += rt-sysdep endif ifeq ($(subdir),debug) diff --git a/sysdeps/mips/nptl/Makefile b/sysdeps/mips/nptl/Makefile index 46baad5..4a710ee 100644 --- a/sysdeps/mips/nptl/Makefile +++ b/sysdeps/mips/nptl/Makefile @@ -21,4 +21,5 @@ endif ifeq ($(subdir),nptl) libpthread-sysdep_routines += nptl-sysdep +libpthread-shared-only-routines += nptl-sysdep endif diff --git a/sysdeps/s390/nptl/Makefile b/sysdeps/s390/nptl/Makefile index 1333260..d105648 100644 --- a/sysdeps/s390/nptl/Makefile +++ b/sysdeps/s390/nptl/Makefile @@ -21,4 +21,5 @@ endif ifeq ($(subdir),nptl) libpthread-routines += ptw-sysdep +libpthread-shared-only-routines += ptw-sysdep endif diff --git a/sysdeps/unix/alpha/Makefile b/sysdeps/unix/alpha/Makefile index 441aa02..0660847 100644 --- a/sysdeps/unix/alpha/Makefile +++ b/sysdeps/unix/alpha/Makefile @@ -1,3 +1,4 @@ ifeq ($(subdir),rt) librt-sysdep_routines += rt-sysdep +librt-shared-only-routines += rt-sysdep endif diff --git a/sysdeps/unix/sysv/linux/alpha/Makefile b/sysdeps/unix/sysv/linux/alpha/Makefile index 3769bef..6e56125 100644 --- a/sysdeps/unix/sysv/linux/alpha/Makefile +++ b/sysdeps/unix/sysv/linux/alpha/Makefile @@ -41,4 +41,5 @@ endif # math ifeq ($(subdir),nptl) # pull in __syscall_error routine, __sigprocmask, __syscall_rt_sigaction libpthread-routines += ptw-sysdep ptw-sigprocmask ptw-rt_sigaction +libpthread-shared-only-routines += ptw-sysdep ptw-sigprocmask ptw-rt_sigaction endif diff --git a/sysdeps/unix/sysv/linux/i386/Makefile b/sysdeps/unix/sysv/linux/i386/Makefile index 80da593..b365c97 100644 --- a/sysdeps/unix/sysv/linux/i386/Makefile +++ b/sysdeps/unix/sysv/linux/i386/Makefile @@ -18,6 +18,7 @@ endif # libpthread uses six-argument inline syscalls. ifeq ($(subdir),nptl) libpthread-sysdep_routines += libc-do-syscall +libpthread-shared-only-routines += libc-do-syscall endif ifeq ($(subdir),resource) diff --git a/sysdeps/unix/sysv/linux/ia64/Makefile b/sysdeps/unix/sysv/linux/ia64/Makefile index 1de62c5..4d6766d 100644 --- a/sysdeps/unix/sysv/linux/ia64/Makefile +++ b/sysdeps/unix/sysv/linux/ia64/Makefile @@ -19,6 +19,7 @@ endif ifeq ($(subdir),rt) librt-routines += rt-sysdep +librt-shared-only-routines += rt-sysdep endif ifeq ($(subdir),nptl) diff --git a/sysdeps/unix/sysv/linux/microblaze/Makefile b/sysdeps/unix/sysv/linux/microblaze/Makefile index 44a838f..d178bc6 100644 --- a/sysdeps/unix/sysv/linux/microblaze/Makefile +++ b/sysdeps/unix/sysv/linux/microblaze/Makefile @@ -5,4 +5,5 @@ endif ifeq ($(subdir),nptl) # pull in __syscall_error routine libpthread-routines += sysdep -endif \ No newline at end of file +libpthread-shared-only-routines += sysdep +endif diff --git a/sysdeps/unix/sysv/linux/powerpc/Makefile b/sysdeps/unix/sysv/linux/powerpc/Makefile index c89ed9e..2cfb46e 100644 --- a/sysdeps/unix/sysv/linux/powerpc/Makefile +++ b/sysdeps/unix/sysv/linux/powerpc/Makefile @@ -8,6 +8,7 @@ abi-64-v2-condition := __WORDSIZE == 64 && _CALL_ELF == 2 ifeq ($(subdir),rt) librt-routines += rt-sysdep +librt-shared-only-routines += rt-sysdep endif ifeq ($(subdir),stdlib) @@ -34,4 +35,5 @@ ifeq ($(subdir),nptl) libpthread-routines += sysdep libpthread-sysdep_routines += elision-lock elision-unlock elision-timed \ elision-trylock +libpthread-shared-only-routines += sysdep endif diff --git a/sysdeps/unix/sysv/linux/s390/Makefile b/sysdeps/unix/sysv/linux/s390/Makefile index 497ffd5..f8ed013 100644 --- a/sysdeps/unix/sysv/linux/s390/Makefile +++ b/sysdeps/unix/sysv/linux/s390/Makefile @@ -6,6 +6,7 @@ abi-64-condition := __WORDSIZE == 64 ifeq ($(subdir),rt) librt-routines += rt-sysdep +librt-shared-only-routines += rt-sysdep endif ifeq ($(subdir),stdlib) diff --git a/sysdeps/unix/sysv/linux/sparc/Makefile b/sysdeps/unix/sysv/linux/sparc/Makefile index e67aecf..a67d199 100644 --- a/sysdeps/unix/sysv/linux/sparc/Makefile +++ b/sysdeps/unix/sysv/linux/sparc/Makefile @@ -6,6 +6,7 @@ abi-64-condition := __WORDSIZE == 64 ifeq ($(subdir),rt) librt-routines += rt-sysdep +librt-shared-only-routines += rt-sysdep endif ifeq ($(subdir),sysvipc) @@ -15,4 +16,5 @@ endif ifeq ($(subdir),nptl) # pull in __syscall_error routine libpthread-routines += sysdep +libpthread-shared-only-routines += sysdep endif diff --git a/sysdeps/unix/sysv/linux/tile/Makefile b/sysdeps/unix/sysv/linux/tile/Makefile index 1c1cfff..43acea3 100644 --- a/sysdeps/unix/sysv/linux/tile/Makefile +++ b/sysdeps/unix/sysv/linux/tile/Makefile @@ -25,4 +25,5 @@ endif ifeq ($(subdir),nptl) # pull in __syscall_error routine libpthread-routines += sysdep +libpthread-shared-only-routines += sysdep endif -- cgit v1.1 From 60022fbfba872422993caf6130ad4b92e74bb356 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Tue, 21 Jun 2016 21:29:21 +0200 Subject: malloc: Avoid premature fallback to mmap [BZ #20284] Before this change, the while loop in reused_arena which avoids returning a corrupt arena would never execute its body if the selected arena were not corrupt. As a result, result == begin after the loop, and the function returns NULL, triggering fallback to mmap. (cherry picked from commit a3b473373ee43a292f5ec68a7fda6b9cfb26a9b0) --- ChangeLog | 6 ++++++ malloc/arena.c | 10 ++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/ChangeLog b/ChangeLog index c048c1a..618515e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2016-06-21 Florian Weimer + + [BZ #20284] + * malloc/arena.c (reused_arena): Do not return NULL if we start + out with a non-corrupted arena. + 2016-08-17 Florian Weimer [BZ #20452] diff --git a/malloc/arena.c b/malloc/arena.c index 7c52633..5350992 100644 --- a/malloc/arena.c +++ b/malloc/arena.c @@ -938,14 +938,12 @@ reused_arena (mstate avoid_arena) { result = result->next; if (result == begin) - break; + /* We looped around the arena list. We could not find any + arena that was either not corrupted or not the one we + wanted to avoid. */ + return NULL; } - /* We could not find any arena that was either not corrupted or not the one - we wanted to avoid. */ - if (result == begin || result == avoid_arena) - return NULL; - /* No arena available without contention. Wait for the next in line. */ LIBC_PROBE (memory_arena_reuse_wait, 3, &result->mutex, result, avoid_arena); (void) mutex_lock (&result->mutex); -- cgit v1.1 From a85abfa92220239cad0a8a6b0f2a223f5e6472a9 Mon Sep 17 00:00:00 2001 From: Andreas Schwab Date: Thu, 18 Aug 2016 11:38:28 +0200 Subject: arm: mark __startcontext as .cantunwind (bug 20435) __startcontext marks the bottom of the call stack of the contexts created by makecontext. (cherry picked from commit 9e2ff6c9cc54c0b4402b8d49e4abe7000fde7617) Also includes the NEWS update, cherry-picked from commits 056dd72af83f5459ce6d545a49dea6dba7d635dc and 4d047efdbc55b0d68947cde682e5363d16a66294. --- ChangeLog | 6 ++++++ NEWS | 6 ++++++ sysdeps/unix/sysv/linux/arm/setcontext.S | 7 +++++++ 3 files changed, 19 insertions(+) diff --git a/ChangeLog b/ChangeLog index 618515e..c2a91e1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2016-08-15 Andreas Schwab + + [BZ #20435] + * sysdeps/unix/sysv/linux/arm/setcontext.S (__startcontext): Mark + as .cantunwind. + 2016-06-21 Florian Weimer [BZ #20284] diff --git a/NEWS b/NEWS index 923468d..a19f656 100644 --- a/NEWS +++ b/NEWS @@ -7,6 +7,12 @@ using `glibc' in the "product" field. Version 2.22.1 +* On ARM EABI (32-bit), generating a backtrace for execution contexts which + have been created with makecontext could fail to terminate due to a + missing .cantunwind annotation. This has been observed to lead to a hang + (denial of service) in some Go applications compiled with gccgo. Reported + by Andreas Schwab. (CVE-2016-6323) + * A stack-based buffer overflow was found in libresolv when invoked from libnss_dns, allowing specially crafted DNS responses to seize control of execution flow in the DNS client. The buffer overflow occurs in diff --git a/sysdeps/unix/sysv/linux/arm/setcontext.S b/sysdeps/unix/sysv/linux/arm/setcontext.S index 24c7294..926b65a 100644 --- a/sysdeps/unix/sysv/linux/arm/setcontext.S +++ b/sysdeps/unix/sysv/linux/arm/setcontext.S @@ -86,12 +86,19 @@ weak_alias(__setcontext, setcontext) /* Called when a makecontext() context returns. Start the context in R4 or fall through to exit(). */ + /* Unwind descriptors are looked up based on PC - 2, so we have to + make sure to mark the instruction preceding the __startcontext + label as .cantunwind. */ + .fnstart + .cantunwind + nop ENTRY(__startcontext) movs r0, r4 bne PLTJMP(__setcontext) @ New context was 0 - exit b PLTJMP(HIDDEN_JUMPTARGET(exit)) + .fnend END(__startcontext) #ifdef PIC -- cgit v1.1 From a8c871a8714b968b1a1e3e679919a2125fc968f3 Mon Sep 17 00:00:00 2001 From: Andreas Schwab Date: Thu, 16 Jun 2016 12:44:29 +0200 Subject: Return proper status from _nss_nis_initgroups_dyn (bug 20262) (cherry picked from commit 73fb56a4d51fd4437e4cde6dd3c8077a610f88a8) --- ChangeLog | 7 +++++++ nis/nss_nis/nis-initgroups.c | 16 +++++++++++----- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index c2a91e1..3541385 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2016-06-30 Andreas Schwab + + [BZ #20262] + * nis/nss_nis/nis-initgroups.c (_nss_nis_initgroups_dyn): Return + NSS_STATUS_SUCCESS when done. Return NSS_STATUS_TRYAGAIN when out + of memory. + 2016-08-15 Andreas Schwab [BZ #20435] diff --git a/nis/nss_nis/nis-initgroups.c b/nis/nss_nis/nis-initgroups.c index ed5c26b..5845b6d 100644 --- a/nis/nss_nis/nis-initgroups.c +++ b/nis/nss_nis/nis-initgroups.c @@ -266,7 +266,7 @@ _nss_nis_initgroups_dyn (const char *user, gid_t group, long int *start, tmpbuf = __alloca (buflen); - do + while (1) { while ((status = internal_getgrent_r (&grpbuf, tmpbuf, buflen, errnop, @@ -275,8 +275,11 @@ _nss_nis_initgroups_dyn (const char *user, gid_t group, long int *start, tmpbuf = extend_alloca (tmpbuf, buflen, 2 * buflen); if (status != NSS_STATUS_SUCCESS) - goto done; - + { + if (status == NSS_STATUS_NOTFOUND) + status = NSS_STATUS_SUCCESS; + goto done; + } g = &grpbuf; if (g->gr_gid != group) @@ -304,7 +307,11 @@ _nss_nis_initgroups_dyn (const char *user, gid_t group, long int *start, newgroups = realloc (groups, newsize * sizeof (*groups)); if (newgroups == NULL) - goto done; + { + status = NSS_STATUS_TRYAGAIN; + *errnop = errno; + goto done; + } *groupsp = groups = newgroups; *size = newsize; } @@ -316,7 +323,6 @@ _nss_nis_initgroups_dyn (const char *user, gid_t group, long int *start, } } } - while (status == NSS_STATUS_SUCCESS); done: while (intern.start != NULL) -- cgit v1.1 From 809cde4a640032f2f87319c9358be4fee8d6d7d5 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Sat, 11 Jun 2016 12:12:56 +0200 Subject: nss_db: Fix initialization of iteration position [BZ #20237] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When get*ent is called without a preceding set*ent, we need to set the initial iteration position in get*ent. Reproducer: Add “services: db files” to /etc/nsswitch.conf, then run “perl -e getservent”. It will segfault before this change, and exit silently after it. (cherry picked from commit 31d0a4fa646db8b8c97ce24e0ec0a7b73de4fca1) --- ChangeLog | 7 +++++++ nss/nss_db/db-XXX.c | 8 +++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 3541385..bb8d618 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2016-06-11 Florian Weimer + + [BZ #20237] + * nss/nss_db/db-XXX.c (set*ent): Reset entidx to NULL. + (get*ent): Set entidx to NULL during initialization. If entidx is + NULL, start iteration from the beginning. + 2016-06-30 Andreas Schwab [BZ #20262] diff --git a/nss/nss_db/db-XXX.c b/nss/nss_db/db-XXX.c index 4a0766a..70b58be 100644 --- a/nss/nss_db/db-XXX.c +++ b/nss/nss_db/db-XXX.c @@ -77,7 +77,7 @@ CONCAT(_nss_db_set,ENTNAME) (int stayopen) keep_db |= stayopen; /* Reset the sequential index. */ - entidx = (const char *) state.header + state.header->valstroffset; + entidx = NULL; } __libc_lock_unlock (lock); @@ -253,8 +253,14 @@ CONCAT(_nss_db_get,ENTNAME_r) (struct STRUCTURE *result, char *buffer, H_ERRNO_SET (NETDB_INTERNAL); goto out; } + entidx = NULL; } + /* Start from the beginning if freshly initialized or reset + requested by set*ent. */ + if (entidx == NULL) + entidx = (const char *) state.header + state.header->valstroffset; + status = NSS_STATUS_UNAVAIL; if (state.header != MAP_FAILED) { -- cgit v1.1 From 240ceafed7a00af8571d56db67a6b8854e418106 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Tue, 29 Mar 2016 11:27:32 +0200 Subject: nss_db: Propagate ERANGE error if parse_line fails [BZ #19837] Reproducer (needs to run as root): perl -e \ 'print "large:x:999:" . join(",", map {"user$_"} (1 .. 135))."\n"' \ >> /etc/group cd /var/db make getent -s db group After the fix, the last command should list the "large" group. The magic number 135 has been chosen so that the line is shorter than 1024 bytes, but the pointers required to encode the member array will cross the threshold, triggering the bug. (cherry picked from commit a6033052d08027f745867e5e346852da1959226c) --- ChangeLog | 6 ++++++ nss/nss_db/db-XXX.c | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index bb8d618..84d847e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2016-03-29 Florian Weimer + + [BZ #19837] + * nss/nss_db/db-XXX.c (_nss_db_getENTNAME_r): Propagate ERANGE + error if parse_line fails. + 2016-06-11 Florian Weimer [BZ #20237] diff --git a/nss/nss_db/db-XXX.c b/nss/nss_db/db-XXX.c index 70b58be..e13287a 100644 --- a/nss/nss_db/db-XXX.c +++ b/nss/nss_db/db-XXX.c @@ -294,8 +294,8 @@ CONCAT(_nss_db_get,ENTNAME_r) (struct STRUCTURE *result, char *buffer, } if (err < 0) { - H_ERRNO_SET (HOST_NOT_FOUND); - status = NSS_STATUS_NOTFOUND; + H_ERRNO_SET (NETDB_INTERNAL); + status = NSS_STATUS_TRYAGAIN; break; } -- cgit v1.1 From 0d6895748bf4531b5e516c47409d35d104f51642 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Sat, 11 Jun 2016 12:07:14 +0200 Subject: fopencookie: Mangle function pointers stored on the heap [BZ #20222] (cherry picked from commit 983fd5c41ab7e5a5c33922259ca1ac99b3b413f8) --- ChangeLog | 11 +++++++++++ libio/iofopncook.c | 49 +++++++++++++++++++++++++++++++++++-------------- 2 files changed, 46 insertions(+), 14 deletions(-) diff --git a/ChangeLog b/ChangeLog index 84d847e..1694de5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2016-06-11 Florian Weimer + + [BZ #20222] + * libio/iofopncook.c (_IO_cookie_read): Demangle callback pointer. + (_IO_cookie_write): Likewise. + (_IO_cookie_seek): Likewise. + (_IO_cookie_close): Likewise. + (_IO_old_cookie_seek): Likewise. + (set_callbacks): New function. + (_IO_cookie_init): Call set_callbacks to copy callbacks. + 2016-03-29 Florian Weimer [BZ #19837] diff --git a/libio/iofopncook.c b/libio/iofopncook.c index b845d29..3aad3d3 100644 --- a/libio/iofopncook.c +++ b/libio/iofopncook.c @@ -46,11 +46,13 @@ _IO_cookie_read (fp, buf, size) _IO_ssize_t size; { struct _IO_cookie_file *cfile = (struct _IO_cookie_file *) fp; + cookie_read_function_t *read_cb = cfile->__io_functions.read; + PTR_DEMANGLE (read_cb); - if (cfile->__io_functions.read == NULL) + if (read_cb == NULL) return -1; - return cfile->__io_functions.read (cfile->__cookie, buf, size); + return read_cb (cfile->__cookie, buf, size); } static _IO_ssize_t @@ -60,14 +62,16 @@ _IO_cookie_write (fp, buf, size) _IO_ssize_t size; { struct _IO_cookie_file *cfile = (struct _IO_cookie_file *) fp; + cookie_write_function_t *write_cb = cfile->__io_functions.write; + PTR_DEMANGLE (write_cb); - if (cfile->__io_functions.write == NULL) + if (write_cb == NULL) { fp->_flags |= _IO_ERR_SEEN; return 0; } - _IO_ssize_t n = cfile->__io_functions.write (cfile->__cookie, buf, size); + _IO_ssize_t n = write_cb (cfile->__cookie, buf, size); if (n < size) fp->_flags |= _IO_ERR_SEEN; @@ -81,9 +85,11 @@ _IO_cookie_seek (fp, offset, dir) int dir; { struct _IO_cookie_file *cfile = (struct _IO_cookie_file *) fp; + cookie_seek_function_t *seek_cb = cfile->__io_functions.seek; + PTR_DEMANGLE (seek_cb); - return ((cfile->__io_functions.seek == NULL - || (cfile->__io_functions.seek (cfile->__cookie, &offset, dir) + return ((seek_cb == NULL + || (seek_cb (cfile->__cookie, &offset, dir) == -1) || offset == (_IO_off64_t) -1) ? _IO_pos_BAD : offset); @@ -94,11 +100,13 @@ _IO_cookie_close (fp) _IO_FILE *fp; { struct _IO_cookie_file *cfile = (struct _IO_cookie_file *) fp; + cookie_close_function_t *close_cb = cfile->__io_functions.close; + PTR_DEMANGLE (close_cb); - if (cfile->__io_functions.close == NULL) + if (close_cb == NULL) return 0; - return cfile->__io_functions.close (cfile->__cookie); + return close_cb (cfile->__cookie); } @@ -140,6 +148,19 @@ static const struct _IO_jump_t _IO_cookie_jumps = { }; +/* Copy the callbacks from SOURCE to *TARGET, with pointer + mangling. */ +static void +set_callbacks (_IO_cookie_io_functions_t *target, + _IO_cookie_io_functions_t source) +{ + PTR_MANGLE (source.read); + PTR_MANGLE (source.write); + PTR_MANGLE (source.seek); + PTR_MANGLE (source.close); + *target = source; +} + void _IO_cookie_init (struct _IO_cookie_file *cfile, int read_write, void *cookie, _IO_cookie_io_functions_t io_functions) @@ -148,7 +169,7 @@ _IO_cookie_init (struct _IO_cookie_file *cfile, int read_write, _IO_JUMPS (&cfile->__fp) = &_IO_cookie_jumps; cfile->__cookie = cookie; - cfile->__io_functions = io_functions; + set_callbacks (&cfile->__io_functions, io_functions); _IO_file_init (&cfile->__fp); @@ -223,14 +244,14 @@ _IO_old_cookie_seek (fp, offset, dir) int dir; { struct _IO_cookie_file *cfile = (struct _IO_cookie_file *) fp; - int (*seek) (_IO_FILE *, _IO_off_t, int); - int ret; + int (*seek_cb) (_IO_FILE *, _IO_off_t, int) + = (int (*) (_IO_FILE *, _IO_off_t, int)) cfile->__io_functions.seek;; + PTR_DEMANGLE (seek_cb); - seek = (int (*)(_IO_FILE *, _IO_off_t, int)) cfile->__io_functions.seek; - if (seek == NULL) + if (seek_cb == NULL) return _IO_pos_BAD; - ret = seek (cfile->__cookie, offset, dir); + int ret = seek_cb (cfile->__cookie, offset, dir); return (ret == -1) ? _IO_pos_BAD : ret; } -- cgit v1.1 From 718da076cbb4675b1d7ae735bc1f3698618cccec Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Thu, 18 Aug 2016 11:15:42 +0200 Subject: argp: Do not override GCC keywords with macros [BZ #16907] glibc provides fallback definitions already. It is not necessary to suppress warnings for unknown attributes because GCC does this automatically for system headers. This commit does not sync with gnulib because gnulib has started to use _GL_* macros in the header file, which are arguably in the gnulib implementation space and not suitable for an installed glibc header file. (cherry picked from commit 2c820533c61fed175390bc6058afbbe42d2edc37) --- ChangeLog | 8 ++++++++ argp/argp-fmtstream.h | 19 ++++--------------- argp/argp.h | 42 ++---------------------------------------- 3 files changed, 14 insertions(+), 55 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1694de5..e15b594 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2016-08-18 Florian Weimer + + [BZ #16907] + * argp/argp.h: Switch to __BEGIN_DECLS and __END_DECLS. + (__THROW, __NTH, __attribute__, __restrict): Remove definitions. + * argp/argp-fmtstream.h: Add __BEGIN_DECLS and __END_DECLS. + (__attribute__): Remove definition. + 2016-06-11 Florian Weimer [BZ #20222] diff --git a/argp/argp-fmtstream.h b/argp/argp-fmtstream.h index 6dd087a..8f8192a 100644 --- a/argp/argp-fmtstream.h +++ b/argp/argp-fmtstream.h @@ -29,21 +29,6 @@ #include #include -#ifndef __attribute__ -/* This feature is available in gcc versions 2.5 and later. */ -# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || \ - defined __STRICT_ANSI__ -# define __attribute__(Spec) /* empty */ -# endif -/* The __-protected variants of `format' and `printf' attributes - are accepted by gcc versions 2.6.4 (effectively 2.7) and later. */ -# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7) || \ - defined __STRICT_ANSI__ -# define __format__ format -# define __printf__ printf -# endif -#endif - #if defined (__GNU_LIBRARY__) && defined (HAVE_LINEWRAP_H) /* line_wrap_stream is available, so use that. */ #define ARGP_FMTSTREAM_USE_LINEWRAP @@ -111,6 +96,8 @@ struct argp_fmtstream typedef struct argp_fmtstream *argp_fmtstream_t; +__BEGIN_DECLS + /* Return an argp_fmtstream that outputs to STREAM, and which prefixes lines written on it with LMARGIN spaces and limits them to RMARGIN columns total. If WMARGIN >= 0, words that extend past RMARGIN are wrapped by @@ -297,6 +284,8 @@ __argp_fmtstream_point (argp_fmtstream_t __fs) #endif /* __OPTIMIZE__ */ +__END_DECLS + #endif /* ARGP_FMTSTREAM_USE_LINEWRAP */ #endif /* argp-fmtstream.h */ diff --git a/argp/argp.h b/argp/argp.h index 40bf5e6..0771921 100644 --- a/argp/argp.h +++ b/argp/argp.h @@ -28,48 +28,12 @@ #define __need_error_t #include -#ifndef __THROW -# define __THROW -#endif -#ifndef __NTH -# define __NTH(fct) fct __THROW -#endif - -#ifndef __attribute__ -/* This feature is available in gcc versions 2.5 and later. */ -# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || \ - defined __STRICT_ANSI__ -# define __attribute__(Spec) /* empty */ -# endif -/* The __-protected variants of `format' and `printf' attributes - are accepted by gcc versions 2.6.4 (effectively 2.7) and later. */ -# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7) || \ - defined __STRICT_ANSI__ -# define __format__ format -# define __printf__ printf -# endif -#endif - -/* GCC 2.95 and later have "__restrict"; C99 compilers have - "restrict", and "configure" may have defined "restrict". */ -#ifndef __restrict -# if ! (2 < __GNUC__ || (2 == __GNUC__ && 95 <= __GNUC_MINOR__)) -# if defined restrict || 199901L <= __STDC_VERSION__ -# define __restrict restrict -# else -# define __restrict -# endif -# endif -#endif - #ifndef __error_t_defined typedef int error_t; # define __error_t_defined #endif -#ifdef __cplusplus -extern "C" { -#endif +__BEGIN_DECLS /* A description of a particular option. A pointer to an array of these is passed in the OPTIONS field of an argp structure. Each option @@ -590,8 +554,6 @@ __NTH (__option_is_end (const struct argp_option *__opt)) # endif #endif /* Use extern inlines. */ -#ifdef __cplusplus -} -#endif +__END_DECLS #endif /* argp.h */ -- cgit v1.1 From e07eca6a72d21a5a37ba33df7b126609db048c41 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Wed, 17 Aug 2016 16:14:02 +0200 Subject: nptl/tst-once5: Reduce time to expected failure (cherry picked from commit 1f645571d2db9008b3cd3d5acb9ff93357864283) --- ChangeLog | 5 +++++ nptl/tst-once5.cc | 2 ++ 2 files changed, 7 insertions(+) diff --git a/ChangeLog b/ChangeLog index e15b594..a19eb4b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2016-08-17 Florian Weimer + + Reduce time to expected nptl/tst-once5 failure. + * nptl/tst-once5.cc (TIMEOUT): Define. + 2016-08-18 Florian Weimer [BZ #16907] diff --git a/nptl/tst-once5.cc b/nptl/tst-once5.cc index 60bc78a..a6985b0 100644 --- a/nptl/tst-once5.cc +++ b/nptl/tst-once5.cc @@ -76,5 +76,7 @@ do_test (void) return result; } +// The test currently hangs and is XFAILed. Reduce the timeout. +#define TIMEOUT 1 #define TEST_FUNCTION do_test () #include "../test-skeleton.c" -- cgit v1.1