lock_impl_posix.cc (4229B)
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() 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 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. 45 void dcheck_trylock_result(int rv) { 46 DCHECK(rv == 0 || rv == EBUSY) 47 << ". " << base::internal::SystemErrorCodeToString(rv); 48 } 49 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 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 89 LockImpl::~LockImpl() { 90 int rv = pthread_mutex_destroy(&native_handle_); 91 DCHECK_EQ(rv, 0) << ". " << SystemErrorCodeToString(rv); 92 } 93 94 void LockImpl::LockInternal() { 95 int rv = pthread_mutex_lock(&native_handle_); 96 DCHECK_EQ(rv, 0) << ". " << SystemErrorCodeToString(rv); 97 } 98 99 // static 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