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