| // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #include "base/synchronization/lock_impl.h" | 
 |  | 
 | #include <string> | 
 |  | 
 | #include "base/logging.h" | 
 | #include "base/posix/safe_strerror.h" | 
 | #include "base/strings/stringprintf.h" | 
 | #include "base/synchronization/lock.h" | 
 | #include "build_config.h" | 
 |  | 
 | namespace base { | 
 | namespace internal { | 
 |  | 
 | namespace { | 
 |  | 
 | #if DCHECK_IS_ON() | 
 | const char* AdditionalHintForSystemErrorCode(int error_code) { | 
 |   switch (error_code) { | 
 |     case EINVAL: | 
 |       return "Hint: This is often related to a use-after-free."; | 
 |     default: | 
 |       return ""; | 
 |   } | 
 | } | 
 | #endif  // DCHECK_IS_ON() | 
 |  | 
 | std::string SystemErrorCodeToString(int error_code) { | 
 | #if DCHECK_IS_ON() | 
 |   return base::safe_strerror(error_code) + ". " + | 
 |          AdditionalHintForSystemErrorCode(error_code); | 
 | #else   // DCHECK_IS_ON() | 
 |   return std::string(); | 
 | #endif  // DCHECK_IS_ON() | 
 | } | 
 |  | 
 | }  // namespace | 
 |  | 
 | // Determines which platforms can consider using priority inheritance locks. Use | 
 | // this define for platform code that may not compile if priority inheritance | 
 | // locks aren't available. For this platform code, | 
 | // PRIORITY_INHERITANCE_LOCKS_POSSIBLE() is a necessary but insufficient check. | 
 | // Lock::PriorityInheritanceAvailable still must be checked as the code may | 
 | // compile but the underlying platform still may not correctly support priority | 
 | // inheritance locks. | 
 | #if defined(OS_NACL) || defined(OS_ANDROID) || defined(OS_FUCHSIA) | 
 | #define PRIORITY_INHERITANCE_LOCKS_POSSIBLE() 0 | 
 | #else | 
 | #define PRIORITY_INHERITANCE_LOCKS_POSSIBLE() 1 | 
 | #endif | 
 |  | 
 | LockImpl::LockImpl() { | 
 |   pthread_mutexattr_t mta; | 
 |   int rv = pthread_mutexattr_init(&mta); | 
 |   DCHECK_EQ(rv, 0) << ". " << SystemErrorCodeToString(rv); | 
 | #if PRIORITY_INHERITANCE_LOCKS_POSSIBLE() | 
 |   if (PriorityInheritanceAvailable()) { | 
 |     rv = pthread_mutexattr_setprotocol(&mta, PTHREAD_PRIO_INHERIT); | 
 |     DCHECK_EQ(rv, 0) << ". " << SystemErrorCodeToString(rv); | 
 |   } | 
 | #endif | 
 | #ifndef NDEBUG | 
 |   // In debug, setup attributes for lock error checking. | 
 |   rv = pthread_mutexattr_settype(&mta, PTHREAD_MUTEX_ERRORCHECK); | 
 |   DCHECK_EQ(rv, 0) << ". " << SystemErrorCodeToString(rv); | 
 | #endif | 
 |   rv = pthread_mutex_init(&native_handle_, &mta); | 
 |   DCHECK_EQ(rv, 0) << ". " << SystemErrorCodeToString(rv); | 
 |   rv = pthread_mutexattr_destroy(&mta); | 
 |   DCHECK_EQ(rv, 0) << ". " << SystemErrorCodeToString(rv); | 
 | } | 
 |  | 
 | LockImpl::~LockImpl() { | 
 |   int rv = pthread_mutex_destroy(&native_handle_); | 
 |   DCHECK_EQ(rv, 0) << ". " << SystemErrorCodeToString(rv); | 
 | } | 
 |  | 
 | bool LockImpl::Try() { | 
 |   int rv = pthread_mutex_trylock(&native_handle_); | 
 |   DCHECK(rv == 0 || rv == EBUSY) << ". " << SystemErrorCodeToString(rv); | 
 |   return rv == 0; | 
 | } | 
 |  | 
 | void LockImpl::Lock() { | 
 |   int rv = pthread_mutex_lock(&native_handle_); | 
 |   DCHECK_EQ(rv, 0) << ". " << SystemErrorCodeToString(rv); | 
 | } | 
 |  | 
 | // static | 
 | bool LockImpl::PriorityInheritanceAvailable() { | 
 | #if PRIORITY_INHERITANCE_LOCKS_POSSIBLE() && defined(OS_MACOSX) | 
 |   return true; | 
 | #else | 
 |   // Security concerns prevent the use of priority inheritance mutexes on Linux. | 
 |   //   * CVE-2010-0622 - Linux < 2.6.33-rc7, wake_futex_pi possible DoS. | 
 |   //     https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-0622 | 
 |   //   * CVE-2012-6647 - Linux < 3.5.1, futex_wait_requeue_pi possible DoS. | 
 |   //     https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2012-6647 | 
 |   //   * CVE-2014-3153 - Linux <= 3.14.5, futex_requeue, privilege escalation. | 
 |   //     https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-3153 | 
 |   // | 
 |   // If the above were all addressed, we still need a runtime check to deal with | 
 |   // the bug below. | 
 |   //   * glibc Bug 14652: https://sourceware.org/bugzilla/show_bug.cgi?id=14652 | 
 |   //     Fixed in glibc 2.17. | 
 |   //     Priority inheritance mutexes may deadlock with condition variables | 
 |   //     during reacquisition of the mutex after the condition variable is | 
 |   //     signalled. | 
 |   return false; | 
 | #endif | 
 | } | 
 |  | 
 | }  // namespace internal | 
 | }  // namespace base |