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>
8
9 #include "base/debug/activity_tracker.h"
10 #include "base/logging.h"
11 #include "base/posix/safe_strerror.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/synchronization/lock.h"
14 #include "base/synchronization/synchronization_buildflags.h"
15 #include "build/build_config.h"
16
17 namespace base {
18 namespace internal {
19
20 namespace {
21
22 #if DCHECK_IS_ON()
AdditionalHintForSystemErrorCode(int error_code)23 const char* AdditionalHintForSystemErrorCode(int error_code) {
24 switch (error_code) {
25 case EINVAL:
26 return "Hint: This is often related to a use-after-free.";
27 default:
28 return "";
29 }
30 }
31 #endif // DCHECK_IS_ON()
32
SystemErrorCodeToString(int error_code)33 std::string SystemErrorCodeToString(int error_code) {
34 #if DCHECK_IS_ON()
35 return base::safe_strerror(error_code) + ". " +
36 AdditionalHintForSystemErrorCode(error_code);
37 #else // DCHECK_IS_ON()
38 return std::string();
39 #endif // DCHECK_IS_ON()
40 }
41
42 } // namespace
43
44 // Determines which platforms can consider using priority inheritance locks. Use
45 // this define for platform code that may not compile if priority inheritance
46 // locks aren't available. For this platform code,
47 // PRIORITY_INHERITANCE_LOCKS_POSSIBLE() is a necessary but insufficient check.
48 // Lock::PriorityInheritanceAvailable still must be checked as the code may
49 // compile but the underlying platform still may not correctly support priority
50 // inheritance locks.
51 #if defined(OS_NACL) || defined(OS_ANDROID) || defined(OS_FUCHSIA)
52 #define PRIORITY_INHERITANCE_LOCKS_POSSIBLE() 0
53 #else
54 #define PRIORITY_INHERITANCE_LOCKS_POSSIBLE() 1
55 #endif
56
LockImpl()57 LockImpl::LockImpl() {
58 pthread_mutexattr_t mta;
59 int rv = pthread_mutexattr_init(&mta);
60 DCHECK_EQ(rv, 0) << ". " << SystemErrorCodeToString(rv);
61 #if PRIORITY_INHERITANCE_LOCKS_POSSIBLE()
62 if (PriorityInheritanceAvailable()) {
63 rv = pthread_mutexattr_setprotocol(&mta, PTHREAD_PRIO_INHERIT);
64 DCHECK_EQ(rv, 0) << ". " << SystemErrorCodeToString(rv);
65 }
66 #endif
67 #ifndef NDEBUG
68 // In debug, setup attributes for lock error checking.
69 rv = pthread_mutexattr_settype(&mta, PTHREAD_MUTEX_ERRORCHECK);
70 DCHECK_EQ(rv, 0) << ". " << SystemErrorCodeToString(rv);
71 #endif
72 rv = pthread_mutex_init(&native_handle_, &mta);
73 DCHECK_EQ(rv, 0) << ". " << SystemErrorCodeToString(rv);
74 rv = pthread_mutexattr_destroy(&mta);
75 DCHECK_EQ(rv, 0) << ". " << SystemErrorCodeToString(rv);
76 }
77
~LockImpl()78 LockImpl::~LockImpl() {
79 int rv = pthread_mutex_destroy(&native_handle_);
80 DCHECK_EQ(rv, 0) << ". " << SystemErrorCodeToString(rv);
81 }
82
Try()83 bool LockImpl::Try() {
84 int rv = pthread_mutex_trylock(&native_handle_);
85 DCHECK(rv == 0 || rv == EBUSY) << ". " << SystemErrorCodeToString(rv);
86 return rv == 0;
87 }
88
Lock()89 void LockImpl::Lock() {
90 // The ScopedLockAcquireActivity below is relatively expensive and so its
91 // actions can become significant due to the very large number of locks
92 // that tend to be used throughout the build. To avoid this cost in the
93 // vast majority of the calls, simply "try" the lock first and only do the
94 // (tracked) blocking call if that fails. Since "try" itself is a system
95 // call, and thus also somewhat expensive, don't bother with it unless
96 // tracking is actually enabled.
97 if (base::debug::GlobalActivityTracker::IsEnabled())
98 if (Try())
99 return;
100
101 base::debug::ScopedLockAcquireActivity lock_activity(this);
102 int rv = pthread_mutex_lock(&native_handle_);
103 DCHECK_EQ(rv, 0) << ". " << SystemErrorCodeToString(rv);
104 }
105
106 // static
PriorityInheritanceAvailable()107 bool LockImpl::PriorityInheritanceAvailable() {
108 #if BUILDFLAG(ENABLE_MUTEX_PRIORITY_INHERITANCE)
109 return true;
110 #elif PRIORITY_INHERITANCE_LOCKS_POSSIBLE() && defined(OS_MACOSX)
111 return true;
112 #else
113 // Security concerns prevent the use of priority inheritance mutexes on Linux.
114 // * CVE-2010-0622 - Linux < 2.6.33-rc7, wake_futex_pi possible DoS.
115 // https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-0622
116 // * CVE-2012-6647 - Linux < 3.5.1, futex_wait_requeue_pi possible DoS.
117 // https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2012-6647
118 // * CVE-2014-3153 - Linux <= 3.14.5, futex_requeue, privilege escalation.
119 // https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-3153
120 //
121 // If the above were all addressed, we still need a runtime check to deal with
122 // the bug below.
123 // * glibc Bug 14652: https://sourceware.org/bugzilla/show_bug.cgi?id=14652
124 // Fixed in glibc 2.17.
125 // Priority inheritance mutexes may deadlock with condition variables
126 // during reacquisition of the mutex after the condition variable is
127 // signalled.
128 return false;
129 #endif
130 }
131
132 } // namespace internal
133 } // namespace base
134