1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/synchronization/lock_impl.h"
6 
7 #include <string.h>
8 
9 #include "base/debug/activity_tracker.h"
10 #include "base/synchronization/lock.h"
11 
12 namespace base {
13 namespace internal {
14 
15 // Determines which platforms can consider using priority inheritance locks. Use
16 // this define for platform code that may not compile if priority inheritance
17 // locks aren't available. For this platform code,
18 // PRIORITY_INHERITANCE_LOCKS_POSSIBLE() is a necessary but insufficient check.
19 // Lock::PriorityInheritanceAvailable still must be checked as the code may
20 // compile but the underlying platform still may not correctly support priority
21 // inheritance locks.
22 #if defined(OS_NACL) || defined(OS_ANDROID)
23 #define PRIORITY_INHERITANCE_LOCKS_POSSIBLE() 0
24 #else
25 #define PRIORITY_INHERITANCE_LOCKS_POSSIBLE() 1
26 #endif
27 
LockImpl()28 LockImpl::LockImpl() {
29   pthread_mutexattr_t mta;
30   int rv = pthread_mutexattr_init(&mta);
31   DCHECK_EQ(rv, 0) << ". " << strerror(rv);
32 #if PRIORITY_INHERITANCE_LOCKS_POSSIBLE()
33   if (PriorityInheritanceAvailable()) {
34     rv = pthread_mutexattr_setprotocol(&mta, PTHREAD_PRIO_INHERIT);
35     DCHECK_EQ(rv, 0) << ". " << strerror(rv);
36   }
37 #endif
38 #ifndef NDEBUG
39   // In debug, setup attributes for lock error checking.
40   rv = pthread_mutexattr_settype(&mta, PTHREAD_MUTEX_ERRORCHECK);
41   DCHECK_EQ(rv, 0) << ". " << strerror(rv);
42 #endif
43   rv = pthread_mutex_init(&native_handle_, &mta);
44   DCHECK_EQ(rv, 0) << ". " << strerror(rv);
45   rv = pthread_mutexattr_destroy(&mta);
46   DCHECK_EQ(rv, 0) << ". " << strerror(rv);
47 }
48 
~LockImpl()49 LockImpl::~LockImpl() {
50   int rv = pthread_mutex_destroy(&native_handle_);
51   DCHECK_EQ(rv, 0) << ". " << strerror(rv);
52 }
53 
Try()54 bool LockImpl::Try() {
55   int rv = pthread_mutex_trylock(&native_handle_);
56   DCHECK(rv == 0 || rv == EBUSY) << ". " << strerror(rv);
57   return rv == 0;
58 }
59 
Lock()60 void LockImpl::Lock() {
61   base::debug::ScopedLockAcquireActivity lock_activity(this);
62   int rv = pthread_mutex_lock(&native_handle_);
63   DCHECK_EQ(rv, 0) << ". " << strerror(rv);
64 }
65 
66 // static
PriorityInheritanceAvailable()67 bool LockImpl::PriorityInheritanceAvailable() {
68 #if PRIORITY_INHERITANCE_LOCKS_POSSIBLE() && defined(OS_MACOSX)
69   return true;
70 #else
71   // Security concerns prevent the use of priority inheritance mutexes on Linux.
72   //   * CVE-2010-0622 - wake_futex_pi unlocks incorrect, possible DoS.
73   //     https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-0622
74   //   * CVE-2012-6647 - Linux < 3.5.1, futex_wait_requeue_pi possible DoS.
75   //     https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2012-6647
76   //   * CVE-2014-3153 - Linux <= 3.14.5, futex_requeue, privilege escalation.
77   //     https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-3153
78   //
79   // If the above were all addressed, we still need a runtime check to deal with
80   // the bug below.
81   //   * glibc Bug 14652: https://sourceware.org/bugzilla/show_bug.cgi?id=14652
82   //     Fixed in glibc 2.17.
83   //     Priority inheritance mutexes may deadlock with condition variables
84   //     during recacquisition of the mutex after the condition variable is
85   //     signalled.
86   return false;
87 #endif
88 }
89 
90 }  // namespace internal
91 }  // namespace base
92