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() 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 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 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 78 LockImpl::~LockImpl() { 79 int rv = pthread_mutex_destroy(&native_handle_); 80 DCHECK_EQ(rv, 0) << ". " << SystemErrorCodeToString(rv); 81 } 82 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 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 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