From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 67296 invoked by alias); 28 Aug 2017 13:27:26 -0000 Mailing-List: contact libc-stable-help@sourceware.org; run by ezmlm Precedence: bulk List-Post: List-Help: List-Subscribe: List-Archive: Sender: libc-stable-owner@sourceware.org Received: (qmail 67278 invoked by uid 89); 28 Aug 2017 13:27:25 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Checked: by ClamAV 0.99.2 on sourceware.org X-Virus-Found: No X-Spam-SWARE-Status: No, score=-25.9 required=5.0 tests=BAYES_00,GIT_PATCH_0,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,KAM_LAZY_DOMAIN_SECURITY,RP_MATCHES_RCVD,SPF_HELO_PASS autolearn=ham version=3.3.2 spammy=locks, 11000, COMMITTED X-Spam-Status: No, score=-25.9 required=5.0 tests=BAYES_00,GIT_PATCH_0,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,KAM_LAZY_DOMAIN_SECURITY,RP_MATCHES_RCVD,SPF_HELO_PASS autolearn=ham version=3.3.2 X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on sourceware.org X-Spam-Level: X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Mon, 28 Aug 2017 13:27:23 +0000 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 9BB51C047B73 for ; Mon, 28 Aug 2017 13:27:22 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 9BB51C047B73 Authentication-Results: ext-mx07.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx07.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=fweimer@redhat.com Received: from oldenburg.str.redhat.com (ovpn-117-19.ams2.redhat.com [10.36.117.19]) by smtp.corp.redhat.com (Postfix) with ESMTP id 3FC5481E33 for ; Mon, 28 Aug 2017 13:27:22 +0000 (UTC) Received: by oldenburg.str.redhat.com (Postfix, from userid 1000) id 93F2C415D957D; Mon, 28 Aug 2017 15:27:21 +0200 (CEST) Date: Sun, 01 Jan 2017 00:00:00 -0000 To: libc-stable@sourceware.org Subject: [2.25 COMMITTED] mutex: Fix robust mutex lock acquire (Bug 21778) User-Agent: Heirloom mailx 12.5 7/5/10 MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Message-Id: <20170828132721.93F2C415D957D@oldenburg.str.redhat.com> From: fweimer@redhat.com (Florian Weimer) X-Scanned-By: MIMEDefang 2.79 on 10.5.11.14 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.31]); Mon, 28 Aug 2017 13:27:22 +0000 (UTC) X-IsSubscribed: yes X-SW-Source: 2017-08/txt/msg00044.txt.bz2 65810f0ef05e8c9e333f17a44e77808b163ca298 fixed a robust mutex bug but introduced BZ 21778: if the CAS used to try to acquire a lock fails, the expected value is not updated, which breaks other cases in the loce acquisition loop. The fix is to simply update the expected value with the value returned by the CAS, which ensures that behavior is as if the first case with the CAS never happened (if the CAS fails). This is a regression introduced in the last release. Tested on x86_64, i686, ppc64, ppc64le, s390x, aarch64, armv7hl. (cherry picked from commit 5920a4a624b1f4db310d1c44997b640e2a4653e5) 2017-07-29 Torvald Riegel Carlos O'Donell [BZ 21778] * nptl/pthread_mutex_timedlock.c (__pthread_mutex_timedlock): Update oldval if the CAS fails. * nptl/pthread_mutex_lock.c (__pthread_mutex_lock_full): Likewise. * nptl/tst-mutex7.c: Add comments explaining template test. (ROBUST, DELAY_NSEC, ROUNDS, N): New. (tf, do_test): Use them. * nptl/tst-mutex7robust.c: New file. * nptl/Makefile (tests): Add new test. diff --git a/NEWS b/NEWS index 6963f3374b..f7057710f1 100644 --- a/NEWS +++ b/NEWS @@ -24,6 +24,7 @@ The following bugs are resolved with this release: [21298] rwlock can deadlock on frequent reader/writer phase switching [21386] Assertion in fork for distinct parent PID is incorrect [21624] Unsafe alloca allows local attackers to alias stack and heap (CVE-2017-1000366) + [21778] Robust mutex may deadlock [21972] assert macro requires operator== (int) for its argument type Version 2.25 diff --git a/nptl/Makefile b/nptl/Makefile index 0cc287305f..24067768ed 100644 --- a/nptl/Makefile +++ b/nptl/Makefile @@ -224,6 +224,7 @@ tests = tst-typesizes \ tst-attr1 tst-attr2 tst-attr3 tst-default-attr \ tst-mutex1 tst-mutex2 tst-mutex3 tst-mutex4 tst-mutex5 tst-mutex6 \ tst-mutex7 tst-mutex8 tst-mutex9 tst-mutex5a tst-mutex7a \ + tst-mutex7robust \ tst-mutexpi1 tst-mutexpi2 tst-mutexpi3 tst-mutexpi4 tst-mutexpi5 \ tst-mutexpi5a tst-mutexpi6 tst-mutexpi7 tst-mutexpi7a tst-mutexpi8 \ tst-mutexpi9 \ diff --git a/nptl/pthread_mutex_lock.c b/nptl/pthread_mutex_lock.c index dc9ca4c476..4425927c30 100644 --- a/nptl/pthread_mutex_lock.c +++ b/nptl/pthread_mutex_lock.c @@ -197,11 +197,14 @@ __pthread_mutex_lock_full (pthread_mutex_t *mutex) { /* Try to acquire the lock through a CAS from 0 (not acquired) to our TID | assume_other_futex_waiters. */ - if (__glibc_likely ((oldval == 0) - && (atomic_compare_and_exchange_bool_acq - (&mutex->__data.__lock, - id | assume_other_futex_waiters, 0) == 0))) - break; + if (__glibc_likely (oldval == 0)) + { + oldval + = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock, + id | assume_other_futex_waiters, 0); + if (__glibc_likely (oldval == 0)) + break; + } if ((oldval & FUTEX_OWNER_DIED) != 0) { diff --git a/nptl/pthread_mutex_timedlock.c b/nptl/pthread_mutex_timedlock.c index a4beb7b0dc..dd88cc4ec9 100644 --- a/nptl/pthread_mutex_timedlock.c +++ b/nptl/pthread_mutex_timedlock.c @@ -154,11 +154,14 @@ pthread_mutex_timedlock (pthread_mutex_t *mutex, { /* Try to acquire the lock through a CAS from 0 (not acquired) to our TID | assume_other_futex_waiters. */ - if (__glibc_likely ((oldval == 0) - && (atomic_compare_and_exchange_bool_acq - (&mutex->__data.__lock, - id | assume_other_futex_waiters, 0) == 0))) - break; + if (__glibc_likely (oldval == 0)) + { + oldval + = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock, + id | assume_other_futex_waiters, 0); + if (__glibc_likely (oldval == 0)) + break; + } if ((oldval & FUTEX_OWNER_DIED) != 0) { diff --git a/nptl/tst-mutex7.c b/nptl/tst-mutex7.c index a11afdba5e..08fe251eeb 100644 --- a/nptl/tst-mutex7.c +++ b/nptl/tst-mutex7.c @@ -22,25 +22,41 @@ #include #include - +/* This test is a template for other tests to use. Other tests define + the following macros to change the behaviour of the template test. + The test is very simple, it configures N threads given the parameters + below and then proceeds to go through mutex lock and unlock + operations in each thread as described before for the thread + function. */ #ifndef TYPE # define TYPE PTHREAD_MUTEX_DEFAULT #endif - +#ifndef ROBUST +# define ROBUST PTHREAD_MUTEX_STALLED +#endif +#ifndef DELAY_NSEC +# define DELAY_NSEC 11000 +#endif +#ifndef ROUNDS +# define ROUNDS 1000 +#endif +#ifndef N +# define N 100 +#endif static pthread_mutex_t lock; - -#define ROUNDS 1000 -#define N 100 - - +/* Each thread locks and the subsequently unlocks the lock, yielding + the smallest critical section possible. After the unlock the thread + waits DELAY_NSEC nanoseconds before doing the lock and unlock again. + Every thread does this ROUNDS times. The lock and unlock are + checked for errors. */ static void * tf (void *arg) { int nr = (long int) arg; int cnt; - struct timespec ts = { .tv_sec = 0, .tv_nsec = 11000 }; + struct timespec ts = { .tv_sec = 0, .tv_nsec = DELAY_NSEC }; for (cnt = 0; cnt < ROUNDS; ++cnt) { @@ -56,13 +72,16 @@ tf (void *arg) return (void *) 1l; } - nanosleep (&ts, NULL); + if ((ts.tv_sec > 0) || (ts.tv_nsec > 0)) + nanosleep (&ts, NULL); } return NULL; } - +/* Setup and run N threads, where each thread does as described + in the above thread function. The threads are given a minimal 1MiB + stack since they don't do anything between the lock and unlock. */ static int do_test (void) { @@ -80,6 +99,12 @@ do_test (void) exit (1); } + if (pthread_mutexattr_setrobust (&a, ROBUST) != 0) + { + puts ("mutexattr_setrobust failed"); + exit (1); + } + #ifdef ENABLE_PI if (pthread_mutexattr_setprotocol (&a, PTHREAD_PRIO_INHERIT) != 0) { diff --git a/nptl/tst-mutex7robust.c b/nptl/tst-mutex7robust.c new file mode 100644 index 0000000000..8221a61d29 --- /dev/null +++ b/nptl/tst-mutex7robust.c @@ -0,0 +1,7 @@ +/* Bug 21778: Fix oversight in robust mutex lock acquisition. */ +#define TYPE PTHREAD_MUTEX_NORMAL +#define ROBUST PTHREAD_MUTEX_ROBUST +#define DELAY_NSEC 0 +#define ROUNDS 1000 +#define N 32 +#include "tst-mutex7.c"