glibc: update to 2.30.

This commit is contained in:
Juan RP 2019-08-13 15:38:37 +02:00
parent 28360ebb2e
commit 25b9921c95
No known key found for this signature in database
GPG key ID: AF19F6CB482F9368
23 changed files with 3 additions and 4119 deletions

View file

@ -1,681 +0,0 @@
From 86013ef5cea322b8f4b9c22f230c22cce369e947 Mon Sep 17 00:00:00 2001
From: Carlos O'Donell <carlos@redhat.com>
Date: Mon, 21 Jan 2019 22:50:12 -0500
Subject: [PATCH 01] nptl: Fix pthread_rwlock_try*lock stalls (Bug 23844)
For a full analysis of both the pthread_rwlock_tryrdlock() stall
and the pthread_rwlock_trywrlock() stall see:
https://sourceware.org/bugzilla/show_bug.cgi?id=23844#c14
In the pthread_rwlock_trydlock() function we fail to inspect for
PTHREAD_RWLOCK_FUTEX_USED in __wrphase_futex and wake the waiting
readers.
In the pthread_rwlock_trywrlock() function we write 1 to
__wrphase_futex and loose the setting of the PTHREAD_RWLOCK_FUTEX_USED
bit, again failing to wake waiting readers during unlock.
The fix in the case of pthread_rwlock_trydlock() is to check for
PTHREAD_RWLOCK_FUTEX_USED and wake the readers.
The fix in the case of pthread_rwlock_trywrlock() is to only write
1 to __wrphase_futex if we installed the write phase, since all other
readers would be spinning waiting for this step.
We add two new tests, one exercises the stall for
pthread_rwlock_trywrlock() which is easy to exercise, and one exercises
the stall for pthread_rwlock_trydlock() which is harder to exercise.
The pthread_rwlock_trywrlock() test fails consistently without the fix,
and passes after. The pthread_rwlock_tryrdlock() test fails roughly
5-10% of the time without the fix, and passes all the time after.
Signed-off-by: Carlos O'Donell <carlos@redhat.com>
Signed-off-by: Torvald Riegel <triegel@redhat.com>
Signed-off-by: Rik Prohaska <prohaska7@gmail.com>
Co-authored-by: Torvald Riegel <triegel@redhat.com>
Co-authored-by: Rik Prohaska <prohaska7@gmail.com>
(cherry picked from commit 5fc9ed4c4058bfbdf51ad6e7aac7d209b580e8c4)
---
ChangeLog | 17 ++
nptl/Makefile | 3 +-
nptl/pthread_rwlock_tryrdlock.c | 25 ++-
nptl/pthread_rwlock_trywrlock.c | 9 +-
nptl/tst-rwlock-tryrdlock-stall.c | 355 ++++++++++++++++++++++++++++++
nptl/tst-rwlock-trywrlock-stall.c | 108 +++++++++
support/Makefile | 1 +
support/xpthread_rwlock_destroy.c | 26 +++
support/xthread.h | 1 +
9 files changed, 534 insertions(+), 11 deletions(-)
create mode 100644 nptl/tst-rwlock-tryrdlock-stall.c
create mode 100644 nptl/tst-rwlock-trywrlock-stall.c
create mode 100644 support/xpthread_rwlock_destroy.c
diff --git a/ChangeLog b/ChangeLog
index 59dab18463..adb4e719a6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,20 @@
+2019-01-31 Carlos O'Donell <carlos@redhat.com>
+ Torvald Riegel <triegel@redhat.com>
+ Rik Prohaska <prohaska7@gmail.com>
+
+ [BZ# 23844]
+ * nptl/Makefile (tests): Add tst-rwlock-tryrdlock-stall, and
+ tst-rwlock-trywrlock-stall.
+ * nptl/pthread_rwlock_tryrdlock.c (__pthread_rwlock_tryrdlock):
+ Wake waiters if PTHREAD_RWLOCK_FUTEX_USED is set.
+ * nptl/pthread_rwlock_trywrlock.c (__pthread_rwlock_trywrlock):
+ Set __wrphase_fute to 1 only if we started the write phase.
+ * nptl/tst-rwlock-tryrdlock-stall.c: New file.
+ * nptl/tst-rwlock-trywrlock-stall.c: New file.
+ * support/Makefile (libsupport-routines): Add xpthread_rwlock_destroy.
+ * support/xpthread_rwlock_destroy.c: New file.
+ * support/xthread.h: Declare xpthread_rwlock_destroy.
+
2019-01-31 Siddhesh Poyarekar <siddhesh@sourceware.org>
* version.h (RELEASE): Set to "stable".
diff --git a/nptl/Makefile b/nptl/Makefile
index 340282c6cb..0e316edfac 100644
--- a/nptl/Makefile
+++ b/nptl/Makefile
@@ -319,7 +319,8 @@ tests = tst-attr1 tst-attr2 tst-attr3 tst-default-attr \
tst-cnd-basic tst-mtx-trylock tst-cnd-broadcast \
tst-cnd-timedwait tst-thrd-detach tst-mtx-basic tst-thrd-sleep \
tst-mtx-recursive tst-tss-basic tst-call-once tst-mtx-timedlock \
- tst-rwlock-pwn
+ tst-rwlock-pwn \
+ tst-rwlock-tryrdlock-stall tst-rwlock-trywrlock-stall
tests-internal := tst-rwlock19 tst-rwlock20 \
tst-sem11 tst-sem12 tst-sem13 \
diff --git a/nptl/pthread_rwlock_tryrdlock.c b/nptl/pthread_rwlock_tryrdlock.c
index 368862ff07..2f94f17f36 100644
--- a/nptl/pthread_rwlock_tryrdlock.c
+++ b/nptl/pthread_rwlock_tryrdlock.c
@@ -94,15 +94,22 @@ __pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock)
/* Same as in __pthread_rwlock_rdlock_full:
We started the read phase, so we are also responsible for
updating the write-phase futex. Relaxed MO is sufficient.
- Note that there can be no other reader that we have to wake
- because all other readers will see the read phase started by us
- (or they will try to start it themselves); if a writer started
- the read phase, we cannot have started it. Furthermore, we
- cannot discard a PTHREAD_RWLOCK_FUTEX_USED flag because we will
- overwrite the value set by the most recent writer (or the readers
- before it in case of explicit hand-over) and we know that there
- are no waiting readers. */
- atomic_store_relaxed (&rwlock->__data.__wrphase_futex, 0);
+ We have to do the same steps as a writer would when handing over the
+ read phase to use because other readers cannot distinguish between
+ us and the writer.
+ Note that __pthread_rwlock_tryrdlock callers will not have to be
+ woken up because they will either see the read phase started by us
+ or they will try to start it themselves; however, callers of
+ __pthread_rwlock_rdlock_full just increase the reader count and then
+ check what state the lock is in, so they cannot distinguish between
+ us and a writer that acquired and released the lock in the
+ meantime. */
+ if ((atomic_exchange_relaxed (&rwlock->__data.__wrphase_futex, 0)
+ & PTHREAD_RWLOCK_FUTEX_USED) != 0)
+ {
+ int private = __pthread_rwlock_get_private (rwlock);
+ futex_wake (&rwlock->__data.__wrphase_futex, INT_MAX, private);
+ }
}
return 0;
diff --git a/nptl/pthread_rwlock_trywrlock.c b/nptl/pthread_rwlock_trywrlock.c
index fd37a71ce4..fae475cc70 100644
--- a/nptl/pthread_rwlock_trywrlock.c
+++ b/nptl/pthread_rwlock_trywrlock.c
@@ -46,8 +46,15 @@ __pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock)
&rwlock->__data.__readers, &r,
r | PTHREAD_RWLOCK_WRPHASE | PTHREAD_RWLOCK_WRLOCKED))
{
+ /* We have become the primary writer and we cannot have shared
+ the PTHREAD_RWLOCK_FUTEX_USED flag with someone else, so we
+ can simply enable blocking (see full wrlock code). */
atomic_store_relaxed (&rwlock->__data.__writers_futex, 1);
- atomic_store_relaxed (&rwlock->__data.__wrphase_futex, 1);
+ /* If we started a write phase, we need to enable readers to
+ wait. If we did not, we must not change it because other threads
+ may have set the PTHREAD_RWLOCK_FUTEX_USED in the meantime. */
+ if ((r & PTHREAD_RWLOCK_WRPHASE) == 0)
+ atomic_store_relaxed (&rwlock->__data.__wrphase_futex, 1);
atomic_store_relaxed (&rwlock->__data.__cur_writer,
THREAD_GETMEM (THREAD_SELF, tid));
return 0;
diff --git a/nptl/tst-rwlock-tryrdlock-stall.c b/nptl/tst-rwlock-tryrdlock-stall.c
new file mode 100644
index 0000000000..5e476da2b8
--- /dev/null
+++ b/nptl/tst-rwlock-tryrdlock-stall.c
@@ -0,0 +1,355 @@
+/* Bug 23844: Test for pthread_rwlock_tryrdlock stalls.
+ Copyright (C) 2019 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* For a full analysis see comment:
+ https://sourceware.org/bugzilla/show_bug.cgi?id=23844#c14
+
+ Provided here for reference:
+
+ --- Analysis of pthread_rwlock_tryrdlock() stall ---
+ A read lock begins to execute.
+
+ In __pthread_rwlock_rdlock_full:
+
+ We can attempt a read lock, but find that the lock is
+ in a write phase (PTHREAD_RWLOCK_WRPHASE, or WP-bit
+ is set), and the lock is held by a primary writer
+ (PTHREAD_RWLOCK_WRLOCKED is set). In this case we must
+ wait for explicit hand over from the writer to us or
+ one of the other waiters. The read lock threads are
+ about to execute:
+
+ 341 r = (atomic_fetch_add_acquire (&rwlock->__data.__readers,
+ 342 (1 << PTHREAD_RWLOCK_READER_SHIFT))
+ 343 + (1 << PTHREAD_RWLOCK_READER_SHIFT));
+
+ An unlock beings to execute.
+
+ Then in __pthread_rwlock_wrunlock:
+
+ 547 unsigned int r = atomic_load_relaxed (&rwlock->__data.__readers);
+ ...
+ 549 while (!atomic_compare_exchange_weak_release
+ 550 (&rwlock->__data.__readers, &r,
+ 551 ((r ^ PTHREAD_RWLOCK_WRLOCKED)
+ 552 ^ ((r >> PTHREAD_RWLOCK_READER_SHIFT) == 0 ? 0
+ 553 : PTHREAD_RWLOCK_WRPHASE))))
+ 554 {
+ ...
+ 556 }
+
+ We clear PTHREAD_RWLOCK_WRLOCKED, and if there are
+ no readers so we leave the lock in PTHRAD_RWLOCK_WRPHASE.
+
+ Back in the read lock.
+
+ The read lock adjusts __readres as above.
+
+ 383 while ((r & PTHREAD_RWLOCK_WRPHASE) != 0
+ 384 && (r & PTHREAD_RWLOCK_WRLOCKED) == 0)
+ 385 {
+ ...
+ 390 if (atomic_compare_exchange_weak_acquire (&rwlock->__data.__readers, &r,
+ 391 r ^ PTHREAD_RWLOCK_WRPHASE))
+ 392 {
+
+ And then attemps to start the read phase.
+
+ Assume there happens to be a tryrdlock at this point, noting
+ that PTHREAD_RWLOCK_WRLOCKED is clear, and PTHREAD_RWLOCK_WRPHASE
+ is 1. So the try lock attemps to start the read phase.
+
+ In __pthread_rwlock_tryrdlock:
+
+ 44 if ((r & PTHREAD_RWLOCK_WRPHASE) == 0)
+ 45 {
+ ...
+ 49 if (((r & PTHREAD_RWLOCK_WRLOCKED) != 0)
+ 50 && (rwlock->__data.__flags
+ 51 == PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP))
+ 52 return EBUSY;
+ 53 rnew = r + (1 << PTHREAD_RWLOCK_READER_SHIFT);
+ 54 }
+ ...
+ 89 while (!atomic_compare_exchange_weak_acquire (&rwlock->__data.__readers,
+ 90 &r, rnew));
+
+ And succeeds.
+
+ Back in the write unlock:
+
+ 557 if ((r >> PTHREAD_RWLOCK_READER_SHIFT) != 0)
+ 558 {
+ ...
+ 563 if ((atomic_exchange_relaxed (&rwlock->__data.__wrphase_futex, 0)
+ 564 & PTHREAD_RWLOCK_FUTEX_USED) != 0)
+ 565 futex_wake (&rwlock->__data.__wrphase_futex, INT_MAX, private);
+ 566 }
+
+ We note that PTHREAD_RWLOCK_FUTEX_USED is non-zero
+ and don't wake anyone. This is OK because we handed
+ over to the trylock. It will be the trylock's responsibility
+ to wake any waiters.
+
+ Back in the read lock:
+
+ The read lock fails to install PTHRAD_REWLOCK_WRPHASE as 0 because
+ the __readers value was adjusted by the trylock, and so it falls through
+ to waiting on the lock for explicit handover from either a new writer
+ or a new reader.
+
+ 448 int err = futex_abstimed_wait (&rwlock->__data.__wrphase_futex,
+ 449 1 | PTHREAD_RWLOCK_FUTEX_USED,
+ 450 abstime, private);
+
+ We use PTHREAD_RWLOCK_FUTEX_USED to indicate the futex
+ is in use.
+
+ At this point we have readers waiting on the read lock
+ to unlock. The wrlock is done. The trylock is finishing
+ the installation of the read phase.
+
+ 92 if ((r & PTHREAD_RWLOCK_WRPHASE) != 0)
+ 93 {
+ ...
+ 105 atomic_store_relaxed (&rwlock->__data.__wrphase_futex, 0);
+ 106 }
+
+ The trylock does note that we were the one that
+ installed the read phase, but the comments are not
+ correct, the execution ordering above shows that
+ readers might indeed be waiting, and they are.
+
+ The atomic_store_relaxed throws away PTHREAD_RWLOCK_FUTEX_USED,
+ and the waiting reader is never worken becuase as noted
+ above it is conditional on the futex being used.
+
+ The solution is for the trylock thread to inspect
+ PTHREAD_RWLOCK_FUTEX_USED and wake the waiting readers.
+
+ --- Analysis of pthread_rwlock_trywrlock() stall ---
+
+ A write lock begins to execute, takes the write lock,
+ and then releases the lock...
+
+ In pthread_rwlock_wrunlock():
+
+ 547 unsigned int r = atomic_load_relaxed (&rwlock->__data.__readers);
+ ...
+ 549 while (!atomic_compare_exchange_weak_release
+ 550 (&rwlock->__data.__readers, &r,
+ 551 ((r ^ PTHREAD_RWLOCK_WRLOCKED)
+ 552 ^ ((r >> PTHREAD_RWLOCK_READER_SHIFT) == 0 ? 0
+ 553 : PTHREAD_RWLOCK_WRPHASE))))
+ 554 {
+ ...
+ 556 }
+
+ ... leaving it in the write phase with zero readers
+ (the case where we leave the write phase in place
+ during a write unlock).
+
+ A write trylock begins to execute.
+
+ In __pthread_rwlock_trywrlock:
+
+ 40 while (((r & PTHREAD_RWLOCK_WRLOCKED) == 0)
+ 41 && (((r >> PTHREAD_RWLOCK_READER_SHIFT) == 0)
+ 42 || (prefer_writer && ((r & PTHREAD_RWLOCK_WRPHASE) != 0))))
+ 43 {
+
+ The lock is not locked.
+
+ There are no readers.
+
+ 45 if (atomic_compare_exchange_weak_acquire (
+ 46 &rwlock->__data.__readers, &r,
+ 47 r | PTHREAD_RWLOCK_WRPHASE | PTHREAD_RWLOCK_WRLOCKED))
+
+ We atomically install the write phase and we take the
+ exclusive write lock.
+
+ 48 {
+ 49 atomic_store_relaxed (&rwlock->__data.__writers_futex, 1);
+
+ We get this far.
+
+ A reader lock begins to execute.
+
+ In pthread_rwlock_rdlock:
+
+ 437 for (;;)
+ 438 {
+ 439 while (((wpf = atomic_load_relaxed (&rwlock->__data.__wrphase_futex))
+ 440 | PTHREAD_RWLOCK_FUTEX_USED) == (1 | PTHREAD_RWLOCK_FUTEX_USED))
+ 441 {
+ 442 int private = __pthread_rwlock_get_private (rwlock);
+ 443 if (((wpf & PTHREAD_RWLOCK_FUTEX_USED) == 0)
+ 444 && (!atomic_compare_exchange_weak_relaxed
+ 445 (&rwlock->__data.__wrphase_futex,
+ 446 &wpf, wpf | PTHREAD_RWLOCK_FUTEX_USED)))
+ 447 continue;
+ 448 int err = futex_abstimed_wait (&rwlock->__data.__wrphase_futex,
+ 449 1 | PTHREAD_RWLOCK_FUTEX_USED,
+ 450 abstime, private);
+
+ We are in a write phase, so the while() on line 439 is true.
+
+ The value of wpf does not have PTHREAD_RWLOCK_FUTEX_USED set
+ since this is the first reader to lock.
+
+ The atomic operation sets wpf with PTHREAD_RELOCK_FUTEX_USED
+ on the expectation that this reader will be woken during
+ the handoff.
+
+ Back in pthread_rwlock_trywrlock:
+
+ 50 atomic_store_relaxed (&rwlock->__data.__wrphase_futex, 1);
+ 51 atomic_store_relaxed (&rwlock->__data.__cur_writer,
+ 52 THREAD_GETMEM (THREAD_SELF, tid));
+ 53 return 0;
+ 54 }
+ ...
+ 57 }
+
+ We write 1 to __wrphase_futex discarding PTHREAD_RWLOCK_FUTEX_USED,
+ and so in the unlock we will not awaken the waiting reader.
+
+ The solution to this is to realize that if we did not start the write
+ phase we need not write 1 or any other value to __wrphase_futex.
+ This ensures that any readers (which saw __wrphase_futex != 0) can
+ set PTHREAD_RWLOCK_FUTEX_USED and this can be used at unlock to
+ wake them.
+
+ If we installed the write phase then all other readers are looping
+ here:
+
+ In __pthread_rwlock_rdlock_full:
+
+ 437 for (;;)
+ 438 {
+ 439 while (((wpf = atomic_load_relaxed (&rwlock->__data.__wrphase_futex))
+ 440 | PTHREAD_RWLOCK_FUTEX_USED) == (1 | PTHREAD_RWLOCK_FUTEX_USED))
+ 441 {
+ ...
+ 508 }
+
+ waiting for the write phase to be installed or removed before they
+ can begin waiting on __wrphase_futex (part of the algorithm), or
+ taking a concurrent read lock, and thus we can safely write 1 to
+ __wrphase_futex.
+
+ If we did not install the write phase then the readers may already
+ be waiting on the futex, the original writer wrote 1 to __wrphase_futex
+ as part of starting the write phase, and we cannot also write 1
+ without loosing the PTHREAD_RWLOCK_FUTEX_USED bit.
+
+ ---
+
+ Summary for the pthread_rwlock_tryrdlock() stall:
+
+ The stall is caused by pthread_rwlock_tryrdlock failing to check
+ that PTHREAD_RWLOCK_FUTEX_USED is set in the __wrphase_futex futex
+ and then waking the futex.
+
+ The fix for bug 23844 ensures that waiters on __wrphase_futex are
+ correctly woken. Before the fix the test stalls as readers can
+ wait forever on __wrphase_futex. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <support/xthread.h>
+#include <errno.h>
+
+/* We need only one lock to reproduce the issue. We will need multiple
+ threads to get the exact case where we have a read, try, and unlock
+ all interleaving to produce the case where the readers are waiting
+ and the try fails to wake them. */
+pthread_rwlock_t onelock;
+
+/* The number of threads is arbitrary but empirically chosen to have
+ enough threads that we see the condition where waiting readers are
+ not woken by a successful tryrdlock. */
+#define NTHREADS 32
+
+_Atomic int do_exit;
+
+void *
+run_loop (void *arg)
+{
+ int i = 0, ret;
+ while (!do_exit)
+ {
+ /* Arbitrarily choose if we are the writer or reader. Choose a
+ high enough ratio of readers to writers to make it likely
+ that readers block (and eventually are susceptable to
+ stalling).
+
+ If we are a writer, take the write lock, and then unlock.
+ If we are a reader, try the lock, then lock, then unlock. */
+ if ((i % 8) != 0)
+ xpthread_rwlock_wrlock (&onelock);
+ else
+ {
+ if ((ret = pthread_rwlock_tryrdlock (&onelock)) != 0)
+ {
+ if (ret == EBUSY)
+ xpthread_rwlock_rdlock (&onelock);
+ else
+ exit (EXIT_FAILURE);
+ }
+ }
+ /* Thread does some work and then unlocks. */
+ xpthread_rwlock_unlock (&onelock);
+ i++;
+ }
+ return NULL;
+}
+
+int
+do_test (void)
+{
+ int i;
+ pthread_t tids[NTHREADS];
+ xpthread_rwlock_init (&onelock, NULL);
+ for (i = 0; i < NTHREADS; i++)
+ tids[i] = xpthread_create (NULL, run_loop, NULL);
+ /* Run for some amount of time. Empirically speaking exercising
+ the stall via pthread_rwlock_tryrdlock is much harder, and on
+ a 3.5GHz 4 core x86_64 VM system it takes somewhere around
+ 20-200s to stall, approaching 100% stall past 200s. We can't
+ wait that long for a regression test so we just test for 20s,
+ and expect the stall to happen with a 5-10% chance (enough for
+ developers to see). */
+ sleep (20);
+ /* Then exit. */
+ printf ("INFO: Exiting...\n");
+ do_exit = 1;
+ /* If any readers stalled then we will timeout waiting for them. */
+ for (i = 0; i < NTHREADS; i++)
+ xpthread_join (tids[i]);
+ printf ("INFO: Done.\n");
+ xpthread_rwlock_destroy (&onelock);
+ printf ("PASS: No pthread_rwlock_tryrdlock stalls detected.\n");
+ return 0;
+}
+
+#define TIMEOUT 30
+#include <support/test-driver.c>
diff --git a/nptl/tst-rwlock-trywrlock-stall.c b/nptl/tst-rwlock-trywrlock-stall.c
new file mode 100644
index 0000000000..14d27cbcbc
--- /dev/null
+++ b/nptl/tst-rwlock-trywrlock-stall.c
@@ -0,0 +1,108 @@
+/* Bug 23844: Test for pthread_rwlock_trywrlock stalls.
+ Copyright (C) 2019 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* For a full analysis see comments in tst-rwlock-tryrdlock-stall.c.
+
+ Summary for the pthread_rwlock_trywrlock() stall:
+
+ The stall is caused by pthread_rwlock_trywrlock setting
+ __wrphase_futex futex to 1 and loosing the
+ PTHREAD_RWLOCK_FUTEX_USED bit.
+
+ The fix for bug 23844 ensures that waiters on __wrphase_futex are
+ correctly woken. Before the fix the test stalls as readers can
+ wait forever on __wrphase_futex. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <support/xthread.h>
+#include <errno.h>
+
+/* We need only one lock to reproduce the issue. We will need multiple
+ threads to get the exact case where we have a read, try, and unlock
+ all interleaving to produce the case where the readers are waiting
+ and the try clears the PTHREAD_RWLOCK_FUTEX_USED bit and a
+ subsequent unlock fails to wake them. */
+pthread_rwlock_t onelock;
+
+/* The number of threads is arbitrary but empirically chosen to have
+ enough threads that we see the condition where waiting readers are
+ not woken by a successful unlock. */
+#define NTHREADS 32
+
+_Atomic int do_exit;
+
+void *
+run_loop (void *arg)
+{
+ int i = 0, ret;
+ while (!do_exit)
+ {
+ /* Arbitrarily choose if we are the writer or reader. Choose a
+ high enough ratio of readers to writers to make it likely
+ that readers block (and eventually are susceptable to
+ stalling).
+
+ If we are a writer, take the write lock, and then unlock.
+ If we are a reader, try the lock, then lock, then unlock. */
+ if ((i % 8) != 0)
+ {
+ if ((ret = pthread_rwlock_trywrlock (&onelock)) != 0)
+ {
+ if (ret == EBUSY)
+ xpthread_rwlock_wrlock (&onelock);
+ else
+ exit (EXIT_FAILURE);
+ }
+ }
+ else
+ xpthread_rwlock_rdlock (&onelock);
+ /* Thread does some work and then unlocks. */
+ xpthread_rwlock_unlock (&onelock);
+ i++;
+ }
+ return NULL;
+}
+
+int
+do_test (void)
+{
+ int i;
+ pthread_t tids[NTHREADS];
+ xpthread_rwlock_init (&onelock, NULL);
+ for (i = 0; i < NTHREADS; i++)
+ tids[i] = xpthread_create (NULL, run_loop, NULL);
+ /* Run for some amount of time. The pthread_rwlock_tryrwlock stall
+ is very easy to trigger and happens in seconds under the test
+ conditions. */
+ sleep (10);
+ /* Then exit. */
+ printf ("INFO: Exiting...\n");
+ do_exit = 1;
+ /* If any readers stalled then we will timeout waiting for them. */
+ for (i = 0; i < NTHREADS; i++)
+ xpthread_join (tids[i]);
+ printf ("INFO: Done.\n");
+ xpthread_rwlock_destroy (&onelock);
+ printf ("PASS: No pthread_rwlock_tryrwlock stalls detected.\n");
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/support/Makefile b/support/Makefile
index 432cf2fe6c..c15b93647c 100644
--- a/support/Makefile
+++ b/support/Makefile
@@ -129,6 +129,7 @@ libsupport-routines = \
xpthread_mutexattr_settype \
xpthread_once \
xpthread_rwlock_init \
+ xpthread_rwlock_destroy \
xpthread_rwlock_rdlock \
xpthread_rwlock_unlock \
xpthread_rwlock_wrlock \
diff --git a/support/xpthread_rwlock_destroy.c b/support/xpthread_rwlock_destroy.c
new file mode 100644
index 0000000000..6d6e953569
--- /dev/null
+++ b/support/xpthread_rwlock_destroy.c
@@ -0,0 +1,26 @@
+/* pthread_rwlock_destroy with error checking.
+ Copyright (C) 2019 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <support/xthread.h>
+
+void
+xpthread_rwlock_destroy (pthread_rwlock_t *rwlock)
+{
+ xpthread_check_return ("pthread_rwlock_destroy",
+ pthread_rwlock_destroy (rwlock));
+}
diff --git a/support/xthread.h b/support/xthread.h
index 47c23235f3..9fe1f68b3b 100644
--- a/support/xthread.h
+++ b/support/xthread.h
@@ -84,6 +84,7 @@ void xpthread_rwlockattr_setkind_np (pthread_rwlockattr_t *attr, int pref);
void xpthread_rwlock_wrlock (pthread_rwlock_t *rwlock);
void xpthread_rwlock_rdlock (pthread_rwlock_t *rwlock);
void xpthread_rwlock_unlock (pthread_rwlock_t *rwlock);
+void xpthread_rwlock_destroy (pthread_rwlock_t *rwlock);
__END_DECLS

View file

@ -1,248 +0,0 @@
From 726a78867b3144e9b9da10197bcf59bde3d8b2a4 Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Mon, 4 Feb 2019 08:55:52 -0800
Subject: [PATCH 02] x86-64 memcmp: Use unsigned Jcc instructions on size
[BZ #24155]
Since the size argument is unsigned. we should use unsigned Jcc
instructions, instead of signed, to check size.
Tested on x86-64 and x32, with and without --disable-multi-arch.
[BZ #24155]
CVE-2019-7309
* NEWS: Updated for CVE-2019-7309.
* sysdeps/x86_64/memcmp.S: Use RDX_LP for size. Clear the
upper 32 bits of RDX register for x32. Use unsigned Jcc
instructions, instead of signed.
* sysdeps/x86_64/x32/Makefile (tests): Add tst-size_t-memcmp-2.
* sysdeps/x86_64/x32/tst-size_t-memcmp-2.c: New test.
(cherry picked from commit 3f635fb43389b54f682fc9ed2acc0b2aaf4a923d)
---
ChangeLog | 11 ++++
NEWS | 17 +++++
sysdeps/x86_64/memcmp.S | 20 +++---
sysdeps/x86_64/x32/Makefile | 3 +-
sysdeps/x86_64/x32/tst-size_t-memcmp-2.c | 79 ++++++++++++++++++++++++
5 files changed, 121 insertions(+), 9 deletions(-)
create mode 100644 sysdeps/x86_64/x32/tst-size_t-memcmp-2.c
diff --git a/ChangeLog b/ChangeLog
index adb4e719a6..e0969afd80 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2019-02-04 H.J. Lu <hongjiu.lu@intel.com>
+
+ [BZ #24155]
+ CVE-2019-7309
+ * NEWS: Updated for CVE-2019-7309.
+ * sysdeps/x86_64/memcmp.S: Use RDX_LP for size. Clear the
+ upper 32 bits of RDX register for x32. Use unsigned Jcc
+ instructions, instead of signed.
+ * sysdeps/x86_64/x32/Makefile (tests): Add tst-size_t-memcmp-2.
+ * sysdeps/x86_64/x32/tst-size_t-memcmp-2.c: New test.
+
2019-01-31 Carlos O'Donell <carlos@redhat.com>
Torvald Riegel <triegel@redhat.com>
Rik Prohaska <prohaska7@gmail.com>
diff --git a/NEWS b/NEWS
index 912a9bdc0f..1751ed118a 100644
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,23 @@ See the end for copying conditions.
Please send GNU C library bug reports via <https://sourceware.org/bugzilla/>
using `glibc' in the "product" field.
+Version 2.29.1
+
+The following bugs are resolved with this release:
+
+ [24155] x32 memcmp can treat positive length as 0 (if sign bit in RDX is set) (CVE-2019-7309)
+
+Security related changes:
+
+ CVE-2019-7309: x86-64 memcmp used signed Jcc instructions to check
+ size. For x86-64, memcmp on an object size larger than SSIZE_MAX
+ has undefined behavior. On x32, the size_t argument may be passed
+ in the lower 32 bits of the 64-bit RDX register with non-zero upper
+ 32 bits. When it happened with the sign bit of RDX register set,
+ memcmp gave the wrong result since it treated the size argument as
+ zero. Reported by H.J. Lu.
+
+
Version 2.29
Major new features:
diff --git a/sysdeps/x86_64/memcmp.S b/sysdeps/x86_64/memcmp.S
index 1fc487caa5..1322bb3b92 100644
--- a/sysdeps/x86_64/memcmp.S
+++ b/sysdeps/x86_64/memcmp.S
@@ -21,14 +21,18 @@
.text
ENTRY (memcmp)
- test %rdx, %rdx
+#ifdef __ILP32__
+ /* Clear the upper 32 bits. */
+ movl %edx, %edx
+#endif
+ test %RDX_LP, %RDX_LP
jz L(finz)
cmpq $1, %rdx
- jle L(finr1b)
+ jbe L(finr1b)
subq %rdi, %rsi
movq %rdx, %r10
cmpq $32, %r10
- jge L(gt32)
+ jae L(gt32)
/* Handle small chunks and last block of less than 32 bytes. */
L(small):
testq $1, %r10
@@ -156,7 +160,7 @@ L(A32):
movq %r11, %r10
andq $-32, %r10
cmpq %r10, %rdi
- jge L(mt16)
+ jae L(mt16)
/* Pre-unroll to be ready for unrolled 64B loop. */
testq $32, %rdi
jz L(A64)
@@ -178,7 +182,7 @@ L(A64):
movq %r11, %r10
andq $-64, %r10
cmpq %r10, %rdi
- jge L(mt32)
+ jae L(mt32)
L(A64main):
movdqu (%rdi,%rsi), %xmm0
@@ -216,7 +220,7 @@ L(mt32):
movq %r11, %r10
andq $-32, %r10
cmpq %r10, %rdi
- jge L(mt16)
+ jae L(mt16)
L(A32main):
movdqu (%rdi,%rsi), %xmm0
@@ -254,7 +258,7 @@ L(ATR):
movq %r11, %r10
andq $-32, %r10
cmpq %r10, %rdi
- jge L(mt16)
+ jae L(mt16)
testq $16, %rdi
jz L(ATR32)
@@ -325,7 +329,7 @@ L(ATR64main):
movq %r11, %r10
andq $-32, %r10
cmpq %r10, %rdi
- jge L(mt16)
+ jae L(mt16)
L(ATR32res):
movdqa (%rdi,%rsi), %xmm0
diff --git a/sysdeps/x86_64/x32/Makefile b/sysdeps/x86_64/x32/Makefile
index 1557724b0c..8748956563 100644
--- a/sysdeps/x86_64/x32/Makefile
+++ b/sysdeps/x86_64/x32/Makefile
@@ -8,7 +8,8 @@ endif
ifeq ($(subdir),string)
tests += tst-size_t-memchr tst-size_t-memcmp tst-size_t-memcpy \
tst-size_t-memrchr tst-size_t-memset tst-size_t-strncasecmp \
- tst-size_t-strncmp tst-size_t-strncpy tst-size_t-strnlen
+ tst-size_t-strncmp tst-size_t-strncpy tst-size_t-strnlen \
+ tst-size_t-memcmp-2
endif
ifeq ($(subdir),wcsmbs)
diff --git a/sysdeps/x86_64/x32/tst-size_t-memcmp-2.c b/sysdeps/x86_64/x32/tst-size_t-memcmp-2.c
new file mode 100644
index 0000000000..d8ae1a0813
--- /dev/null
+++ b/sysdeps/x86_64/x32/tst-size_t-memcmp-2.c
@@ -0,0 +1,79 @@
+/* Test memcmp with size_t in the lower 32 bits of 64-bit register.
+ Copyright (C) 2019 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#define TEST_MAIN
+#ifdef WIDE
+# define TEST_NAME "wmemcmp"
+#else
+# define TEST_NAME "memcmp"
+#endif
+
+#include "test-size_t.h"
+
+#ifdef WIDE
+# include <inttypes.h>
+# include <wchar.h>
+
+# define MEMCMP wmemcmp
+# define CHAR wchar_t
+#else
+# define MEMCMP memcmp
+# define CHAR char
+#endif
+
+IMPL (MEMCMP, 1)
+
+typedef int (*proto_t) (const CHAR *, const CHAR *, size_t);
+
+static int
+__attribute__ ((noinline, noclone))
+do_memcmp (parameter_t a, parameter_t b)
+{
+ return CALL (&b, a.p, b.p, a.len);
+}
+
+static int
+test_main (void)
+{
+ test_init ();
+
+ parameter_t dest = { { page_size / sizeof (CHAR) }, buf1 };
+ parameter_t src = { { 0 }, buf2 };
+
+ memcpy (buf1, buf2, page_size);
+
+ CHAR *p = (CHAR *) buf1;
+ p[page_size / sizeof (CHAR) - 1] = (CHAR) 1;
+
+ int ret = 0;
+ FOR_EACH_IMPL (impl, 0)
+ {
+ src.fn = impl->fn;
+ int res = do_memcmp (dest, src);
+ if (res >= 0)
+ {
+ error (0, 0, "Wrong result in function %s: %i >= 0",
+ impl->name, res);
+ ret = 1;
+ }
+ }
+
+ return ret ? EXIT_FAILURE : EXIT_SUCCESS;
+}
+
+#include <support/test-driver.c>

View file

@ -1,119 +0,0 @@
From 2de15ac95713a238dc258eb8977ecdfca811fc19 Mon Sep 17 00:00:00 2001
From: Florian Weimer <fweimer@redhat.com>
Date: Tue, 5 Feb 2019 13:49:02 +0100
Subject: [PATCH 03] arm: Use "nr" constraint for Systemtap probes [BZ
#24164]
With the default "nor" constraint, current GCC will use the "o"
constraint for constants, after emitting the constant to memory. That
results in unparseable Systemtap probe notes such as "-4@.L1052".
Removing the "o" alternative and using "nr" instead avoids this.
(cherry picked from commit f1ac7455831546e5dca0ed98fe8af2686fae7ce6)
---
ChangeLog | 11 +++++++++++
NEWS | 1 +
include/stap-probe.h | 1 +
sysdeps/arm/stap-probe-machine.h | 22 ++++++++++++++++++++++
sysdeps/generic/stap-probe-machine.h | 19 +++++++++++++++++++
5 files changed, 54 insertions(+)
create mode 100644 sysdeps/arm/stap-probe-machine.h
create mode 100644 sysdeps/generic/stap-probe-machine.h
diff --git a/ChangeLog b/ChangeLog
index e0969afd80..9517ff9e82 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2019-02-05 Florian Weimer <fweimer@redhat.com>
+
+ [BZ #24164]
+ arm: Use "nr" constraint for Systemtap probes, to avoid the
+ compiler using memory operands for constants, due to the "o"
+ alternative in the default "nor" constraint.
+ * include/stap-probe.h [USE_STAP_PROBE]: Include
+ <stap-probe-machine.h>
+ * sysdeps/generic/stap-probe-machine.h: New file.
+ * sysdeps/arm/stap-probe-machine.h: Likewise.
+
2019-02-04 H.J. Lu <hongjiu.lu@intel.com>
[BZ #24155]
diff --git a/NEWS b/NEWS
index 1751ed118a..1f0fc4b3cb 100644
--- a/NEWS
+++ b/NEWS
@@ -10,6 +10,7 @@ Version 2.29.1
The following bugs are resolved with this release:
[24155] x32 memcmp can treat positive length as 0 (if sign bit in RDX is set) (CVE-2019-7309)
+ [24164] Systemtap probes need to use "nr" constraint on 32-bit Arm
Security related changes:
diff --git a/include/stap-probe.h b/include/stap-probe.h
index c53dd86592..8c26292edd 100644
--- a/include/stap-probe.h
+++ b/include/stap-probe.h
@@ -21,6 +21,7 @@
#ifdef USE_STAP_PROBE
+# include <stap-probe-machine.h>
# include <sys/sdt.h>
/* Our code uses one macro LIBC_PROBE (name, n, arg1, ..., argn).
diff --git a/sysdeps/arm/stap-probe-machine.h b/sysdeps/arm/stap-probe-machine.h
new file mode 100644
index 0000000000..d27ca22040
--- /dev/null
+++ b/sysdeps/arm/stap-probe-machine.h
@@ -0,0 +1,22 @@
+/* Macros for customizing Systemtap <sys/sdt.h>. Arm version.
+ Copyright (C) 2019 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* The default "nor" constraint produces unparseable memory references
+ for constants. Omit the problematic "o" constraint. See bug 24164
+ and GCC PR 89146. */
+#define STAP_SDT_ARG_CONSTRAINT nr
diff --git a/sysdeps/generic/stap-probe-machine.h b/sysdeps/generic/stap-probe-machine.h
new file mode 100644
index 0000000000..2e5790c3b2
--- /dev/null
+++ b/sysdeps/generic/stap-probe-machine.h
@@ -0,0 +1,19 @@
+/* Macros for customizing Systemtap <sys/sdt.h>. Generic version.
+ Copyright (C) 2019 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* By default, there are no customizations. */

View file

@ -1,221 +0,0 @@
From 44113a8ba24af23d7bbb174f9087a6b83a76289a Mon Sep 17 00:00:00 2001
From: Stefan Liebler <stli@linux.ibm.com>
Date: Thu, 7 Feb 2019 15:18:36 +0100
Subject: [PATCH 04] Add compiler barriers around modifications of the
robust mutex list for pthread_mutex_trylock. [BZ #24180]
While debugging a kernel warning, Thomas Gleixner, Sebastian Sewior and
Heiko Carstens found a bug in pthread_mutex_trylock due to misordered
instructions:
140: a5 1b 00 01 oill %r1,1
144: e5 48 a0 f0 00 00 mvghi 240(%r10),0 <--- THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
14a: e3 10 a0 e0 00 24 stg %r1,224(%r10) <--- last THREAD_SETMEM of ENQUEUE_MUTEX_PI
vs (with compiler barriers):
140: a5 1b 00 01 oill %r1,1
144: e3 10 a0 e0 00 24 stg %r1,224(%r10)
14a: e5 48 a0 f0 00 00 mvghi 240(%r10),0
Please have a look at the discussion:
"Re: WARN_ON_ONCE(!new_owner) within wake_futex_pi() triggerede"
(https://lore.kernel.org/lkml/20190202112006.GB3381@osiris/)
This patch is introducing the same compiler barriers and comments
for pthread_mutex_trylock as introduced for pthread_mutex_lock and
pthread_mutex_timedlock by commit 8f9450a0b7a9e78267e8ae1ab1000ebca08e473e
"Add compiler barriers around modifications of the robust mutex list."
ChangeLog:
[BZ #24180]
* nptl/pthread_mutex_trylock.c (__pthread_mutex_trylock):
Add compiler barriers and comments.
(cherry picked from commit 823624bdc47f1f80109c9c52dee7939b9386d708)
---
ChangeLog | 6 ++++
nptl/pthread_mutex_trylock.c | 57 +++++++++++++++++++++++++++++++++---
2 files changed, 59 insertions(+), 4 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 9517ff9e82..7a8895bcc6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2019-02-07 Stefan Liebler <stli@linux.ibm.com>
+
+ [BZ #24180]
+ * nptl/pthread_mutex_trylock.c (__pthread_mutex_trylock):
+ Add compiler barriers and comments.
+
2019-02-05 Florian Weimer <fweimer@redhat.com>
[BZ #24164]
diff --git a/nptl/pthread_mutex_trylock.c b/nptl/pthread_mutex_trylock.c
index 8fe43b8f0f..bf2869eca2 100644
--- a/nptl/pthread_mutex_trylock.c
+++ b/nptl/pthread_mutex_trylock.c
@@ -94,6 +94,9 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex)
case PTHREAD_MUTEX_ROBUST_ADAPTIVE_NP:
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
&mutex->__data.__list.__next);
+ /* We need to set op_pending before starting the operation. Also
+ see comments at ENQUEUE_MUTEX. */
+ __asm ("" ::: "memory");
oldval = mutex->__data.__lock;
do
@@ -119,7 +122,12 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex)
/* But it is inconsistent unless marked otherwise. */
mutex->__data.__owner = PTHREAD_MUTEX_INCONSISTENT;
+ /* We must not enqueue the mutex before we have acquired it.
+ Also see comments at ENQUEUE_MUTEX. */
+ __asm ("" ::: "memory");
ENQUEUE_MUTEX (mutex);
+ /* We need to clear op_pending after we enqueue the mutex. */
+ __asm ("" ::: "memory");
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
/* Note that we deliberately exist here. If we fall
@@ -135,6 +143,8 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex)
int kind = PTHREAD_MUTEX_TYPE (mutex);
if (kind == PTHREAD_MUTEX_ROBUST_ERRORCHECK_NP)
{
+ /* We do not need to ensure ordering wrt another memory
+ access. Also see comments at ENQUEUE_MUTEX. */
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
NULL);
return EDEADLK;
@@ -142,6 +152,8 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex)
if (kind == PTHREAD_MUTEX_ROBUST_RECURSIVE_NP)
{
+ /* We do not need to ensure ordering wrt another memory
+ access. */
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
NULL);
@@ -160,6 +172,9 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex)
id, 0);
if (oldval != 0 && (oldval & FUTEX_OWNER_DIED) == 0)
{
+ /* We haven't acquired the lock as it is already acquired by
+ another owner. We do not need to ensure ordering wrt another
+ memory access. */
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
return EBUSY;
@@ -173,13 +188,20 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex)
if (oldval == id)
lll_unlock (mutex->__data.__lock,
PTHREAD_ROBUST_MUTEX_PSHARED (mutex));
+ /* FIXME This violates the mutex destruction requirements. See
+ __pthread_mutex_unlock_full. */
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
return ENOTRECOVERABLE;
}
}
while ((oldval & FUTEX_OWNER_DIED) != 0);
+ /* We must not enqueue the mutex before we have acquired it.
+ Also see comments at ENQUEUE_MUTEX. */
+ __asm ("" ::: "memory");
ENQUEUE_MUTEX (mutex);
+ /* We need to clear op_pending after we enqueue the mutex. */
+ __asm ("" ::: "memory");
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
mutex->__data.__owner = id;
@@ -211,10 +233,15 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex)
}
if (robust)
- /* Note: robust PI futexes are signaled by setting bit 0. */
- THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
- (void *) (((uintptr_t) &mutex->__data.__list.__next)
- | 1));
+ {
+ /* Note: robust PI futexes are signaled by setting bit 0. */
+ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
+ (void *) (((uintptr_t) &mutex->__data.__list.__next)
+ | 1));
+ /* We need to set op_pending before starting the operation. Also
+ see comments at ENQUEUE_MUTEX. */
+ __asm ("" ::: "memory");
+ }
oldval = mutex->__data.__lock;
@@ -223,12 +250,16 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex)
{
if (kind == PTHREAD_MUTEX_ERRORCHECK_NP)
{
+ /* We do not need to ensure ordering wrt another memory
+ access. */
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
return EDEADLK;
}
if (kind == PTHREAD_MUTEX_RECURSIVE_NP)
{
+ /* We do not need to ensure ordering wrt another memory
+ access. */
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
/* Just bump the counter. */
@@ -250,6 +281,9 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex)
{
if ((oldval & FUTEX_OWNER_DIED) == 0)
{
+ /* We haven't acquired the lock as it is already acquired by
+ another owner. We do not need to ensure ordering wrt another
+ memory access. */
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
return EBUSY;
@@ -270,6 +304,9 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex)
if (INTERNAL_SYSCALL_ERROR_P (e, __err)
&& INTERNAL_SYSCALL_ERRNO (e, __err) == EWOULDBLOCK)
{
+ /* The kernel has not yet finished the mutex owner death.
+ We do not need to ensure ordering wrt another memory
+ access. */
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
return EBUSY;
@@ -287,7 +324,12 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex)
/* But it is inconsistent unless marked otherwise. */
mutex->__data.__owner = PTHREAD_MUTEX_INCONSISTENT;
+ /* We must not enqueue the mutex before we have acquired it.
+ Also see comments at ENQUEUE_MUTEX. */
+ __asm ("" ::: "memory");
ENQUEUE_MUTEX (mutex);
+ /* We need to clear op_pending after we enqueue the mutex. */
+ __asm ("" ::: "memory");
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
/* Note that we deliberately exit here. If we fall
@@ -310,13 +352,20 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex)
PTHREAD_ROBUST_MUTEX_PSHARED (mutex)),
0, 0);
+ /* To the kernel, this will be visible after the kernel has
+ acquired the mutex in the syscall. */
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
return ENOTRECOVERABLE;
}
if (robust)
{
+ /* We must not enqueue the mutex before we have acquired it.
+ Also see comments at ENQUEUE_MUTEX. */
+ __asm ("" ::: "memory");
ENQUEUE_MUTEX_PI (mutex);
+ /* We need to clear op_pending after we enqueue the mutex. */
+ __asm ("" ::: "memory");
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
}

View file

@ -1,157 +0,0 @@
From c096b008d2671028c21ac8cf01f18a2083e73c44 Mon Sep 17 00:00:00 2001
From: Florian Weimer <fweimer@redhat.com>
Date: Fri, 8 Feb 2019 12:54:41 +0100
Subject: [PATCH 05] nptl: Avoid fork handler lock for async-signal-safe
fork [BZ #24161]
Commit 27761a1042daf01987e7d79636d0c41511c6df3c ("Refactor atfork
handlers") introduced a lock, atfork_lock, around fork handler list
accesses. It turns out that this lock occasionally results in
self-deadlocks in malloc/tst-mallocfork2:
(gdb) bt
#0 __lll_lock_wait_private ()
at ../sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:63
#1 0x00007f160c6f927a in __run_fork_handlers (who=(unknown: 209394016),
who@entry=atfork_run_prepare) at register-atfork.c:116
#2 0x00007f160c6b7897 in __libc_fork () at ../sysdeps/nptl/fork.c:58
#3 0x00000000004027d6 in sigusr1_handler (signo=<optimized out>)
at tst-mallocfork2.c:80
#4 sigusr1_handler (signo=<optimized out>) at tst-mallocfork2.c:64
#5 <signal handler called>
#6 0x00007f160c6f92e4 in __run_fork_handlers (who=who@entry=atfork_run_parent)
at register-atfork.c:136
#7 0x00007f160c6b79a2 in __libc_fork () at ../sysdeps/nptl/fork.c:152
#8 0x0000000000402567 in do_test () at tst-mallocfork2.c:156
#9 0x0000000000402dd2 in support_test_main (argc=1, argv=0x7ffc81ef1ab0,
config=config@entry=0x7ffc81ef1970) at support_test_main.c:350
#10 0x0000000000402362 in main (argc=<optimized out>, argv=<optimized out>)
at ../support/test-driver.c:168
If no locking happens in the single-threaded case (where fork is
expected to be async-signal-safe), this deadlock is avoided.
(pthread_atfork is not required to be async-signal-safe, so a fork
call from a signal handler interrupting pthread_atfork is not
a problem.)
(cherry picked from commit 669ff911e2571f74a2668493e326ac9a505776bd)
---
ChangeLog | 10 ++++++++++
NEWS | 1 +
nptl/register-atfork.c | 8 +++++---
sysdeps/nptl/fork.c | 6 +++---
sysdeps/nptl/fork.h | 8 +++++---
5 files changed, 24 insertions(+), 9 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 7a8895bcc6..d363be4620 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2019-02-08 Florian Weimer <fweimer@redhat.com>
+
+ [BZ #24161]
+ * sysdeps/nptl/fork.h (__run_fork_handlers): Add multiple_threads
+ argument.
+ * nptl/register-atfork.c (__run_fork_handlers): Only perform
+ locking if the new do_locking argument is true.
+ * sysdeps/nptl/fork.c (__libc_fork): Pass multiple_threads to
+ __run_fork_handlers.
+
2019-02-07 Stefan Liebler <stli@linux.ibm.com>
[BZ #24180]
diff --git a/NEWS b/NEWS
index 1f0fc4b3cb..dbcdd48502 100644
--- a/NEWS
+++ b/NEWS
@@ -11,6 +11,7 @@ The following bugs are resolved with this release:
[24155] x32 memcmp can treat positive length as 0 (if sign bit in RDX is set) (CVE-2019-7309)
[24164] Systemtap probes need to use "nr" constraint on 32-bit Arm
+ [24161] __run_fork_handlers self-deadlocks in malloc/tst-mallocfork2
Security related changes:
diff --git a/nptl/register-atfork.c b/nptl/register-atfork.c
index bc797b761a..80a1becb5f 100644
--- a/nptl/register-atfork.c
+++ b/nptl/register-atfork.c
@@ -107,13 +107,14 @@ __unregister_atfork (void *dso_handle)
}
void
-__run_fork_handlers (enum __run_fork_handler_type who)
+__run_fork_handlers (enum __run_fork_handler_type who, _Bool do_locking)
{
struct fork_handler *runp;
if (who == atfork_run_prepare)
{
- lll_lock (atfork_lock, LLL_PRIVATE);
+ if (do_locking)
+ lll_lock (atfork_lock, LLL_PRIVATE);
size_t sl = fork_handler_list_size (&fork_handlers);
for (size_t i = sl; i > 0; i--)
{
@@ -133,7 +134,8 @@ __run_fork_handlers (enum __run_fork_handler_type who)
else if (who == atfork_run_parent && runp->parent_handler)
runp->parent_handler ();
}
- lll_unlock (atfork_lock, LLL_PRIVATE);
+ if (do_locking)
+ lll_unlock (atfork_lock, LLL_PRIVATE);
}
}
diff --git a/sysdeps/nptl/fork.c b/sysdeps/nptl/fork.c
index bd68f18b45..14b69a6f89 100644
--- a/sysdeps/nptl/fork.c
+++ b/sysdeps/nptl/fork.c
@@ -55,7 +55,7 @@ __libc_fork (void)
but our current fork implementation is not. */
bool multiple_threads = THREAD_GETMEM (THREAD_SELF, header.multiple_threads);
- __run_fork_handlers (atfork_run_prepare);
+ __run_fork_handlers (atfork_run_prepare, multiple_threads);
/* If we are not running multiple threads, we do not have to
preserve lock state. If fork runs from a signal handler, only
@@ -134,7 +134,7 @@ __libc_fork (void)
__rtld_lock_initialize (GL(dl_load_lock));
/* Run the handlers registered for the child. */
- __run_fork_handlers (atfork_run_child);
+ __run_fork_handlers (atfork_run_child, multiple_threads);
}
else
{
@@ -149,7 +149,7 @@ __libc_fork (void)
}
/* Run the handlers registered for the parent. */
- __run_fork_handlers (atfork_run_parent);
+ __run_fork_handlers (atfork_run_parent, multiple_threads);
}
return pid;
diff --git a/sysdeps/nptl/fork.h b/sysdeps/nptl/fork.h
index a1c3b26b68..99ed76034b 100644
--- a/sysdeps/nptl/fork.h
+++ b/sysdeps/nptl/fork.h
@@ -52,9 +52,11 @@ enum __run_fork_handler_type
- atfork_run_child: run all the CHILD_HANDLER and unlocks the internal
lock.
- atfork_run_parent: run all the PARENT_HANDLER and unlocks the internal
- lock. */
-extern void __run_fork_handlers (enum __run_fork_handler_type who)
- attribute_hidden;
+ lock.
+
+ Perform locking only if DO_LOCKING. */
+extern void __run_fork_handlers (enum __run_fork_handler_type who,
+ _Bool do_locking) attribute_hidden;
/* C library side function to register new fork handlers. */
extern int __register_atfork (void (*__prepare) (void),

View file

@ -1,86 +0,0 @@
From 067fc32968b601493f4b247a3ac00caeea3f3d61 Mon Sep 17 00:00:00 2001
From: Florian Weimer <fweimer@redhat.com>
Date: Fri, 15 Feb 2019 21:27:01 +0100
Subject: [PATCH 06] nptl: Fix invalid Systemtap probe in pthread_join [BZ
#24211]
After commit f1ac7455831546e5dca0ed98fe8af2686fae7ce6 ("arm: Use "nr"
constraint for Systemtap probes [BZ #24164]"), we load pd->result into
a register in the probe below:
/* Free the TCB. */
__free_tcb (pd);
}
else
pd->joinid = NULL;
LIBC_PROBE (pthread_join_ret, 3, threadid, result, pd->result);
However, at this point, the thread descriptor has been freed. If the
thread stack does not fit into the thread stack cache, the memory will
have been unmapped, and the program will crash in the probe.
(cherry picked from commit bc10e22c90e42613bd5dafb77b80a9ea1759dd1b)
---
ChangeLog | 6 ++++++
NEWS | 1 +
nptl/pthread_join_common.c | 5 +++--
3 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index d363be4620..a6a0ce19ed 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2019-02-15 Florian Weimer <fweimer@redhat.com>
+
+ [BZ #24211]
+ * nptl/pthread_join_common.c (__pthread_timedjoin_ex): Do not read
+ pd->result after the thread descriptor has been freed.
+
2019-02-08 Florian Weimer <fweimer@redhat.com>
[BZ #24161]
diff --git a/NEWS b/NEWS
index dbcdd48502..340e06d0f4 100644
--- a/NEWS
+++ b/NEWS
@@ -12,6 +12,7 @@ The following bugs are resolved with this release:
[24155] x32 memcmp can treat positive length as 0 (if sign bit in RDX is set) (CVE-2019-7309)
[24164] Systemtap probes need to use "nr" constraint on 32-bit Arm
[24161] __run_fork_handlers self-deadlocks in malloc/tst-mallocfork2
+ [24211] Use-after-free in Systemtap probe in pthread_join
Security related changes:
diff --git a/nptl/pthread_join_common.c b/nptl/pthread_join_common.c
index ecb78ffba5..366feb376b 100644
--- a/nptl/pthread_join_common.c
+++ b/nptl/pthread_join_common.c
@@ -86,6 +86,7 @@ __pthread_timedjoin_ex (pthread_t threadid, void **thread_return,
pthread_cleanup_pop (0);
}
+ void *pd_result = pd->result;
if (__glibc_likely (result == 0))
{
/* We mark the thread as terminated and as joined. */
@@ -93,7 +94,7 @@ __pthread_timedjoin_ex (pthread_t threadid, void **thread_return,
/* Store the return value if the caller is interested. */
if (thread_return != NULL)
- *thread_return = pd->result;
+ *thread_return = pd_result;
/* Free the TCB. */
__free_tcb (pd);
@@ -101,7 +102,7 @@ __pthread_timedjoin_ex (pthread_t threadid, void **thread_return,
else
pd->joinid = NULL;
- LIBC_PROBE (pthread_join_ret, 3, threadid, result, pd->result);
+ LIBC_PROBE (pthread_join_ret, 3, threadid, result, pd_result);
return result;
}

View file

@ -1,161 +0,0 @@
From bc6f839fb4066be83272c735e662850af2595777 Mon Sep 17 00:00:00 2001
From: Stefan Liebler <stli@linux.ibm.com>
Date: Wed, 13 Mar 2019 10:45:35 +0100
Subject: [PATCH 07] Fix output of LD_SHOW_AUXV=1.
Starting with commit 1616d034b61622836d3a36af53dcfca7624c844e
the output was corrupted on some platforms as _dl_procinfo
was called for every auxv entry and on some architectures like s390
all entries were represented as "AT_HWCAP".
This patch is removing the condition and let _dl_procinfo decide if
an entry is printed in a platform specific or generic way.
This patch also adjusts all _dl_procinfo implementations which assumed
that they are only called for AT_HWCAP or AT_HWCAP2. They are now just
returning a non-zero-value for entries which are not handled platform
specifc.
ChangeLog:
* elf/dl-sysdep.c (_dl_show_auxv): Remove condition and always
call _dl_procinfo.
* sysdeps/unix/sysv/linux/s390/dl-procinfo.h (_dl_procinfo):
Ignore types other than AT_HWCAP.
* sysdeps/sparc/dl-procinfo.h (_dl_procinfo): Likewise.
* sysdeps/unix/sysv/linux/i386/dl-procinfo.h (_dl_procinfo):
Likewise.
* sysdeps/powerpc/dl-procinfo.h (_dl_procinfo): Adjust comment
in the case of falling back to generic output mechanism.
* sysdeps/unix/sysv/linux/arm/dl-procinfo.h (_dl_procinfo):
Likewise.
(cherry picked from commit 7c6513082b787a7d36ab7d75720b48f8a216089c)
Conflicts:
ChangeLog
---
ChangeLog | 14 ++++++++++++++
elf/dl-sysdep.c | 11 +++--------
sysdeps/powerpc/dl-procinfo.h | 2 +-
sysdeps/sparc/dl-procinfo.h | 4 ++--
sysdeps/unix/sysv/linux/arm/dl-procinfo.h | 2 +-
sysdeps/unix/sysv/linux/i386/dl-procinfo.h | 4 ++--
sysdeps/unix/sysv/linux/s390/dl-procinfo.h | 4 ++--
7 files changed, 25 insertions(+), 16 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index a6a0ce19ed..90558e434c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2019-03-13 Stefan Liebler <stli@linux.ibm.com>
+
+ * elf/dl-sysdep.c (_dl_show_auxv): Remove condition and always
+ call _dl_procinfo.
+ * sysdeps/unix/sysv/linux/s390/dl-procinfo.h (_dl_procinfo):
+ Ignore types other than AT_HWCAP.
+ * sysdeps/sparc/dl-procinfo.h (_dl_procinfo): Likewise.
+ * sysdeps/unix/sysv/linux/i386/dl-procinfo.h (_dl_procinfo):
+ Likewise.
+ * sysdeps/powerpc/dl-procinfo.h (_dl_procinfo): Adjust comment
+ in the case of falling back to generic output mechanism.
+ * sysdeps/unix/sysv/linux/arm/dl-procinfo.h (_dl_procinfo):
+ Likewise.
+
2019-02-15 Florian Weimer <fweimer@redhat.com>
[BZ #24211]
diff --git a/elf/dl-sysdep.c b/elf/dl-sysdep.c
index 5f6c679a3f..5d19b100b2 100644
--- a/elf/dl-sysdep.c
+++ b/elf/dl-sysdep.c
@@ -328,14 +328,9 @@ _dl_show_auxv (void)
assert (AT_NULL == 0);
assert (AT_IGNORE == 1);
- if (av->a_type == AT_HWCAP || av->a_type == AT_HWCAP2
- || AT_L1I_CACHEGEOMETRY || AT_L1D_CACHEGEOMETRY
- || AT_L2_CACHEGEOMETRY || AT_L3_CACHEGEOMETRY)
- {
- /* These are handled in a special way per platform. */
- if (_dl_procinfo (av->a_type, av->a_un.a_val) == 0)
- continue;
- }
+ /* Some entries are handled in a special way per platform. */
+ if (_dl_procinfo (av->a_type, av->a_un.a_val) == 0)
+ continue;
if (idx < sizeof (auxvars) / sizeof (auxvars[0])
&& auxvars[idx].form != unknown)
diff --git a/sysdeps/powerpc/dl-procinfo.h b/sysdeps/powerpc/dl-procinfo.h
index f542f7318f..dfc3b33a72 100644
--- a/sysdeps/powerpc/dl-procinfo.h
+++ b/sysdeps/powerpc/dl-procinfo.h
@@ -225,7 +225,7 @@ _dl_procinfo (unsigned int type, unsigned long int word)
break;
}
default:
- /* This should not happen. */
+ /* Fallback to generic output mechanism. */
return -1;
}
_dl_printf ("\n");
diff --git a/sysdeps/sparc/dl-procinfo.h b/sysdeps/sparc/dl-procinfo.h
index 282b8c5117..64ee267fc7 100644
--- a/sysdeps/sparc/dl-procinfo.h
+++ b/sysdeps/sparc/dl-procinfo.h
@@ -31,8 +31,8 @@ _dl_procinfo (unsigned int type, unsigned long int word)
{
int i;
- /* Fallback to unknown output mechanism. */
- if (type == AT_HWCAP2)
+ /* Fallback to generic output mechanism. */
+ if (type != AT_HWCAP)
return -1;
_dl_printf ("AT_HWCAP: ");
diff --git a/sysdeps/unix/sysv/linux/arm/dl-procinfo.h b/sysdeps/unix/sysv/linux/arm/dl-procinfo.h
index 66c00297b7..05c62c8687 100644
--- a/sysdeps/unix/sysv/linux/arm/dl-procinfo.h
+++ b/sysdeps/unix/sysv/linux/arm/dl-procinfo.h
@@ -67,7 +67,7 @@ _dl_procinfo (unsigned int type, unsigned long int word)
break;
}
default:
- /* This should not happen. */
+ /* Fallback to generic output mechanism. */
return -1;
}
_dl_printf ("\n");
diff --git a/sysdeps/unix/sysv/linux/i386/dl-procinfo.h b/sysdeps/unix/sysv/linux/i386/dl-procinfo.h
index 22b43431bc..0585cdaa9c 100644
--- a/sysdeps/unix/sysv/linux/i386/dl-procinfo.h
+++ b/sysdeps/unix/sysv/linux/i386/dl-procinfo.h
@@ -30,8 +30,8 @@ _dl_procinfo (unsigned int type, unsigned long int word)
in the kernel sources. */
int i;
- /* Fallback to unknown output mechanism. */
- if (type == AT_HWCAP2)
+ /* Fallback to generic output mechanism. */
+ if (type != AT_HWCAP)
return -1;
_dl_printf ("AT_HWCAP: ");
diff --git a/sysdeps/unix/sysv/linux/s390/dl-procinfo.h b/sysdeps/unix/sysv/linux/s390/dl-procinfo.h
index 19329a335b..d67fde368f 100644
--- a/sysdeps/unix/sysv/linux/s390/dl-procinfo.h
+++ b/sysdeps/unix/sysv/linux/s390/dl-procinfo.h
@@ -32,8 +32,8 @@ _dl_procinfo (unsigned int type, unsigned long int word)
in the kernel sources. */
int i;
- /* Fallback to unknown output mechanism. */
- if (type == AT_HWCAP2)
+ /* Fallback to generic output mechanism. */
+ if (type != AT_HWCAP)
return -1;
_dl_printf ("AT_HWCAP: ");

View file

@ -1,50 +0,0 @@
From 4d0b1b0f61bfba034e9e76a1d76acc59c975238f Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert@cs.ucla.edu>
Date: Mon, 21 Jan 2019 11:08:13 -0800
Subject: [PATCH 08] regex: fix read overrun [BZ #24114]
Problem found by AddressSanitizer, reported by Hongxu Chen in:
https://debbugs.gnu.org/34140
* posix/regexec.c (proceed_next_node):
Do not read past end of input buffer.
(cherry picked from commit 583dd860d5b833037175247230a328f0050dbfe9)
---
ChangeLog | 8 ++++++++
posix/regexec.c | 6 ++++--
2 files changed, 12 insertions(+), 2 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 90558e434c..fb88626efe 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2019-01-31 Paul Eggert <eggert@cs.ucla.edu>
+
+ regex: fix read overrun [BZ #24114]
+ Problem found by AddressSanitizer, reported by Hongxu Chen in:
+ https://debbugs.gnu.org/34140
+ * posix/regexec.c (proceed_next_node):
+ Do not read past end of input buffer.
+
2019-03-13 Stefan Liebler <stli@linux.ibm.com>
* elf/dl-sysdep.c (_dl_show_auxv): Remove condition and always
diff --git a/posix/regexec.c b/posix/regexec.c
index 91d5a797b8..084b1222d9 100644
--- a/posix/regexec.c
+++ b/posix/regexec.c
@@ -1293,8 +1293,10 @@ proceed_next_node (const re_match_context_t *mctx, Idx nregs, regmatch_t *regs,
else if (naccepted)
{
char *buf = (char *) re_string_get_buffer (&mctx->input);
- if (memcmp (buf + regs[subexp_idx].rm_so, buf + *pidx,
- naccepted) != 0)
+ if (mctx->input.valid_len - *pidx < naccepted
+ || (memcmp (buf + regs[subexp_idx].rm_so, buf + *pidx,
+ naccepted)
+ != 0))
return -1;
}
}

View file

@ -1,38 +0,0 @@
From 10dd17da710fd32aaf1f2187544d80064b8c4ee0 Mon Sep 17 00:00:00 2001
From: Aurelien Jarno <aurelien@aurel32.net>
Date: Sat, 16 Mar 2019 22:59:56 +0100
Subject: [PATCH 09] Record CVE-2019-9169 in NEWS and ChangeLog [BZ #24114]
(cherry picked from commit b626c5aa5d0673a9caa48fb79fba8bda237e6fa8)
---
ChangeLog | 1 +
NEWS | 4 ++++
2 files changed, 5 insertions(+)
diff --git a/ChangeLog b/ChangeLog
index fb88626efe..80413dd560 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,6 @@
2019-01-31 Paul Eggert <eggert@cs.ucla.edu>
+ CVE-2019-9169
regex: fix read overrun [BZ #24114]
Problem found by AddressSanitizer, reported by Hongxu Chen in:
https://debbugs.gnu.org/34140
diff --git a/NEWS b/NEWS
index 340e06d0f4..271bf7a2cd 100644
--- a/NEWS
+++ b/NEWS
@@ -24,6 +24,10 @@ Security related changes:
memcmp gave the wrong result since it treated the size argument as
zero. Reported by H.J. Lu.
+ CVE-2019-9169: Attempted case-insensitive regular-expression match
+ via proceed_next_node in posix/regexec.c leads to heap-based buffer
+ over-read. Reported by Hongxu Chen.
+
Version 2.29

View file

@ -1,51 +0,0 @@
From 6eb48fe80cb6dd3ef536e86d005976d1c22b170e Mon Sep 17 00:00:00 2001
From: Stefan Liebler <stli@linux.ibm.com>
Date: Thu, 21 Mar 2019 09:14:26 +0100
Subject: [PATCH 10] S390: Mark vx and vxe as important hwcap.
This patch adds vx and vxe as important hwcaps
which allows one to provide shared libraries
tuned for platforms with non-vx/-vxe, vx or vxe.
ChangeLog:
* sysdeps/s390/dl-procinfo.h (HWCAP_IMPORTANT):
Add HWCAP_S390_VX and HWCAP_S390_VXE.
(cherry picked from commit 61f5e9470fb397a4c334938ac5a667427d9047df)
Conflicts:
ChangeLog
---
ChangeLog | 5 +++++
sysdeps/s390/dl-procinfo.h | 3 ++-
2 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/ChangeLog b/ChangeLog
index 80413dd560..7111aeb149 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2019-03-21 Stefan Liebler <stli@linux.ibm.com>
+
+ * sysdeps/s390/dl-procinfo.h (HWCAP_IMPORTANT):
+ Add HWCAP_S390_VX and HWCAP_S390_VXE.
+
2019-01-31 Paul Eggert <eggert@cs.ucla.edu>
CVE-2019-9169
diff --git a/sysdeps/s390/dl-procinfo.h b/sysdeps/s390/dl-procinfo.h
index b4b81fc70a..99697ae649 100644
--- a/sysdeps/s390/dl-procinfo.h
+++ b/sysdeps/s390/dl-procinfo.h
@@ -57,7 +57,8 @@ enum
};
#define HWCAP_IMPORTANT (HWCAP_S390_ZARCH | HWCAP_S390_LDISP \
- | HWCAP_S390_EIMM | HWCAP_S390_DFP)
+ | HWCAP_S390_EIMM | HWCAP_S390_DFP \
+ | HWCAP_S390_VX | HWCAP_S390_VXE)
/* We cannot provide a general printing function. */
#define _dl_procinfo(type, word) -1

View file

@ -1,53 +0,0 @@
From e28ad442e73b00ae2047d89c8cc7f9b2a0de5436 Mon Sep 17 00:00:00 2001
From: TAMUKI Shoichi <tamuki@linet.gr.jp>
Date: Sat, 2 Mar 2019 21:00:28 +0900
Subject: [PATCH 11] ja_JP: Change the offset for Taisho gan-nen from 2 to 1
[BZ #24162]
The offset in era-string format for Taisho gan-nen (1912) is currently
defined as 2, but it should be 1. So fix it. "Gan-nen" means the 1st
(origin) year, Taisho started on July 30, 1912.
Reported-by: Morimitsu, Junji <junji.morimitsu@hpe.com>
Reviewed-by: Rafal Luzynski <digitalfreak@lingonborough.com>
ChangeLog:
[BZ #24162]
* localedata/locales/ja_JP (LC_TIME): Change the offset for Taisho
gan-nen from 2 to 1. Problem reported by Morimitsu, Junji.
(cherry picked from commit 31effacee2fc1b327bedc9a5fcb4b83f227c6539)
---
ChangeLog | 6 ++++++
localedata/locales/ja_JP | 2 +-
2 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/ChangeLog b/ChangeLog
index 7111aeb149..048ca9644c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2019-03-02 TAMUKI Shoichi <tamuki@linet.gr.jp>
+
+ [BZ #24162]
+ * localedata/locales/ja_JP (LC_TIME): Change the offset for Taisho
+ gan-nen from 2 to 1. Problem reported by Morimitsu, Junji.
+
2019-03-21 Stefan Liebler <stli@linux.ibm.com>
* sysdeps/s390/dl-procinfo.h (HWCAP_IMPORTANT):
diff --git a/localedata/locales/ja_JP b/localedata/locales/ja_JP
index 1fd2fee44b..9bfbb2bb9b 100644
--- a/localedata/locales/ja_JP
+++ b/localedata/locales/ja_JP
@@ -14951,7 +14951,7 @@ era "+:2:1990//01//01:+*:<U5E73><U6210>:%EC%Ey<U5E74>";/
"+:2:1927//01//01:1989//01//07:<U662D><U548C>:%EC%Ey<U5E74>";/
"+:1:1926//12//25:1926//12//31:<U662D><U548C>:%EC<U5143><U5E74>";/
"+:2:1913//01//01:1926//12//24:<U5927><U6B63>:%EC%Ey<U5E74>";/
- "+:2:1912//07//30:1912//12//31:<U5927><U6B63>:%EC<U5143><U5E74>";/
+ "+:1:1912//07//30:1912//12//31:<U5927><U6B63>:%EC<U5143><U5E74>";/
"+:6:1873//01//01:1912//07//29:<U660E><U6CBB>:%EC%Ey<U5E74>";/
"+:1:0001//01//01:1872//12//31:<U897F><U66A6>:%EC%Ey<U5E74>";/
"+:1:-0001//12//31:-*:<U7D00><U5143><U524D>:%EC%Ey<U5E74>"

View file

@ -1,66 +0,0 @@
From 0941350c20a52447e53c5169354408e3db591f73 Mon Sep 17 00:00:00 2001
From: TAMUKI Shoichi <tamuki@linet.gr.jp>
Date: Tue, 2 Apr 2019 16:46:55 +0900
Subject: [PATCH 12] ja_JP locale: Add entry for the new Japanese era [BZ
#22964]
The Japanese era name will be changed on May 1, 2019. The Japanese
government made a preliminary announcement on April 1, 2019.
The glibc ja_JP locale must be updated to include the new era name for
strftime's alternative year format support.
This is a minimal cherry pick of just the required locale changes.
(cherry picked from commit 466afec30896585b60c2106df7a722a86247c9f3)
---
ChangeLog | 6 ++++++
NEWS | 4 ++++
localedata/locales/ja_JP | 4 +++-
3 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/ChangeLog b/ChangeLog
index 048ca9644c..3b5d24cf67 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2019-04-02 TAMUKI Shoichi <tamuki@linet.gr.jp>
+
+ [BZ #22964]
+ * localedata/locales/ja_JP (LC_TIME): Add entry for the new Japanese
+ era.
+
2019-03-02 TAMUKI Shoichi <tamuki@linet.gr.jp>
[BZ #24162]
diff --git a/NEWS b/NEWS
index 271bf7a2cd..703864ac75 100644
--- a/NEWS
+++ b/NEWS
@@ -7,6 +7,10 @@ using `glibc' in the "product" field.
Version 2.29.1
+Major new features:
+
+* The entry for the new Japanese era has been added for ja_JP locale.
+
The following bugs are resolved with this release:
[24155] x32 memcmp can treat positive length as 0 (if sign bit in RDX is set) (CVE-2019-7309)
diff --git a/localedata/locales/ja_JP b/localedata/locales/ja_JP
index 9bfbb2bb9b..c64aaaff55 100644
--- a/localedata/locales/ja_JP
+++ b/localedata/locales/ja_JP
@@ -14946,7 +14946,9 @@ am_pm "<U5348><U524D>";"<U5348><U5F8C>"
t_fmt_ampm "%p%I<U6642>%M<U5206>%S<U79D2>"
-era "+:2:1990//01//01:+*:<U5E73><U6210>:%EC%Ey<U5E74>";/
+era "+:2:2020//01//01:+*:<U4EE4><U548C>:%EC%Ey<U5E74>";/
+ "+:1:2019//05//01:2019//12//31:<U4EE4><U548C>:%EC<U5143><U5E74>";/
+ "+:2:1990//01//01:2019//04//30:<U5E73><U6210>:%EC%Ey<U5E74>";/
"+:1:1989//01//08:1989//12//31:<U5E73><U6210>:%EC<U5143><U5E74>";/
"+:2:1927//01//01:1989//01//07:<U662D><U548C>:%EC%Ey<U5E74>";/
"+:1:1926//12//25:1926//12//31:<U662D><U548C>:%EC<U5143><U5E74>";/

View file

@ -1,206 +0,0 @@
From dcd2b97dd1d695445d45beb4daa815cfe06691dd Mon Sep 17 00:00:00 2001
From: Carlos O'Donell <carlos@redhat.com>
Date: Mon, 15 Apr 2019 20:49:32 +0200
Subject: [PATCH 13] malloc: Set and reset all hooks for tracing (Bug 16573)
If an error occurs during the tracing operation, particularly during a
call to lock_and_info() which calls _dl_addr, we may end up calling back
into the malloc-subsystem and relock the loader lock and deadlock. For
all intents and purposes the call to _dl_addr can call any of the malloc
family API functions and so we should disable all tracing before calling
such loader functions. This is similar to the strategy that the new
malloc tracer takes when calling the real malloc, namely that all
tracing ceases at the boundary to the real function and any faults at
that point are the purvue of the library (though the new tracer does
this on a per-thread basis in an MT-safe fashion). Since the new tracer
and the hook deprecation are not yet complete we must fix these issues
where we can.
Tested on x86_64 with no regressions.
Co-authored-by: Kwok Cheung Yeung <kcy@codesourcery.com>
Reviewed-by: DJ Delorie <dj@redhat.com>
(cherry picked from commit e621246ec6393ea08ae50310f9d5e72500f8c9bc)
---
ChangeLog | 15 +++++++++++
NEWS | 1 +
malloc/mtrace.c | 72 +++++++++++++++++++++++++++++++------------------
3 files changed, 62 insertions(+), 26 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 3b5d24cf67..077d0dae29 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,18 @@
+2019-04-09 Carlos O'Donell <carlos@redhat.com>
+ Kwok Cheung Yeung <kcy@codesourcery.com>
+
+ [BZ #16573]
+ * malloc/mtrace.c: Define prototypes for all hooks.
+ (set_default_hooks): New function.
+ (set_trace_hooks): Likewise.
+ (save_default_hooks): Likewise.
+ (tr_freehook): Use new s*_hooks functions.
+ (tr_mallochook): Likewise.
+ (tr_reallochook): Likewise.
+ (tr_memalignhook): Likewise.
+ (mtrace): Likewise.
+ (muntrace): Likewise.
+
2019-04-02 TAMUKI Shoichi <tamuki@linet.gr.jp>
[BZ #22964]
diff --git a/NEWS b/NEWS
index 703864ac75..117646df7b 100644
--- a/NEWS
+++ b/NEWS
@@ -13,6 +13,7 @@ Major new features:
The following bugs are resolved with this release:
+ [16573] malloc: Set and reset all hooks for tracing
[24155] x32 memcmp can treat positive length as 0 (if sign bit in RDX is set) (CVE-2019-7309)
[24164] Systemtap probes need to use "nr" constraint on 32-bit Arm
[24161] __run_fork_handlers self-deadlocks in malloc/tst-mallocfork2
diff --git a/malloc/mtrace.c b/malloc/mtrace.c
index a2facf65ea..2fda262508 100644
--- a/malloc/mtrace.c
+++ b/malloc/mtrace.c
@@ -121,6 +121,41 @@ lock_and_info (const void *caller, Dl_info *mem)
return res;
}
+static void tr_freehook (void *, const void *);
+static void * tr_mallochook (size_t, const void *);
+static void * tr_reallochook (void *, size_t, const void *);
+static void * tr_memalignhook (size_t, size_t, const void *);
+
+/* Set all the default non-trace hooks. */
+static __always_inline void
+set_default_hooks (void)
+{
+ __free_hook = tr_old_free_hook;
+ __malloc_hook = tr_old_malloc_hook;
+ __realloc_hook = tr_old_realloc_hook;
+ __memalign_hook = tr_old_memalign_hook;
+}
+
+/* Set all of the tracing hooks used for mtrace. */
+static __always_inline void
+set_trace_hooks (void)
+{
+ __free_hook = tr_freehook;
+ __malloc_hook = tr_mallochook;
+ __realloc_hook = tr_reallochook;
+ __memalign_hook = tr_memalignhook;
+}
+
+/* Save the current set of hooks as the default hooks. */
+static __always_inline void
+save_default_hooks (void)
+{
+ tr_old_free_hook = __free_hook;
+ tr_old_malloc_hook = __malloc_hook;
+ tr_old_realloc_hook = __realloc_hook;
+ tr_old_memalign_hook = __memalign_hook;
+}
+
static void
tr_freehook (void *ptr, const void *caller)
{
@@ -138,12 +173,12 @@ tr_freehook (void *ptr, const void *caller)
tr_break ();
__libc_lock_lock (lock);
}
- __free_hook = tr_old_free_hook;
+ set_default_hooks ();
if (tr_old_free_hook != NULL)
(*tr_old_free_hook)(ptr, caller);
else
free (ptr);
- __free_hook = tr_freehook;
+ set_trace_hooks ();
__libc_lock_unlock (lock);
}
@@ -155,12 +190,12 @@ tr_mallochook (size_t size, const void *caller)
Dl_info mem;
Dl_info *info = lock_and_info (caller, &mem);
- __malloc_hook = tr_old_malloc_hook;
+ set_default_hooks ();
if (tr_old_malloc_hook != NULL)
hdr = (void *) (*tr_old_malloc_hook)(size, caller);
else
hdr = (void *) malloc (size);
- __malloc_hook = tr_mallochook;
+ set_trace_hooks ();
tr_where (caller, info);
/* We could be printing a NULL here; that's OK. */
@@ -185,16 +220,12 @@ tr_reallochook (void *ptr, size_t size, const void *caller)
Dl_info mem;
Dl_info *info = lock_and_info (caller, &mem);
- __free_hook = tr_old_free_hook;
- __malloc_hook = tr_old_malloc_hook;
- __realloc_hook = tr_old_realloc_hook;
+ set_default_hooks ();
if (tr_old_realloc_hook != NULL)
hdr = (void *) (*tr_old_realloc_hook)(ptr, size, caller);
else
hdr = (void *) realloc (ptr, size);
- __free_hook = tr_freehook;
- __malloc_hook = tr_mallochook;
- __realloc_hook = tr_reallochook;
+ set_trace_hooks ();
tr_where (caller, info);
if (hdr == NULL)
@@ -230,14 +261,12 @@ tr_memalignhook (size_t alignment, size_t size, const void *caller)
Dl_info mem;
Dl_info *info = lock_and_info (caller, &mem);
- __memalign_hook = tr_old_memalign_hook;
- __malloc_hook = tr_old_malloc_hook;
+ set_default_hooks ();
if (tr_old_memalign_hook != NULL)
hdr = (void *) (*tr_old_memalign_hook)(alignment, size, caller);
else
hdr = (void *) memalign (alignment, size);
- __memalign_hook = tr_memalignhook;
- __malloc_hook = tr_mallochook;
+ set_trace_hooks ();
tr_where (caller, info);
/* We could be printing a NULL here; that's OK. */
@@ -305,14 +334,8 @@ mtrace (void)
malloc_trace_buffer = mtb;
setvbuf (mallstream, malloc_trace_buffer, _IOFBF, TRACE_BUFFER_SIZE);
fprintf (mallstream, "= Start\n");
- tr_old_free_hook = __free_hook;
- __free_hook = tr_freehook;
- tr_old_malloc_hook = __malloc_hook;
- __malloc_hook = tr_mallochook;
- tr_old_realloc_hook = __realloc_hook;
- __realloc_hook = tr_reallochook;
- tr_old_memalign_hook = __memalign_hook;
- __memalign_hook = tr_memalignhook;
+ save_default_hooks ();
+ set_trace_hooks ();
#ifdef _LIBC
if (!added_atexit_handler)
{
@@ -338,10 +361,7 @@ muntrace (void)
file. */
FILE *f = mallstream;
mallstream = NULL;
- __free_hook = tr_old_free_hook;
- __malloc_hook = tr_old_malloc_hook;
- __realloc_hook = tr_old_realloc_hook;
- __memalign_hook = tr_old_memalign_hook;
+ set_default_hooks ();
fprintf (f, "= End\n");
fclose (f);

View file

@ -1,69 +0,0 @@
From 42dfc13abf6fbb4c7a0215238eb636b7d374e0e0 Mon Sep 17 00:00:00 2001
From: Mike Frysinger <vapier@gentoo.org>
Date: Wed, 24 Apr 2019 19:07:46 +0200
Subject: [PATCH 14] memusagestat: use local glibc when linking [BZ #18465]
The memusagestat is the only binary that has its own link line which
causes it to be linked against the existing installed C library. It
has been this way since it was originally committed in 1999, but I
don't see any reason as to why. Since we want all the programs we
build locally to be against the new copy of glibc, change the build
to be like all other programs.
(cherry picked from commit f9b645b4b0a10c43753296ce3fa40053fa44606a)
---
ChangeLog | 7 +++++++
NEWS | 1 +
malloc/Makefile | 4 ++--
3 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 077d0dae29..5291a88f85 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2019-04-24 Mike Frysinger <vapier@gentoo.org>
+
+ [BZ #18465]
+ * malloc/Makefile (others): Add memusagestat.
+ ($(objpfx)memusagestat): Delete rule.
+ (LDLIBS-memusagestat): New variable.
+
2019-04-09 Carlos O'Donell <carlos@redhat.com>
Kwok Cheung Yeung <kcy@codesourcery.com>
diff --git a/NEWS b/NEWS
index 117646df7b..07e099b5ec 100644
--- a/NEWS
+++ b/NEWS
@@ -14,6 +14,7 @@ Major new features:
The following bugs are resolved with this release:
[16573] malloc: Set and reset all hooks for tracing
+ [18465] memusagestat: use local glibc when linking
[24155] x32 memcmp can treat positive length as 0 (if sign bit in RDX is set) (CVE-2019-7309)
[24164] Systemtap probes need to use "nr" constraint on 32-bit Arm
[24161] __run_fork_handlers self-deadlocks in malloc/tst-mallocfork2
diff --git a/malloc/Makefile b/malloc/Makefile
index ab2eed09c6..aadf602dfd 100644
--- a/malloc/Makefile
+++ b/malloc/Makefile
@@ -131,6 +131,7 @@ ifneq ($(cross-compiling),yes)
# If the gd library is available we build the `memusagestat' program.
ifneq ($(LIBGD),no)
others: $(objpfx)memusage
+others += memusagestat
install-bin = memusagestat
install-bin-script += memusage
generated += memusagestat memusage
@@ -154,8 +155,7 @@ cpp-srcs-left := $(memusagestat-modules)
lib := memusagestat
include $(patsubst %,$(..)libof-iterator.mk,$(cpp-srcs-left))
-$(objpfx)memusagestat: $(memusagestat-modules:%=$(objpfx)%.o)
- $(LINK.o) -o $@ $^ $(libgd-LDFLAGS) -lgd -lpng -lz -lm
+LDLIBS-memusagestat = $(libgd-LDFLAGS) -lgd -lpng -lz -lm
ifeq ($(run-built-tests),yes)
ifeq (yes,$(build-shared))

View file

@ -1,67 +0,0 @@
From 0744a268bc73e42b14b83e4cf3d083c6df6344e8 Mon Sep 17 00:00:00 2001
From: Florian Weimer <fweimer@redhat.com>
Date: Thu, 25 Apr 2019 14:58:13 +0200
Subject: [PATCH 15] Revert "memusagestat: use local glibc when linking [BZ
#18465]"
This reverts commit 42dfc13abf6fbb4c7a0215238eb636b7d374e0e0.
The position of the -Wl,-rpath-link= options on the linker command
line is not correct, so the new way of linking memusagestat does not
always work.
---
ChangeLog | 7 -------
NEWS | 1 -
malloc/Makefile | 4 ++--
3 files changed, 2 insertions(+), 10 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 5291a88f85..077d0dae29 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,10 +1,3 @@
-2019-04-24 Mike Frysinger <vapier@gentoo.org>
-
- [BZ #18465]
- * malloc/Makefile (others): Add memusagestat.
- ($(objpfx)memusagestat): Delete rule.
- (LDLIBS-memusagestat): New variable.
-
2019-04-09 Carlos O'Donell <carlos@redhat.com>
Kwok Cheung Yeung <kcy@codesourcery.com>
diff --git a/NEWS b/NEWS
index 07e099b5ec..117646df7b 100644
--- a/NEWS
+++ b/NEWS
@@ -14,7 +14,6 @@ Major new features:
The following bugs are resolved with this release:
[16573] malloc: Set and reset all hooks for tracing
- [18465] memusagestat: use local glibc when linking
[24155] x32 memcmp can treat positive length as 0 (if sign bit in RDX is set) (CVE-2019-7309)
[24164] Systemtap probes need to use "nr" constraint on 32-bit Arm
[24161] __run_fork_handlers self-deadlocks in malloc/tst-mallocfork2
diff --git a/malloc/Makefile b/malloc/Makefile
index aadf602dfd..ab2eed09c6 100644
--- a/malloc/Makefile
+++ b/malloc/Makefile
@@ -131,7 +131,6 @@ ifneq ($(cross-compiling),yes)
# If the gd library is available we build the `memusagestat' program.
ifneq ($(LIBGD),no)
others: $(objpfx)memusage
-others += memusagestat
install-bin = memusagestat
install-bin-script += memusage
generated += memusagestat memusage
@@ -155,7 +154,8 @@ cpp-srcs-left := $(memusagestat-modules)
lib := memusagestat
include $(patsubst %,$(..)libof-iterator.mk,$(cpp-srcs-left))
-LDLIBS-memusagestat = $(libgd-LDFLAGS) -lgd -lpng -lz -lm
+$(objpfx)memusagestat: $(memusagestat-modules:%=$(objpfx)%.o)
+ $(LINK.o) -o $@ $^ $(libgd-LDFLAGS) -lgd -lpng -lz -lm
ifeq ($(run-built-tests),yes)
ifeq (yes,$(build-shared))

View file

@ -1,852 +0,0 @@
From f62d21a1f0107e6f7182f346293583c9121a877d Mon Sep 17 00:00:00 2001
From: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date: Fri, 12 Apr 2019 17:39:53 -0300
Subject: [PATCH 16] support: Add support_capture_subprogram
Its API is similar to support_capture_subprocess, but rather creates a
new process based on the input path and arguments. Under the hoods it
uses posix_spawn to create the new process.
It also allows the use of other support_capture_* functions to check
for expected results and free the resources.
Checked on x86_64-linux-gnu.
* support/Makefile (libsupport-routines): Add support_subprocess,
xposix_spawn, xposix_spawn_file_actions_addclose, and
xposix_spawn_file_actions_adddup2.
(tst-support_capture_subprocess-ARGS): New rule.
* support/capture_subprocess.h (support_capture_subprogram): New
prototype.
* support/support_capture_subprocess.c (support_capture_subprocess):
Refactor to use support_subprocess and support_capture_poll.
(support_capture_subprogram): New function.
* support/tst-support_capture_subprocess.c (write_mode_to_str,
str_to_write_mode, test_common, parse_int, handle_restart,
do_subprocess, do_subprogram, do_multiple_tests): New functions.
(do_test): Add support_capture_subprogram tests.
* support/subprocess.h: New file.
* support/support_subprocess.c: Likewise.
* support/xposix_spawn.c: Likewise.
* support/xposix_spawn_file_actions_addclose.c: Likewise.
* support/xposix_spawn_file_actions_adddup2.c: Likewise.
* support/xspawn.h: Likewise.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
(cherry picked from commit 0e169691290a6d2187a4ff41495fc5678cbfdcdc)
---
ChangeLog | 22 +++
support/Makefile | 6 +
support/capture_subprocess.h | 6 +
support/subprocess.h | 49 +++++
support/support_capture_subprocess.c | 80 ++++----
support/support_subprocess.c | 152 +++++++++++++++
support/tst-support_capture_subprocess.c | 183 ++++++++++++++++++-
support/xposix_spawn.c | 32 ++++
support/xposix_spawn_file_actions_addclose.c | 29 +++
support/xposix_spawn_file_actions_adddup2.c | 30 +++
support/xspawn.h | 34 ++++
11 files changed, 573 insertions(+), 50 deletions(-)
create mode 100644 support/subprocess.h
create mode 100644 support/support_subprocess.c
create mode 100644 support/xposix_spawn.c
create mode 100644 support/xposix_spawn_file_actions_addclose.c
create mode 100644 support/xposix_spawn_file_actions_adddup2.c
create mode 100644 support/xspawn.h
diff --git a/ChangeLog b/ChangeLog
index 077d0dae29..2524e25697 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,25 @@
+2019-04-17 Adhemerval Zanella <adhemerval.zanella@linaro.org>
+
+ * support/Makefile (libsupport-routines): Add support_subprocess,
+ xposix_spawn, xposix_spawn_file_actions_addclose, and
+ xposix_spawn_file_actions_adddup2.
+ (tst-support_capture_subprocess-ARGS): New rule.
+ * support/capture_subprocess.h (support_capture_subprogram): New
+ prototype.
+ * support/support_capture_subprocess.c (support_capture_subprocess):
+ Refactor to use support_subprocess and support_capture_poll.
+ (support_capture_subprogram): New function.
+ * support/tst-support_capture_subprocess.c (write_mode_to_str,
+ str_to_write_mode, test_common, parse_int, handle_restart,
+ do_subprocess, do_subprogram, do_multiple_tests): New functions.
+ (do_test): Add support_capture_subprogram tests.
+ * support/subprocess.h: New file.
+ * support/support_subprocess.c: Likewise.
+ * support/xposix_spawn.c: Likewise.
+ * support/xposix_spawn_file_actions_addclose.c: Likewise.
+ * support/xposix_spawn_file_actions_adddup2.c: Likewise.
+ * support/xspawn.h: Likewise.
+
2019-04-09 Carlos O'Donell <carlos@redhat.com>
Kwok Cheung Yeung <kcy@codesourcery.com>
diff --git a/support/Makefile b/support/Makefile
index c15b93647c..8d61de6c57 100644
--- a/support/Makefile
+++ b/support/Makefile
@@ -63,6 +63,7 @@ libsupport-routines = \
support_record_failure \
support_run_diff \
support_shared_allocate \
+ support_subprocess \
support_test_compare_blob \
support_test_compare_failure \
support_test_compare_string \
@@ -148,6 +149,9 @@ libsupport-routines = \
xsignal \
xsigstack \
xsocket \
+ xposix_spawn \
+ xposix_spawn_file_actions_addclose \
+ xposix_spawn_file_actions_adddup2 \
xstrdup \
xstrndup \
xsymlink \
@@ -223,4 +227,6 @@ endif
$(objpfx)tst-support_format_dns_packet: $(common-objpfx)resolv/libresolv.so
+tst-support_capture_subprocess-ARGS = -- $(host-test-program-cmd)
+
include ../Rules
diff --git a/support/capture_subprocess.h b/support/capture_subprocess.h
index 2dce42e3a3..2832cfc635 100644
--- a/support/capture_subprocess.h
+++ b/support/capture_subprocess.h
@@ -35,6 +35,12 @@ struct support_capture_subprocess
struct support_capture_subprocess support_capture_subprocess
(void (*callback) (void *), void *closure);
+/* Issue FILE with ARGV arguments by using posix_spawn and capture standard
+ output, standard error, and the exit status. The out.buffer and err.buffer
+ are handle as support_capture_subprocess. */
+struct support_capture_subprocess support_capture_subprogram
+ (const char *file, char *const argv[]);
+
/* Deallocate the subprocess data captured by
support_capture_subprocess. */
void support_capture_subprocess_free (struct support_capture_subprocess *);
diff --git a/support/subprocess.h b/support/subprocess.h
new file mode 100644
index 0000000000..c031878d94
--- /dev/null
+++ b/support/subprocess.h
@@ -0,0 +1,49 @@
+/* Create a subprocess.
+ Copyright (C) 2019 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef SUPPORT_SUBPROCESS_H
+#define SUPPORT_SUBPROCESS_H
+
+#include <sys/types.h>
+
+struct support_subprocess
+{
+ int stdout_pipe[2];
+ int stderr_pipe[2];
+ pid_t pid;
+};
+
+/* Invoke CALLBACK (CLOSURE) in a subprocess created with fork and return
+ its PID, a pipe redirected to STDOUT, and a pipe redirected to STDERR. */
+struct support_subprocess support_subprocess
+ (void (*callback) (void *), void *closure);
+
+/* Issue FILE with ARGV arguments by using posix_spawn and return is PID, a
+ pipe redirected to STDOUT, and a pipe redirected to STDERR. */
+struct support_subprocess support_subprogram
+ (const char *file, char *const argv[]);
+
+/* Wait for the subprocess indicated by PROC::PID. Return the status
+ indicate by waitpid call. */
+int support_process_wait (struct support_subprocess *proc);
+
+/* Terminate the subprocess indicated by PROC::PID, first with a SIGTERM and
+ then with a SIGKILL. Return the status as for waitpid call. */
+int support_process_terminate (struct support_subprocess *proc);
+
+#endif
diff --git a/support/support_capture_subprocess.c b/support/support_capture_subprocess.c
index 167514faf1..948ce5a0c6 100644
--- a/support/support_capture_subprocess.c
+++ b/support/support_capture_subprocess.c
@@ -16,6 +16,7 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
+#include <support/subprocess.h>
#include <support/capture_subprocess.h>
#include <errno.h>
@@ -23,6 +24,7 @@
#include <support/check.h>
#include <support/xunistd.h>
#include <support/xsocket.h>
+#include <support/xspawn.h>
static void
transfer (const char *what, struct pollfd *pfd, struct xmemstream *stream)
@@ -50,59 +52,53 @@ transfer (const char *what, struct pollfd *pfd, struct xmemstream *stream)
}
}
-struct support_capture_subprocess
-support_capture_subprocess (void (*callback) (void *), void *closure)
+static void
+support_capture_poll (struct support_capture_subprocess *result,
+ struct support_subprocess *proc)
{
- struct support_capture_subprocess result;
- xopen_memstream (&result.out);
- xopen_memstream (&result.err);
-
- int stdout_pipe[2];
- xpipe (stdout_pipe);
- TEST_VERIFY (stdout_pipe[0] > STDERR_FILENO);
- TEST_VERIFY (stdout_pipe[1] > STDERR_FILENO);
- int stderr_pipe[2];
- xpipe (stderr_pipe);
- TEST_VERIFY (stderr_pipe[0] > STDERR_FILENO);
- TEST_VERIFY (stderr_pipe[1] > STDERR_FILENO);
-
- TEST_VERIFY (fflush (stdout) == 0);
- TEST_VERIFY (fflush (stderr) == 0);
-
- pid_t pid = xfork ();
- if (pid == 0)
- {
- xclose (stdout_pipe[0]);
- xclose (stderr_pipe[0]);
- xdup2 (stdout_pipe[1], STDOUT_FILENO);
- xdup2 (stderr_pipe[1], STDERR_FILENO);
- xclose (stdout_pipe[1]);
- xclose (stderr_pipe[1]);
- callback (closure);
- _exit (0);
- }
- xclose (stdout_pipe[1]);
- xclose (stderr_pipe[1]);
-
struct pollfd fds[2] =
{
- { .fd = stdout_pipe[0], .events = POLLIN },
- { .fd = stderr_pipe[0], .events = POLLIN },
+ { .fd = proc->stdout_pipe[0], .events = POLLIN },
+ { .fd = proc->stderr_pipe[0], .events = POLLIN },
};
do
{
xpoll (fds, 2, -1);
- transfer ("stdout", &fds[0], &result.out);
- transfer ("stderr", &fds[1], &result.err);
+ transfer ("stdout", &fds[0], &result->out);
+ transfer ("stderr", &fds[1], &result->err);
}
while (fds[0].events != 0 || fds[1].events != 0);
- xclose (stdout_pipe[0]);
- xclose (stderr_pipe[0]);
- xfclose_memstream (&result.out);
- xfclose_memstream (&result.err);
- xwaitpid (pid, &result.status, 0);
+ xfclose_memstream (&result->out);
+ xfclose_memstream (&result->err);
+
+ result->status = support_process_wait (proc);
+}
+
+struct support_capture_subprocess
+support_capture_subprocess (void (*callback) (void *), void *closure)
+{
+ struct support_capture_subprocess result;
+ xopen_memstream (&result.out);
+ xopen_memstream (&result.err);
+
+ struct support_subprocess proc = support_subprocess (callback, closure);
+
+ support_capture_poll (&result, &proc);
+ return result;
+}
+
+struct support_capture_subprocess
+support_capture_subprogram (const char *file, char *const argv[])
+{
+ struct support_capture_subprocess result;
+ xopen_memstream (&result.out);
+ xopen_memstream (&result.err);
+
+ struct support_subprocess proc = support_subprogram (file, argv);
+
+ support_capture_poll (&result, &proc);
return result;
}
diff --git a/support/support_subprocess.c b/support/support_subprocess.c
new file mode 100644
index 0000000000..0c8cc6af30
--- /dev/null
+++ b/support/support_subprocess.c
@@ -0,0 +1,152 @@
+/* Create subprocess.
+ Copyright (C) 2019 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <signal.h>
+#include <time.h>
+#include <sys/wait.h>
+#include <stdbool.h>
+#include <support/xspawn.h>
+#include <support/check.h>
+#include <support/xunistd.h>
+#include <support/subprocess.h>
+
+static struct support_subprocess
+support_suprocess_init (void)
+{
+ struct support_subprocess result;
+
+ xpipe (result.stdout_pipe);
+ TEST_VERIFY (result.stdout_pipe[0] > STDERR_FILENO);
+ TEST_VERIFY (result.stdout_pipe[1] > STDERR_FILENO);
+
+ xpipe (result.stderr_pipe);
+ TEST_VERIFY (result.stderr_pipe[0] > STDERR_FILENO);
+ TEST_VERIFY (result.stderr_pipe[1] > STDERR_FILENO);
+
+ TEST_VERIFY (fflush (stdout) == 0);
+ TEST_VERIFY (fflush (stderr) == 0);
+
+ return result;
+}
+
+struct support_subprocess
+support_subprocess (void (*callback) (void *), void *closure)
+{
+ struct support_subprocess result = support_suprocess_init ();
+
+ result.pid = xfork ();
+ if (result.pid == 0)
+ {
+ xclose (result.stdout_pipe[0]);
+ xclose (result.stderr_pipe[0]);
+ xdup2 (result.stdout_pipe[1], STDOUT_FILENO);
+ xdup2 (result.stderr_pipe[1], STDERR_FILENO);
+ xclose (result.stdout_pipe[1]);
+ xclose (result.stderr_pipe[1]);
+ callback (closure);
+ _exit (0);
+ }
+ xclose (result.stdout_pipe[1]);
+ xclose (result.stderr_pipe[1]);
+
+ return result;
+}
+
+struct support_subprocess
+support_subprogram (const char *file, char *const argv[])
+{
+ struct support_subprocess result = support_suprocess_init ();
+
+ posix_spawn_file_actions_t fa;
+ /* posix_spawn_file_actions_init does not fail. */
+ posix_spawn_file_actions_init (&fa);
+
+ xposix_spawn_file_actions_addclose (&fa, result.stdout_pipe[0]);
+ xposix_spawn_file_actions_addclose (&fa, result.stderr_pipe[0]);
+ xposix_spawn_file_actions_adddup2 (&fa, result.stdout_pipe[1], STDOUT_FILENO);
+ xposix_spawn_file_actions_adddup2 (&fa, result.stderr_pipe[1], STDERR_FILENO);
+ xposix_spawn_file_actions_addclose (&fa, result.stdout_pipe[1]);
+ xposix_spawn_file_actions_addclose (&fa, result.stderr_pipe[1]);
+
+ result.pid = xposix_spawn (file, &fa, NULL, argv, NULL);
+
+ xclose (result.stdout_pipe[1]);
+ xclose (result.stderr_pipe[1]);
+
+ return result;
+}
+
+int
+support_process_wait (struct support_subprocess *proc)
+{
+ xclose (proc->stdout_pipe[0]);
+ xclose (proc->stderr_pipe[0]);
+
+ int status;
+ xwaitpid (proc->pid, &status, 0);
+ return status;
+}
+
+
+static bool
+support_process_kill (int pid, int signo, int *status)
+{
+ /* Kill the whole process group. */
+ kill (-pid, signo);
+ /* In case setpgid failed in the child, kill it individually too. */
+ kill (pid, signo);
+
+ /* Wait for it to terminate. */
+ pid_t killed;
+ for (int i = 0; i < 5; ++i)
+ {
+ int status;
+ killed = xwaitpid (pid, &status, WNOHANG|WUNTRACED);
+ if (killed != 0)
+ break;
+
+ /* Delay, give the system time to process the kill. If the
+ nanosleep() call return prematurely, all the better. We
+ won't restart it since this probably means the child process
+ finally died. */
+ nanosleep (&((struct timespec) { 0, 100000000 }), NULL);
+ }
+ if (killed != 0 && killed != pid)
+ return false;
+
+ return true;
+}
+
+int
+support_process_terminate (struct support_subprocess *proc)
+{
+ xclose (proc->stdout_pipe[0]);
+ xclose (proc->stderr_pipe[0]);
+
+ int status;
+ pid_t killed = xwaitpid (proc->pid, &status, WNOHANG|WUNTRACED);
+ if (killed != 0 && killed == proc->pid)
+ return status;
+
+ /* Subprocess is still running, terminate it. */
+ if (!support_process_kill (proc->pid, SIGTERM, &status) )
+ support_process_kill (proc->pid, SIGKILL, &status);
+
+ return status;
+}
diff --git a/support/tst-support_capture_subprocess.c b/support/tst-support_capture_subprocess.c
index d8ba42ea8b..ab363e41ac 100644
--- a/support/tst-support_capture_subprocess.c
+++ b/support/tst-support_capture_subprocess.c
@@ -23,8 +23,20 @@
#include <support/capture_subprocess.h>
#include <support/check.h>
#include <support/support.h>
+#include <support/temp_file.h>
#include <sys/wait.h>
#include <unistd.h>
+#include <paths.h>
+#include <getopt.h>
+#include <limits.h>
+#include <errno.h>
+#include <array_length.h>
+
+/* Nonzero if the program gets called via 'exec'. */
+static int restart;
+
+/* Hold the four initial argument used to respawn the process. */
+static char *initial_argv[5];
/* Write one byte at *P to FD and advance *P. Do nothing if *P is
'\0'. */
@@ -42,6 +54,30 @@ transfer (const unsigned char **p, int fd)
enum write_mode { out_first, err_first, interleave,
write_mode_last = interleave };
+static const char *
+write_mode_to_str (enum write_mode mode)
+{
+ switch (mode)
+ {
+ case out_first: return "out_first";
+ case err_first: return "err_first";
+ case interleave: return "interleave";
+ default: return "write_mode_last";
+ }
+}
+
+static enum write_mode
+str_to_write_mode (const char *mode)
+{
+ if (strcmp (mode, "out_first") == 0)
+ return out_first;
+ else if (strcmp (mode, "err_first") == 0)
+ return err_first;
+ else if (strcmp (mode, "interleave") == 0)
+ return interleave;
+ return write_mode_last;
+}
+
/* Describe what to write in the subprocess. */
struct test
{
@@ -52,11 +88,9 @@ struct test
int status;
};
-/* For use with support_capture_subprocess. */
-static void
-callback (void *closure)
+_Noreturn static void
+test_common (const struct test *test)
{
- const struct test *test = closure;
bool mode_ok = false;
switch (test->write_mode)
{
@@ -95,6 +129,40 @@ callback (void *closure)
exit (test->status);
}
+static int
+parse_int (const char *str)
+{
+ char *endptr;
+ long int ret = strtol (str, &endptr, 10);
+ TEST_COMPARE (errno, 0);
+ TEST_VERIFY (ret >= 0 && ret <= INT_MAX);
+ return ret;
+}
+
+/* For use with support_capture_subprogram. */
+_Noreturn static void
+handle_restart (char *out, char *err, const char *write_mode,
+ const char *signal, const char *status)
+{
+ struct test test =
+ {
+ out,
+ err,
+ str_to_write_mode (write_mode),
+ parse_int (signal),
+ parse_int (status)
+ };
+ test_common (&test);
+}
+
+/* For use with support_capture_subprocess. */
+_Noreturn static void
+callback (void *closure)
+{
+ const struct test *test = closure;
+ test_common (test);
+}
+
/* Create a heap-allocated random string of letters. */
static char *
random_string (size_t length)
@@ -130,12 +198,59 @@ check_stream (const char *what, const struct xmemstream *stream,
}
}
+static struct support_capture_subprocess
+do_subprocess (struct test *test)
+{
+ return support_capture_subprocess (callback, test);
+}
+
+static struct support_capture_subprocess
+do_subprogram (const struct test *test)
+{
+ /* Three digits per byte plus null terminator. */
+ char signalstr[3 * sizeof(int) + 1];
+ snprintf (signalstr, sizeof (signalstr), "%d", test->signal);
+ char statusstr[3 * sizeof(int) + 1];
+ snprintf (statusstr, sizeof (statusstr), "%d", test->status);
+
+ int argc = 0;
+ enum {
+ /* 4 elements from initial_argv (path to ld.so, '--library-path', the
+ path', and application name'), 2 for restart argument ('--direct',
+ '--restart'), 5 arguments plus NULL. */
+ argv_size = 12
+ };
+ char *args[argv_size];
+
+ for (char **arg = initial_argv; *arg != NULL; arg++)
+ args[argc++] = *arg;
+
+ args[argc++] = (char*) "--direct";
+ args[argc++] = (char*) "--restart";
+
+ args[argc++] = test->out;
+ args[argc++] = test->err;
+ args[argc++] = (char*) write_mode_to_str (test->write_mode);
+ args[argc++] = signalstr;
+ args[argc++] = statusstr;
+ args[argc] = NULL;
+ TEST_VERIFY (argc < argv_size);
+
+ return support_capture_subprogram (args[0], args);
+}
+
+enum test_type
+{
+ subprocess,
+ subprogram,
+};
+
static int
-do_test (void)
+do_multiple_tests (enum test_type type)
{
const int lengths[] = {0, 1, 17, 512, 20000, -1};
- /* Test multiple combinations of support_capture_subprocess.
+ /* Test multiple combinations of support_capture_sub{process,program}.
length_idx_stdout: Index into the lengths array above,
controls how many bytes are written by the subprocess to
@@ -164,8 +279,10 @@ do_test (void)
TEST_VERIFY (strlen (test.out) == lengths[length_idx_stdout]);
TEST_VERIFY (strlen (test.err) == lengths[length_idx_stderr]);
- struct support_capture_subprocess result
- = support_capture_subprocess (callback, &test);
+ struct support_capture_subprocess result
+ = type == subprocess ? do_subprocess (&test)
+ : do_subprogram (&test);
+
check_stream ("stdout", &result.out, test.out);
check_stream ("stderr", &result.err, test.err);
@@ -199,4 +316,54 @@ do_test (void)
return 0;
}
+static int
+do_test (int argc, char *argv[])
+{
+ /* We must have either:
+
+ - one or four parameters if called initially:
+ + argv[1]: path for ld.so optional
+ + argv[2]: "--library-path" optional
+ + argv[3]: the library path optional
+ + argv[4]: the application name
+
+ - six parameters left if called through re-execution:
+ + argv[1]: the application name
+ + argv[2]: the stdout to print
+ + argv[3]: the stderr to print
+ + argv[4]: the write mode to use
+ + argv[5]: the signal to issue
+ + argv[6]: the exit status code to use
+
+ * When built with --enable-hardcoded-path-in-tests or issued without
+ using the loader directly.
+ */
+
+ if (argc != (restart ? 6 : 5) && argc != (restart ? 6 : 2))
+ FAIL_EXIT1 ("wrong number of arguments (%d)", argc);
+
+ if (restart)
+ {
+ handle_restart (argv[1], /* stdout */
+ argv[2], /* stderr */
+ argv[3], /* write_mode */
+ argv[4], /* signal */
+ argv[5]); /* status */
+ }
+
+ initial_argv[0] = argv[1]; /* path for ld.so */
+ initial_argv[1] = argv[2]; /* "--library-path" */
+ initial_argv[2] = argv[3]; /* the library path */
+ initial_argv[3] = argv[4]; /* the application name */
+ initial_argv[4] = NULL;
+
+ do_multiple_tests (subprocess);
+ do_multiple_tests (subprogram);
+
+ return 0;
+}
+
+#define CMDLINE_OPTIONS \
+ { "restart", no_argument, &restart, 1 },
+#define TEST_FUNCTION_ARGV do_test
#include <support/test-driver.c>
diff --git a/support/xposix_spawn.c b/support/xposix_spawn.c
new file mode 100644
index 0000000000..e846017632
--- /dev/null
+++ b/support/xposix_spawn.c
@@ -0,0 +1,32 @@
+/* xposix_spawn implementation.
+ Copyright (C) 2019 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <support/xspawn.h>
+#include <support/check.h>
+
+pid_t
+xposix_spawn (const char *file, const posix_spawn_file_actions_t *fa,
+ const posix_spawnattr_t *attr, char *const args[],
+ char *const envp[])
+{
+ pid_t pid;
+ int status = posix_spawn (&pid, file, fa, attr, args, envp);
+ if (status != 0)
+ FAIL_EXIT1 ("posix_spawn to %s file failed: %m", file);
+ return pid;
+}
diff --git a/support/xposix_spawn_file_actions_addclose.c b/support/xposix_spawn_file_actions_addclose.c
new file mode 100644
index 0000000000..eed54a6514
--- /dev/null
+++ b/support/xposix_spawn_file_actions_addclose.c
@@ -0,0 +1,29 @@
+/* xposix_spawn_file_actions_addclose implementation.
+ Copyright (C) 2019 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <support/xspawn.h>
+#include <support/check.h>
+
+int
+xposix_spawn_file_actions_addclose (posix_spawn_file_actions_t *fa, int fd)
+{
+ int status = posix_spawn_file_actions_addclose (fa, fd);
+ if (status == -1)
+ FAIL_EXIT1 ("posix_spawn_file_actions_addclose failed: %m\n");
+ return status;
+}
diff --git a/support/xposix_spawn_file_actions_adddup2.c b/support/xposix_spawn_file_actions_adddup2.c
new file mode 100644
index 0000000000..a43b6490be
--- /dev/null
+++ b/support/xposix_spawn_file_actions_adddup2.c
@@ -0,0 +1,30 @@
+/* xposix_spawn_file_actions_adddup2 implementation.
+ Copyright (C) 2019 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <support/xspawn.h>
+#include <support/check.h>
+
+int
+xposix_spawn_file_actions_adddup2 (posix_spawn_file_actions_t *fa, int fd,
+ int newfd)
+{
+ int status = posix_spawn_file_actions_adddup2 (fa, fd, newfd);
+ if (status == -1)
+ FAIL_EXIT1 ("posix_spawn_file_actions_adddup2 failed: %m\n");
+ return status;
+}
diff --git a/support/xspawn.h b/support/xspawn.h
new file mode 100644
index 0000000000..bbf89132e4
--- /dev/null
+++ b/support/xspawn.h
@@ -0,0 +1,34 @@
+/* posix_spawn with support checks.
+ Copyright (C) 2019 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef SUPPORT_XSPAWN_H
+#define SUPPORT_XSPAWN_H
+
+#include <spawn.h>
+
+__BEGIN_DECLS
+
+int xposix_spawn_file_actions_addclose (posix_spawn_file_actions_t *, int);
+int xposix_spawn_file_actions_adddup2 (posix_spawn_file_actions_t *, int, int);
+
+pid_t xposix_spawn (const char *, const posix_spawn_file_actions_t *,
+ const posix_spawnattr_t *, char *const [], char *const []);
+
+__END_DECLS
+
+#endif

View file

@ -1,616 +0,0 @@
From eaea1dfbe95a31c29adc259100569962cddb6f19 Mon Sep 17 00:00:00 2001
From: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date: Fri, 26 Apr 2019 13:58:31 +0200
Subject: [PATCH 17] elf: Fix pldd (BZ#18035)
Since 9182aa67994 (Fix vDSO l_name for GDB's, BZ#387) the initial link_map
for executable itself and loader will have both l_name and l_libname->name
holding the same value due:
elf/dl-object.c
95 new->l_name = *realname ? realname : (char *) newname->name + libname_len - 1;
Since newname->name points to new->l_libname->name.
This leads to pldd to an infinite call at:
elf/pldd-xx.c
203 again:
204 while (1)
205 {
206 ssize_t n = pread64 (memfd, tmpbuf.data, tmpbuf.length, name_offset);
228 /* Try the l_libname element. */
229 struct E(libname_list) ln;
230 if (pread64 (memfd, &ln, sizeof (ln), m.l_libname) == sizeof (ln))
231 {
232 name_offset = ln.name;
233 goto again;
234 }
Since the value at ln.name (l_libname->name) will be the same as previously
read. The straightforward fix is just avoid the check and read the new list
entry.
I checked also against binaries issues with old loaders with fix for BZ#387,
and pldd could dump the shared objects.
Checked on x86_64-linux-gnu, i686-linux-gnu, aarch64-linux-gnu, and
powerpc64le-linux-gnu.
[BZ #18035]
* elf/Makefile (tests-container): Add tst-pldd.
* elf/pldd-xx.c: Use _Static_assert in of pldd_assert.
(E(find_maps)): Avoid use alloca, use default read file operations
instead of explicit LFS names, and fix infinite loop.
* elf/pldd.c: Explicit set _FILE_OFFSET_BITS, cleanup headers.
(get_process_info): Use _Static_assert instead of assert, use default
directory operations instead of explicit LFS names, and free some
leadek pointers.
* elf/tst-pldd.c: New file.
(cherry picked from commit 1a4c27355e146b6d8cc6487b998462c7fdd1048f)
---
ChangeLog | 13 ++++++
NEWS | 1 +
elf/Makefile | 1 +
elf/pldd-xx.c | 114 +++++++++++++++++------------------------------
elf/pldd.c | 64 +++++++++++++--------------
elf/tst-pldd.c | 118 +++++++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 203 insertions(+), 108 deletions(-)
create mode 100644 elf/tst-pldd.c
diff --git a/ChangeLog b/ChangeLog
index 2524e25697..5af8e27ab9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2019-04-23 Adhemerval Zanella <adhemerval.zanella@linaro.org>
+
+ [BZ #18035]
+ * elf/Makefile (tests-container): Add tst-pldd.
+ * elf/pldd-xx.c: Use _Static_assert in of pldd_assert.
+ (E(find_maps)): Avoid use alloca, use default read file operations
+ instead of explicit LFS names, and fix infinite loop.
+ * elf/pldd.c: Explicit set _FILE_OFFSET_BITS, cleanup headers.
+ (get_process_info): Use _Static_assert instead of assert, use default
+ directory operations instead of explicit LFS names, and free some
+ leadek pointers.
+ * elf/tst-pldd.c: New file.
+
2019-04-17 Adhemerval Zanella <adhemerval.zanella@linaro.org>
* support/Makefile (libsupport-routines): Add support_subprocess,
diff --git a/NEWS b/NEWS
index 117646df7b..b39a0ccf91 100644
--- a/NEWS
+++ b/NEWS
@@ -14,6 +14,7 @@ Major new features:
The following bugs are resolved with this release:
[16573] malloc: Set and reset all hooks for tracing
+ [18035] Fix pldd hang
[24155] x32 memcmp can treat positive length as 0 (if sign bit in RDX is set) (CVE-2019-7309)
[24164] Systemtap probes need to use "nr" constraint on 32-bit Arm
[24161] __run_fork_handlers self-deadlocks in malloc/tst-mallocfork2
diff --git a/elf/Makefile b/elf/Makefile
index 9cf5cd8dfd..e7457e809f 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -194,6 +194,7 @@ tests-internal += loadtest unload unload2 circleload1 \
tst-tls3 tst-tls6 tst-tls7 tst-tls8 tst-dlmopen2 \
tst-ptrguard1 tst-stackguard1 tst-libc_dlvsym \
tst-create_format1
+tests-container += tst-pldd
ifeq ($(build-hardcoded-path-in-tests),yes)
tests += tst-dlopen-aout
tst-dlopen-aout-no-pie = yes
diff --git a/elf/pldd-xx.c b/elf/pldd-xx.c
index 547f840ee1..756f6d7a1c 100644
--- a/elf/pldd-xx.c
+++ b/elf/pldd-xx.c
@@ -23,10 +23,6 @@
#define EW_(e, w, t) EW__(e, w, _##t)
#define EW__(e, w, t) e##w##t
-#define pldd_assert(name, exp) \
- typedef int __assert_##name[((exp) != 0) - 1]
-
-
struct E(link_map)
{
EW(Addr) l_addr;
@@ -39,12 +35,12 @@ struct E(link_map)
EW(Addr) l_libname;
};
#if CLASS == __ELF_NATIVE_CLASS
-pldd_assert (l_addr, (offsetof (struct link_map, l_addr)
- == offsetof (struct E(link_map), l_addr)));
-pldd_assert (l_name, (offsetof (struct link_map, l_name)
- == offsetof (struct E(link_map), l_name)));
-pldd_assert (l_next, (offsetof (struct link_map, l_next)
- == offsetof (struct E(link_map), l_next)));
+_Static_assert (offsetof (struct link_map, l_addr)
+ == offsetof (struct E(link_map), l_addr), "l_addr");
+_Static_assert (offsetof (struct link_map, l_name)
+ == offsetof (struct E(link_map), l_name), "l_name");
+_Static_assert (offsetof (struct link_map, l_next)
+ == offsetof (struct E(link_map), l_next), "l_next");
#endif
@@ -54,10 +50,10 @@ struct E(libname_list)
EW(Addr) next;
};
#if CLASS == __ELF_NATIVE_CLASS
-pldd_assert (name, (offsetof (struct libname_list, name)
- == offsetof (struct E(libname_list), name)));
-pldd_assert (next, (offsetof (struct libname_list, next)
- == offsetof (struct E(libname_list), next)));
+_Static_assert (offsetof (struct libname_list, name)
+ == offsetof (struct E(libname_list), name), "name");
+_Static_assert (offsetof (struct libname_list, next)
+ == offsetof (struct E(libname_list), next), "next");
#endif
struct E(r_debug)
@@ -69,16 +65,17 @@ struct E(r_debug)
EW(Addr) r_map;
};
#if CLASS == __ELF_NATIVE_CLASS
-pldd_assert (r_version, (offsetof (struct r_debug, r_version)
- == offsetof (struct E(r_debug), r_version)));
-pldd_assert (r_map, (offsetof (struct r_debug, r_map)
- == offsetof (struct E(r_debug), r_map)));
+_Static_assert (offsetof (struct r_debug, r_version)
+ == offsetof (struct E(r_debug), r_version), "r_version");
+_Static_assert (offsetof (struct r_debug, r_map)
+ == offsetof (struct E(r_debug), r_map), "r_map");
#endif
static int
-E(find_maps) (pid_t pid, void *auxv, size_t auxv_size)
+E(find_maps) (const char *exe, int memfd, pid_t pid, void *auxv,
+ size_t auxv_size)
{
EW(Addr) phdr = 0;
unsigned int phnum = 0;
@@ -104,12 +101,9 @@ E(find_maps) (pid_t pid, void *auxv, size_t auxv_size)
if (phdr == 0 || phnum == 0 || phent == 0)
error (EXIT_FAILURE, 0, gettext ("cannot find program header of process"));
- EW(Phdr) *p = alloca (phnum * phent);
- if (pread64 (memfd, p, phnum * phent, phdr) != phnum * phent)
- {
- error (0, 0, gettext ("cannot read program header"));
- return EXIT_FAILURE;
- }
+ EW(Phdr) *p = xmalloc (phnum * phent);
+ if (pread (memfd, p, phnum * phent, phdr) != phnum * phent)
+ error (EXIT_FAILURE, 0, gettext ("cannot read program header"));
/* Determine the load offset. We need this for interpreting the
other program header entries so we do this in a separate loop.
@@ -129,24 +123,18 @@ E(find_maps) (pid_t pid, void *auxv, size_t auxv_size)
if (p[i].p_type == PT_DYNAMIC)
{
EW(Dyn) *dyn = xmalloc (p[i].p_filesz);
- if (pread64 (memfd, dyn, p[i].p_filesz, offset + p[i].p_vaddr)
+ if (pread (memfd, dyn, p[i].p_filesz, offset + p[i].p_vaddr)
!= p[i].p_filesz)
- {
- error (0, 0, gettext ("cannot read dynamic section"));
- return EXIT_FAILURE;
- }
+ error (EXIT_FAILURE, 0, gettext ("cannot read dynamic section"));
/* Search for the DT_DEBUG entry. */
for (unsigned int j = 0; j < p[i].p_filesz / sizeof (EW(Dyn)); ++j)
if (dyn[j].d_tag == DT_DEBUG && dyn[j].d_un.d_ptr != 0)
{
struct E(r_debug) r;
- if (pread64 (memfd, &r, sizeof (r), dyn[j].d_un.d_ptr)
+ if (pread (memfd, &r, sizeof (r), dyn[j].d_un.d_ptr)
!= sizeof (r))
- {
- error (0, 0, gettext ("cannot read r_debug"));
- return EXIT_FAILURE;
- }
+ error (EXIT_FAILURE, 0, gettext ("cannot read r_debug"));
if (r.r_map != 0)
{
@@ -160,13 +148,10 @@ E(find_maps) (pid_t pid, void *auxv, size_t auxv_size)
}
else if (p[i].p_type == PT_INTERP)
{
- interp = alloca (p[i].p_filesz);
- if (pread64 (memfd, interp, p[i].p_filesz, offset + p[i].p_vaddr)
+ interp = xmalloc (p[i].p_filesz);
+ if (pread (memfd, interp, p[i].p_filesz, offset + p[i].p_vaddr)
!= p[i].p_filesz)
- {
- error (0, 0, gettext ("cannot read program interpreter"));
- return EXIT_FAILURE;
- }
+ error (EXIT_FAILURE, 0, gettext ("cannot read program interpreter"));
}
if (list == 0)
@@ -174,14 +159,16 @@ E(find_maps) (pid_t pid, void *auxv, size_t auxv_size)
if (interp == NULL)
{
// XXX check whether the executable itself is the loader
- return EXIT_FAILURE;
+ exit (EXIT_FAILURE);
}
// XXX perhaps try finding ld.so and _r_debug in it
-
- return EXIT_FAILURE;
+ exit (EXIT_FAILURE);
}
+ free (p);
+ free (interp);
+
/* Print the PID and program name first. */
printf ("%lu:\t%s\n", (unsigned long int) pid, exe);
@@ -192,47 +179,27 @@ E(find_maps) (pid_t pid, void *auxv, size_t auxv_size)
do
{
struct E(link_map) m;
- if (pread64 (memfd, &m, sizeof (m), list) != sizeof (m))
- {
- error (0, 0, gettext ("cannot read link map"));
- status = EXIT_FAILURE;
- goto out;
- }
+ if (pread (memfd, &m, sizeof (m), list) != sizeof (m))
+ error (EXIT_FAILURE, 0, gettext ("cannot read link map"));
EW(Addr) name_offset = m.l_name;
- again:
while (1)
{
- ssize_t n = pread64 (memfd, tmpbuf.data, tmpbuf.length, name_offset);
+ ssize_t n = pread (memfd, tmpbuf.data, tmpbuf.length, name_offset);
if (n == -1)
- {
- error (0, 0, gettext ("cannot read object name"));
- status = EXIT_FAILURE;
- goto out;
- }
+ error (EXIT_FAILURE, 0, gettext ("cannot read object name"));
if (memchr (tmpbuf.data, '\0', n) != NULL)
break;
if (!scratch_buffer_grow (&tmpbuf))
- {
- error (0, 0, gettext ("cannot allocate buffer for object name"));
- status = EXIT_FAILURE;
- goto out;
- }
+ error (EXIT_FAILURE, 0,
+ gettext ("cannot allocate buffer for object name"));
}
- if (((char *)tmpbuf.data)[0] == '\0' && name_offset == m.l_name
- && m.l_libname != 0)
- {
- /* Try the l_libname element. */
- struct E(libname_list) ln;
- if (pread64 (memfd, &ln, sizeof (ln), m.l_libname) == sizeof (ln))
- {
- name_offset = ln.name;
- goto again;
- }
- }
+ /* The m.l_name and m.l_libname.name for loader linkmap points to same
+ values (since BZ#387 fix). Trying to use l_libname name as the
+ shared object name might lead to an infinite loop (BZ#18035). */
/* Skip over the executable. */
if (((char *)tmpbuf.data)[0] != '\0')
@@ -242,7 +209,6 @@ E(find_maps) (pid_t pid, void *auxv, size_t auxv_size)
}
while (list != 0);
- out:
scratch_buffer_free (&tmpbuf);
return status;
}
diff --git a/elf/pldd.c b/elf/pldd.c
index f3fac4e487..69629bd5d2 100644
--- a/elf/pldd.c
+++ b/elf/pldd.c
@@ -17,23 +17,17 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
-#include <alloca.h>
+#define _FILE_OFFSET_BITS 64
+
#include <argp.h>
-#include <assert.h>
#include <dirent.h>
-#include <elf.h>
-#include <errno.h>
#include <error.h>
#include <fcntl.h>
#include <libintl.h>
-#include <link.h>
-#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
-#include <string.h>
#include <unistd.h>
#include <sys/ptrace.h>
-#include <sys/stat.h>
#include <sys/wait.h>
#include <scratch_buffer.h>
@@ -76,14 +70,9 @@ static struct argp argp =
options, parse_opt, args_doc, doc, NULL, more_help, NULL
};
-// File descriptor of /proc/*/mem file.
-static int memfd;
-
-/* Name of the executable */
-static char *exe;
/* Local functions. */
-static int get_process_info (int dfd, long int pid);
+static int get_process_info (const char *exe, int dfd, long int pid);
static void wait_for_ptrace_stop (long int pid);
@@ -102,8 +91,10 @@ main (int argc, char *argv[])
return 1;
}
- assert (sizeof (pid_t) == sizeof (int)
- || sizeof (pid_t) == sizeof (long int));
+ _Static_assert (sizeof (pid_t) == sizeof (int)
+ || sizeof (pid_t) == sizeof (long int),
+ "sizeof (pid_t) != sizeof (int) or sizeof (long int)");
+
char *endp;
errno = 0;
long int pid = strtol (argv[remaining], &endp, 10);
@@ -119,25 +110,24 @@ main (int argc, char *argv[])
if (dfd == -1)
error (EXIT_FAILURE, errno, gettext ("cannot open %s"), buf);
- struct scratch_buffer exebuf;
- scratch_buffer_init (&exebuf);
+ /* Name of the executable */
+ struct scratch_buffer exe;
+ scratch_buffer_init (&exe);
ssize_t nexe;
while ((nexe = readlinkat (dfd, "exe",
- exebuf.data, exebuf.length)) == exebuf.length)
+ exe.data, exe.length)) == exe.length)
{
- if (!scratch_buffer_grow (&exebuf))
+ if (!scratch_buffer_grow (&exe))
{
nexe = -1;
break;
}
}
if (nexe == -1)
- exe = (char *) "<program name undetermined>";
+ /* Default stack allocation is at least 1024. */
+ snprintf (exe.data, exe.length, "<program name undetermined>");
else
- {
- exe = exebuf.data;
- exe[nexe] = '\0';
- }
+ ((char*)exe.data)[nexe] = '\0';
/* Stop all threads since otherwise the list of loaded modules might
change while we are reading it. */
@@ -155,8 +145,8 @@ main (int argc, char *argv[])
error (EXIT_FAILURE, errno, gettext ("cannot prepare reading %s/task"),
buf);
- struct dirent64 *d;
- while ((d = readdir64 (dir)) != NULL)
+ struct dirent *d;
+ while ((d = readdir (dir)) != NULL)
{
if (! isdigit (d->d_name[0]))
continue;
@@ -182,7 +172,7 @@ main (int argc, char *argv[])
wait_for_ptrace_stop (tid);
- struct thread_list *newp = alloca (sizeof (*newp));
+ struct thread_list *newp = xmalloc (sizeof (*newp));
newp->tid = tid;
newp->next = thread_list;
thread_list = newp;
@@ -190,17 +180,22 @@ main (int argc, char *argv[])
closedir (dir);
- int status = get_process_info (dfd, pid);
+ if (thread_list == NULL)
+ error (EXIT_FAILURE, 0, gettext ("no valid %s/task entries"), buf);
+
+ int status = get_process_info (exe.data, dfd, pid);
- assert (thread_list != NULL);
do
{
ptrace (PTRACE_DETACH, thread_list->tid, NULL, NULL);
+ struct thread_list *prev = thread_list;
thread_list = thread_list->next;
+ free (prev);
}
while (thread_list != NULL);
close (dfd);
+ scratch_buffer_free (&exe);
return status;
}
@@ -281,9 +276,10 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
static int
-get_process_info (int dfd, long int pid)
+get_process_info (const char *exe, int dfd, long int pid)
{
- memfd = openat (dfd, "mem", O_RDONLY);
+ /* File descriptor of /proc/<pid>/mem file. */
+ int memfd = openat (dfd, "mem", O_RDONLY);
if (memfd == -1)
goto no_info;
@@ -333,9 +329,9 @@ get_process_info (int dfd, long int pid)
int retval;
if (e_ident[EI_CLASS] == ELFCLASS32)
- retval = find_maps32 (pid, auxv, auxv_size);
+ retval = find_maps32 (exe, memfd, pid, auxv, auxv_size);
else
- retval = find_maps64 (pid, auxv, auxv_size);
+ retval = find_maps64 (exe, memfd, pid, auxv, auxv_size);
free (auxv);
close (memfd);
diff --git a/elf/tst-pldd.c b/elf/tst-pldd.c
new file mode 100644
index 0000000000..ed19cedd05
--- /dev/null
+++ b/elf/tst-pldd.c
@@ -0,0 +1,118 @@
+/* Basic tests for pldd program.
+ Copyright (C) 2019 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <libgen.h>
+#include <stdbool.h>
+
+#include <array_length.h>
+#include <gnu/lib-names.h>
+
+#include <support/subprocess.h>
+#include <support/capture_subprocess.h>
+#include <support/check.h>
+
+static void
+target_process (void *arg)
+{
+ pause ();
+}
+
+/* The test runs in a container because pldd does not support tracing
+ a binary started by the loader iself (as with testrun.sh). */
+
+static int
+do_test (void)
+{
+ /* Create a copy of current test to check with pldd. */
+ struct support_subprocess target = support_subprocess (target_process, NULL);
+
+ /* Run 'pldd' on test subprocess. */
+ struct support_capture_subprocess pldd;
+ {
+ /* Three digits per byte plus null terminator. */
+ char pid[3 * sizeof (uint32_t) + 1];
+ snprintf (pid, array_length (pid), "%d", target.pid);
+
+ const char prog[] = "/usr/bin/pldd";
+
+ pldd = support_capture_subprogram (prog,
+ (char *const []) { (char *) prog, pid, NULL });
+
+ support_capture_subprocess_check (&pldd, "pldd", 0, sc_allow_stdout);
+ }
+
+ /* Check 'pldd' output. The test is expected to be linked against only
+ loader and libc. */
+ {
+ pid_t pid;
+ char buffer[512];
+#define STRINPUT(size) "%" # size "s"
+
+ FILE *out = fmemopen (pldd.out.buffer, pldd.out.length, "r");
+ TEST_VERIFY (out != NULL);
+
+ /* First line is in the form of <pid>: <full path of executable> */
+ TEST_COMPARE (fscanf (out, "%u: " STRINPUT (512), &pid, buffer), 2);
+
+ TEST_COMPARE (pid, target.pid);
+ TEST_COMPARE (strcmp (basename (buffer), "tst-pldd"), 0);
+
+ /* It expects only one loader and libc loaded by the program. */
+ bool interpreter_found = false, libc_found = false;
+ while (fgets (buffer, array_length (buffer), out) != NULL)
+ {
+ /* Ignore vDSO. */
+ if (buffer[0] != '/')
+ continue;
+
+ /* Remove newline so baseline (buffer) can compare against the
+ LD_SO and LIBC_SO macros unmodified. */
+ if (buffer[strlen(buffer)-1] == '\n')
+ buffer[strlen(buffer)-1] = '\0';
+
+ if (strcmp (basename (buffer), LD_SO) == 0)
+ {
+ TEST_COMPARE (interpreter_found, false);
+ interpreter_found = true;
+ continue;
+ }
+
+ if (strcmp (basename (buffer), LIBC_SO) == 0)
+ {
+ TEST_COMPARE (libc_found, false);
+ libc_found = true;
+ continue;
+ }
+ }
+ TEST_COMPARE (interpreter_found, true);
+ TEST_COMPARE (libc_found, true);
+
+ fclose (out);
+ }
+
+ support_capture_subprocess_free (&pldd);
+ support_process_terminate (&target);
+
+ return 0;
+}
+
+#include <support/test-driver.c>

View file

@ -1,37 +0,0 @@
From 52b7cd6e9a701bb203023d56e84551943dc6a4c0 Mon Sep 17 00:00:00 2001
From: Adam Maris <amaris@redhat.com>
Date: Thu, 14 Mar 2019 16:51:16 -0400
Subject: [PATCH 18] malloc: Check for large bin list corruption when
inserting unsorted chunk
Fixes bug 24216. This patch adds security checks for bk and bk_nextsize pointers
of chunks in large bin when inserting chunk from unsorted bin. It was possible
to write the pointer to victim (newly inserted chunk) to arbitrary memory
locations if bk or bk_nextsize pointers of the next large bin chunk
got corrupted.
(cherry picked from commit 5b06f538c5aee0389ed034f60d90a8884d6d54de)
---
malloc/malloc.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/malloc/malloc.c b/malloc/malloc.c
index feaf7ee0bf..ce771375b6 100644
--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -3876,10 +3876,14 @@ _int_malloc (mstate av, size_t bytes)
{
victim->fd_nextsize = fwd;
victim->bk_nextsize = fwd->bk_nextsize;
+ if (__glibc_unlikely (fwd->bk_nextsize->fd_nextsize != fwd))
+ malloc_printerr ("malloc(): largebin double linked list corrupted (nextsize)");
fwd->bk_nextsize = victim;
victim->bk_nextsize->fd_nextsize = victim;
}
bck = fwd->bk;
+ if (bck->fd != fwd)
+ malloc_printerr ("malloc(): largebin double linked list corrupted (bk)");
}
}
else

View file

@ -1,144 +0,0 @@
From c6177be4b92d5d7df50a785652d1912db511423e Mon Sep 17 00:00:00 2001
From: Andreas Schwab <schwab@suse.de>
Date: Wed, 15 May 2019 17:09:05 +0200
Subject: [PATCH 19] Fix crash in _IO_wfile_sync (bug 20568)
When computing the length of the converted part of the stdio buffer, use
the number of consumed wide characters, not the (negative) distance to the
end of the wide buffer.
(cherry picked from commit 32ff397533715988c19cbf3675dcbd727ec13e18)
---
ChangeLog | 10 ++++++++++
NEWS | 1 +
libio/Makefile | 3 ++-
libio/tst-wfile-sync.c | 39 ++++++++++++++++++++++++++++++++++++++
libio/tst-wfile-sync.input | 1 +
libio/wfileops.c | 5 +++--
6 files changed, 56 insertions(+), 3 deletions(-)
create mode 100644 libio/tst-wfile-sync.c
create mode 100644 libio/tst-wfile-sync.input
diff --git a/ChangeLog b/ChangeLog
index 5af8e27ab9..d3fcf73e47 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2019-05-15 Andreas Schwab <schwab@suse.de>
+
+ [BZ #20568]
+ * libio/wfileops.c (_IO_wfile_sync): Correct last argument to
+ __codecvt_do_length.
+ * libio/Makefile (tests): Add tst-wfile-sync.
+ ($(objpfx)tst-wfile-sync.out): Depend on $(gen-locales).
+ * libio/tst-wfile-sync.c: New file.
+ * libio/tst-wfile-sync.input: New file.
+
2019-04-23 Adhemerval Zanella <adhemerval.zanella@linaro.org>
[BZ #18035]
diff --git a/NEWS b/NEWS
index b39a0ccf91..c10ab5e851 100644
--- a/NEWS
+++ b/NEWS
@@ -15,6 +15,7 @@ The following bugs are resolved with this release:
[16573] malloc: Set and reset all hooks for tracing
[18035] Fix pldd hang
+ [20568] Fix crash in _IO_wfile_sync
[24155] x32 memcmp can treat positive length as 0 (if sign bit in RDX is set) (CVE-2019-7309)
[24164] Systemtap probes need to use "nr" constraint on 32-bit Arm
[24161] __run_fork_handlers self-deadlocks in malloc/tst-mallocfork2
diff --git a/libio/Makefile b/libio/Makefile
index 5bee83e55c..ee3a34cc3b 100644
--- a/libio/Makefile
+++ b/libio/Makefile
@@ -65,7 +65,7 @@ tests = tst_swprintf tst_wprintf tst_swscanf tst_wscanf tst_getwc tst_putwc \
tst-setvbuf1 tst-popen1 tst-fgetwc bug-wsetpos tst-fseek \
tst-fwrite-error tst-ftell-partial-wide tst-ftell-active-handler \
tst-ftell-append tst-fputws tst-bz22415 tst-fgetc-after-eof \
- tst-sprintf-ub tst-sprintf-chk-ub
+ tst-sprintf-ub tst-sprintf-chk-ub tst-wfile-sync
tests-internal = tst-vtables tst-vtables-interposed tst-readline
@@ -212,6 +212,7 @@ $(objpfx)tst-ungetwc1.out: $(gen-locales)
$(objpfx)tst-ungetwc2.out: $(gen-locales)
$(objpfx)tst-widetext.out: $(gen-locales)
$(objpfx)tst_wprintf2.out: $(gen-locales)
+$(objpfx)tst-wfile-sync.out: $(gen-locales)
endif
$(objpfx)test-freopen.out: test-freopen.sh $(objpfx)test-freopen
diff --git a/libio/tst-wfile-sync.c b/libio/tst-wfile-sync.c
new file mode 100644
index 0000000000..618682064d
--- /dev/null
+++ b/libio/tst-wfile-sync.c
@@ -0,0 +1,39 @@
+/* Test that _IO_wfile_sync does not crash (bug 20568).
+ Copyright (C) 2019 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <locale.h>
+#include <stdio.h>
+#include <wchar.h>
+#include <support/check.h>
+#include <support/xunistd.h>
+
+static int
+do_test (void)
+{
+ TEST_VERIFY_EXIT (setlocale (LC_ALL, "de_DE.UTF-8") != NULL);
+ /* Fill the stdio buffer and advance the read pointer. */
+ TEST_VERIFY_EXIT (fgetwc (stdin) != WEOF);
+ /* This calls _IO_wfile_sync, it should not crash. */
+ TEST_VERIFY_EXIT (setvbuf (stdin, NULL, _IONBF, 0) == 0);
+ /* Verify that the external file offset has been synchronized. */
+ TEST_COMPARE (xlseek (0, 0, SEEK_CUR), 1);
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/libio/tst-wfile-sync.input b/libio/tst-wfile-sync.input
new file mode 100644
index 0000000000..12d0958f7a
--- /dev/null
+++ b/libio/tst-wfile-sync.input
@@ -0,0 +1 @@
+This is a test of _IO_wfile_sync.
diff --git a/libio/wfileops.c b/libio/wfileops.c
index 78f20486e5..bab2ba4892 100644
--- a/libio/wfileops.c
+++ b/libio/wfileops.c
@@ -508,11 +508,12 @@ _IO_wfile_sync (FILE *fp)
generate the wide characters up to the current reading
position. */
int nread;
-
+ size_t wnread = (fp->_wide_data->_IO_read_ptr
+ - fp->_wide_data->_IO_read_base);
fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;
nread = (*cv->__codecvt_do_length) (cv, &fp->_wide_data->_IO_state,
fp->_IO_read_base,
- fp->_IO_read_end, delta);
+ fp->_IO_read_end, wnread);
fp->_IO_read_ptr = fp->_IO_read_base + nread;
delta = -(fp->_IO_read_end - fp->_IO_read_base - nread);
}

View file

@ -1,93 +0,0 @@
From e3f828b8bd6e21922da8be8dee35edef09382d8d Mon Sep 17 00:00:00 2001
From: Mark Wielaard <mark@klomp.org>
Date: Wed, 15 May 2019 17:14:01 +0200
Subject: [PATCH 20] dlfcn: Guard __dlerror_main_freeres with
__libc_once_get (once) [BZ#24476]
dlerror.c (__dlerror_main_freeres) will try to free resources which only
have been initialized when init () has been called. That function is
called when resources are needed using __libc_once (once, init) where
once is a __libc_once_define (static, once) in the dlerror.c file.
Trying to free those resources if init () hasn't been called will
produce errors under valgrind memcheck. So guard the freeing of those
resources using __libc_once_get (once) and make sure we have a valid
key. Also add a similar guard to __dlerror ().
* dlfcn/dlerror.c (__dlerror_main_freeres): Guard using
__libc_once_get (once) and static_bug == NULL.
(__dlerror): Check we have a valid key, set result to static_buf
otherwise.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
(cherry picked from commit 11b451c8868d8a2b0edc5dfd44fc58d9ee538be0)
---
ChangeLog | 8 ++++++++
dlfcn/dlerror.c | 29 +++++++++++++++++++++--------
2 files changed, 29 insertions(+), 8 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index d3fcf73e47..de8c5c214d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2019-05-15 Mark Wielaard <mark@klomp.org>
+
+ [BZ#24476]
+ * dlfcn/dlerror.c (__dlerror_main_freeres): Guard using
+ __libc_once_get (once) and static_buf == NULL.
+ (__dlerror): Check we have a valid key, set result to static_buf
+ otherwise.
+
2019-05-15 Andreas Schwab <schwab@suse.de>
[BZ #20568]
diff --git a/dlfcn/dlerror.c b/dlfcn/dlerror.c
index 27376582d0..ca42c126c1 100644
--- a/dlfcn/dlerror.c
+++ b/dlfcn/dlerror.c
@@ -72,9 +72,16 @@ __dlerror (void)
__libc_once (once, init);
/* Get error string. */
- result = (struct dl_action_result *) __libc_getspecific (key);
- if (result == NULL)
- result = &last_result;
+ if (static_buf != NULL)
+ result = static_buf;
+ else
+ {
+ /* init () has been run and we don't use the static buffer.
+ So we have a valid key. */
+ result = (struct dl_action_result *) __libc_getspecific (key);
+ if (result == NULL)
+ result = &last_result;
+ }
/* Test whether we already returned the string. */
if (result->returned != 0)
@@ -230,13 +237,19 @@ free_key_mem (void *mem)
void
__dlerror_main_freeres (void)
{
- void *mem;
/* Free the global memory if used. */
check_free (&last_result);
- /* Free the TSD memory if used. */
- mem = __libc_getspecific (key);
- if (mem != NULL)
- free_key_mem (mem);
+
+ if (__libc_once_get (once) && static_buf == NULL)
+ {
+ /* init () has been run and we don't use the static buffer.
+ So we have a valid key. */
+ void *mem;
+ /* Free the TSD memory if used. */
+ mem = __libc_getspecific (key);
+ if (mem != NULL)
+ free_key_mem (mem);
+ }
}
struct dlfcn_hook *_dlfcn_hook __attribute__((nocommon));

View file

@ -1,22 +0,0 @@
From 980cb43f15c4320afc6272e7a508f1415413b945 Mon Sep 17 00:00:00 2001
From: Mark Wielaard <mark@klomp.org>
Date: Thu, 16 May 2019 15:25:40 +0200
Subject: [PATCH 21] Update NEWS for BZ#24476 Guard __dlerror_main_freeres.
---
NEWS | 1 +
1 file changed, 1 insertion(+)
diff --git a/NEWS b/NEWS
index c10ab5e851..17dcaa7b74 100644
--- a/NEWS
+++ b/NEWS
@@ -20,6 +20,7 @@ The following bugs are resolved with this release:
[24164] Systemtap probes need to use "nr" constraint on 32-bit Arm
[24161] __run_fork_handlers self-deadlocks in malloc/tst-mallocfork2
[24211] Use-after-free in Systemtap probe in pthread_join
+ [24476] dlfcn: Guard __dlerror_main_freeres with __libc_once_get (once)
Security related changes:

View file

@ -1,79 +0,0 @@
From 95d66fecaabbc92ab53027e808f0fc1929c9f21a Mon Sep 17 00:00:00 2001
From: Wilco Dijkstra <wdijkstr@arm.com>
Date: Fri, 10 May 2019 16:38:21 +0100
Subject: [PATCH 22] Fix tcache count maximum (BZ #24531)
The tcache counts[] array is a char, which has a very small range and thus
may overflow. When setting tcache_count tunable, there is no overflow check.
However the tunable must not be larger than the maximum value of the tcache
counts[] array, otherwise it can overflow when filling the tcache.
[BZ #24531]
* malloc/malloc.c (MAX_TCACHE_COUNT): New define.
(do_set_tcache_count): Only update if count is small enough.
* manual/tunables.texi (glibc.malloc.tcache_count): Document max value.
(cherry picked from commit 5ad533e8e65092be962e414e0417112c65d154fb)
---
ChangeLog | 7 +++++++
malloc/malloc.c | 9 +++++++--
manual/tunables.texi | 4 ++--
3 files changed, 16 insertions(+), 4 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index de8c5c214d..f4586d34a3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2019-05-22 Wilco Dijkstra <wdijkstr@arm.com>
+
+ [BZ #24531]
+ * malloc/malloc.c (MAX_TCACHE_COUNT): New define.
+ (do_set_tcache_count): Only update if count is small enough.
+ * manual/tunables.texi (glibc.malloc.tcache_count): Document max value.
+
2019-05-15 Mark Wielaard <mark@klomp.org>
[BZ#24476]
diff --git a/malloc/malloc.c b/malloc/malloc.c
index ce771375b6..0abd653be2 100644
--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -2919,6 +2919,8 @@ typedef struct tcache_perthread_struct
tcache_entry *entries[TCACHE_MAX_BINS];
} tcache_perthread_struct;
+#define MAX_TCACHE_COUNT 127 /* Maximum value of counts[] entries. */
+
static __thread bool tcache_shutting_down = false;
static __thread tcache_perthread_struct *tcache = NULL;
@@ -5124,8 +5126,11 @@ static inline int
__always_inline
do_set_tcache_count (size_t value)
{
- LIBC_PROBE (memory_tunable_tcache_count, 2, value, mp_.tcache_count);
- mp_.tcache_count = value;
+ if (value <= MAX_TCACHE_COUNT)
+ {
+ LIBC_PROBE (memory_tunable_tcache_count, 2, value, mp_.tcache_count);
+ mp_.tcache_count = value;
+ }
return 1;
}
diff --git a/manual/tunables.texi b/manual/tunables.texi
index af820820e0..8edfea4edd 100644
--- a/manual/tunables.texi
+++ b/manual/tunables.texi
@@ -189,8 +189,8 @@ per-thread cache. The default (and maximum) value is 1032 bytes on
@deftp Tunable glibc.malloc.tcache_count
The maximum number of chunks of each size to cache. The default is 7.
-There is no upper limit, other than available system memory. If set
-to zero, the per-thread cache is effectively disabled.
+The upper limit is 127. If set to zero, the per-thread cache is effectively
+disabled.
The approximate maximum overhead of the per-thread cache is thus equal
to the number of bins times the chunk count in each bin times the size

View file

@ -1,14 +1,14 @@
# Template file for 'glibc'
pkgname=glibc
version=2.29
revision=6
version=2.30
revision=1
bootstrap=yes
short_desc="GNU C library"
maintainer="Juan RP <xtraeme@voidlinux.org>"
license="GPL-2.0-or-later, LGPL-2.1-or-later, BSD-3-Clause"
homepage="http://www.gnu.org/software/libc"
distfiles="${GNU_SITE}/glibc/glibc-${version}.tar.xz"
checksum=f3eeb8d57e25ca9fc13c2af3dae97754f9f643bc69229546828e3a240e2af04b
checksum=e2c4114e569afbe7edbc29131a43be833850ab9a459d81beb2588016d2bbb8af
patch_args="-Np1"
# Do not strip these files, objcopy errors out.
nostrip_files="