1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
4 // Use of this source code is governed by a BSD-style license that can be
5 // found in the LICENSE file.
6 
7 #include "base/lock_impl.h"
8 
9 #include <errno.h>
10 #include <string.h>
11 
12 #include "base/logging.h"
13 #include "base/lock.h"
14 
15 namespace base {
16 namespace internal {
17 
18 // Determines which platforms can consider using priority inheritance locks. Use
19 // this define for platform code that may not compile if priority inheritance
20 // locks aren't available. For this platform code,
21 // PRIORITY_INHERITANCE_LOCKS_POSSIBLE() is a necessary but insufficient check.
22 // Lock::PriorityInheritanceAvailable still must be checked as the code may
23 // compile but the underlying platform still may not correctly support priority
24 // inheritance locks.
25 #if defined(OS_NACL) || defined(OS_ANDROID)
26 #  define PRIORITY_INHERITANCE_LOCKS_POSSIBLE() 0
27 #else
28 #  define PRIORITY_INHERITANCE_LOCKS_POSSIBLE() 1
29 #endif
30 
LockImpl()31 LockImpl::LockImpl() {
32   pthread_mutexattr_t mta;
33   int rv = pthread_mutexattr_init(&mta);
34   DCHECK_EQ(rv, 0) << ". " << strerror(rv);
35 #if PRIORITY_INHERITANCE_LOCKS_POSSIBLE()
36   if (PriorityInheritanceAvailable()) {
37     rv = pthread_mutexattr_setprotocol(&mta, PTHREAD_PRIO_INHERIT);
38     DCHECK_EQ(rv, 0) << ". " << strerror(rv);
39   }
40 #endif
41 #ifndef NDEBUG
42   // In debug, setup attributes for lock error checking.
43   rv = pthread_mutexattr_settype(&mta, PTHREAD_MUTEX_ERRORCHECK);
44   DCHECK_EQ(rv, 0) << ". " << strerror(rv);
45 #endif
46   rv = pthread_mutex_init(&native_handle_, &mta);
47   DCHECK_EQ(rv, 0) << ". " << strerror(rv);
48   rv = pthread_mutexattr_destroy(&mta);
49   DCHECK_EQ(rv, 0) << ". " << strerror(rv);
50 }
51 
~LockImpl()52 LockImpl::~LockImpl() {
53   int rv = pthread_mutex_destroy(&native_handle_);
54   DCHECK_EQ(rv, 0) << ". " << strerror(rv);
55 }
56 
Try()57 bool LockImpl::Try() {
58   int rv = pthread_mutex_trylock(&native_handle_);
59   DCHECK(rv == 0 || rv == EBUSY) << ". " << strerror(rv);
60   return rv == 0;
61 }
62 
Lock()63 void LockImpl::Lock() {
64   int rv = pthread_mutex_lock(&native_handle_);
65   DCHECK_EQ(rv, 0) << ". " << strerror(rv);
66 }
67 
Unlock()68 void LockImpl::Unlock() {
69   int rv = pthread_mutex_unlock(&native_handle_);
70   DCHECK_EQ(rv, 0) << ". " << strerror(rv);
71 }
72 
73 // static
PriorityInheritanceAvailable()74 bool LockImpl::PriorityInheritanceAvailable() {
75 #if PRIORITY_INHERITANCE_LOCKS_POSSIBLE() && defined(OS_MACOSX)
76   return true;
77 #else
78   // Security concerns prevent the use of priority inheritance mutexes on Linux.
79   //   * CVE-2010-0622 - wake_futex_pi unlocks incorrect, possible DoS.
80   //     https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-0622
81   //   * CVE-2012-6647 - Linux < 3.5.1, futex_wait_requeue_pi possible DoS.
82   //     https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2012-6647
83   //   * CVE-2014-3153 - Linux <= 3.14.5, futex_requeue, privilege escalation.
84   //     https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-3153
85   //
86   // If the above were all addressed, we still need a runtime check to deal with
87   // the bug below.
88   //   * glibc Bug 14652: https://sourceware.org/bugzilla/show_bug.cgi?id=14652
89   //     Fixed in glibc 2.17.
90   //     Priority inheritance mutexes may deadlock with condition variables
91   //     during recacquisition of the mutex after the condition variable is
92   //     signalled.
93   return false;
94 #endif
95 }
96 
97 }  // namespace internal
98 }  // namespace base
99