1 // Copyright 2011 The Chromium Authors
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 <ostream>
8 #include <string>
9
10 #include "base/check_op.h"
11 #include "base/posix/safe_strerror.h"
12 #include "base/synchronization/lock.h"
13 #include "base/synchronization/synchronization_buildflags.h"
14 #include "build/build_config.h"
15
16 namespace base {
17 namespace internal {
18
19 namespace {
20
21 #if DCHECK_IS_ON()
AdditionalHintForSystemErrorCode(int error_code)22 const char* AdditionalHintForSystemErrorCode(int error_code) {
23 switch (error_code) {
24 case EINVAL:
25 return "Hint: This is often related to a use-after-free.";
26 default:
27 return "";
28 }
29 }
30 #endif // DCHECK_IS_ON()
31
SystemErrorCodeToString(int error_code)32 std::string SystemErrorCodeToString(int error_code) {
33 #if DCHECK_IS_ON()
34 return base::safe_strerror(error_code) + ". " +
35 AdditionalHintForSystemErrorCode(error_code);
36 #else // DCHECK_IS_ON()
37 return std::string();
38 #endif // DCHECK_IS_ON()
39 }
40
41 } // namespace
42
43 #if DCHECK_IS_ON()
44 // These are out-of-line so that the .h file doesn't have to include ostream.
dcheck_trylock_result(int rv)45 void dcheck_trylock_result(int rv) {
46 DCHECK(rv == 0 || rv == EBUSY)
47 << ". " << base::internal::SystemErrorCodeToString(rv);
48 }
49
dcheck_unlock_result(int rv)50 void dcheck_unlock_result(int rv) {
51 DCHECK_EQ(rv, 0) << ". " << strerror(rv);
52 }
53 #endif
54
55 // Determines which platforms can consider using priority inheritance locks. Use
56 // this define for platform code that may not compile if priority inheritance
57 // locks aren't available. For this platform code,
58 // PRIORITY_INHERITANCE_LOCKS_POSSIBLE() is a necessary but insufficient check.
59 // Lock::PriorityInheritanceAvailable still must be checked as the code may
60 // compile but the underlying platform still may not correctly support priority
61 // inheritance locks.
62 #if BUILDFLAG(IS_NACL) || BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_FUCHSIA)
63 #define PRIORITY_INHERITANCE_LOCKS_POSSIBLE() 0
64 #else
65 #define PRIORITY_INHERITANCE_LOCKS_POSSIBLE() 1
66 #endif
67
LockImpl()68 LockImpl::LockImpl() {
69 pthread_mutexattr_t mta;
70 int rv = pthread_mutexattr_init(&mta);
71 DCHECK_EQ(rv, 0) << ". " << SystemErrorCodeToString(rv);
72 #if PRIORITY_INHERITANCE_LOCKS_POSSIBLE()
73 if (PriorityInheritanceAvailable()) {
74 rv = pthread_mutexattr_setprotocol(&mta, PTHREAD_PRIO_INHERIT);
75 DCHECK_EQ(rv, 0) << ". " << SystemErrorCodeToString(rv);
76 }
77 #endif
78 #ifndef NDEBUG
79 // In debug, setup attributes for lock error checking.
80 rv = pthread_mutexattr_settype(&mta, PTHREAD_MUTEX_ERRORCHECK);
81 DCHECK_EQ(rv, 0) << ". " << SystemErrorCodeToString(rv);
82 #endif
83 rv = pthread_mutex_init(&native_handle_, &mta);
84 DCHECK_EQ(rv, 0) << ". " << SystemErrorCodeToString(rv);
85 rv = pthread_mutexattr_destroy(&mta);
86 DCHECK_EQ(rv, 0) << ". " << SystemErrorCodeToString(rv);
87 }
88
~LockImpl()89 LockImpl::~LockImpl() {
90 int rv = pthread_mutex_destroy(&native_handle_);
91 DCHECK_EQ(rv, 0) << ". " << SystemErrorCodeToString(rv);
92 }
93
LockInternal()94 void LockImpl::LockInternal() {
95 int rv = pthread_mutex_lock(&native_handle_);
96 DCHECK_EQ(rv, 0) << ". " << SystemErrorCodeToString(rv);
97 }
98
99 // static
PriorityInheritanceAvailable()100 bool LockImpl::PriorityInheritanceAvailable() {
101 #if BUILDFLAG(ENABLE_MUTEX_PRIORITY_INHERITANCE)
102 return true;
103 #elif PRIORITY_INHERITANCE_LOCKS_POSSIBLE() && BUILDFLAG(IS_APPLE)
104 return true;
105 #else
106 // Security concerns prevent the use of priority inheritance mutexes on Linux.
107 // * CVE-2010-0622 - Linux < 2.6.33-rc7, wake_futex_pi possible DoS.
108 // https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-0622
109 // * CVE-2012-6647 - Linux < 3.5.1, futex_wait_requeue_pi possible DoS.
110 // https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2012-6647
111 // * CVE-2014-3153 - Linux <= 3.14.5, futex_requeue, privilege escalation.
112 // https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-3153
113 //
114 // If the above were all addressed, we still need a runtime check to deal with
115 // the bug below.
116 // * glibc Bug 14652: https://sourceware.org/bugzilla/show_bug.cgi?id=14652
117 // Fixed in glibc 2.17.
118 // Priority inheritance mutexes may deadlock with condition variables
119 // during reacquisition of the mutex after the condition variable is
120 // signalled.
121 return false;
122 #endif
123 }
124
125 } // namespace internal
126 } // namespace base
127