File: lock_impl_posix.cc

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (176 lines) | stat: -rw-r--r-- 6,300 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
// Copyright 2011 The Chromium Authors
// 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 <pthread.h>

#include <atomic>
#include <cstdint>
#include <ostream>
#include <string>

#include "base/check_op.h"
#include "base/posix/safe_strerror.h"
#include "base/synchronization/lock.h"
#include "base/synchronization/synchronization_buildflags.h"
#include "base/system/sys_info.h"
#include "build/build_config.h"
#if BUILDFLAG(IS_ANDROID)
#include "base/android/background_thread_pool_field_trial.h"
#endif

// On Android, `pthread_mutexattr_setprotocol()` is only defined in bionic
// starting with API level 28. Make it a weak import, so that we can compile.
extern "C" {
int __attribute__((weak)) pthread_mutexattr_setprotocol(
    pthread_mutexattr_t* _Nonnull __attr,
    int __protocol);
}

namespace base {

namespace internal {
namespace {

#if BUILDFLAG(ENABLE_MUTEX_PRIORITY_INHERITANCE) && BUILDFLAG(IS_ANDROID)
bool IsMutexPriorityInheritanceEnabled() {
  return
#pragma clang diagnostic push  // Can be removed once our min-sdk is >= 28.
#pragma clang diagnostic ignored "-Wunguarded-availability"
      (pthread_mutexattr_setprotocol != nullptr) &&
#pragma clang diagnostic pop
      base::android::BackgroundThreadPoolFieldTrial::
          ShouldUsePriorityInheritanceLocks();
}
#endif  //  BUILDFLAG(ENABLE_MUTEX_PRIORITY_INHERITANCE) &&
        //  BUILDFLAG(IS_ANDROID)

#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

#if DCHECK_IS_ON()
// These are out-of-line so that the .h file doesn't have to include ostream.
void dcheck_trylock_result(int rv) {
  DCHECK(rv == 0 || rv == EBUSY)
      << ". " << base::internal::SystemErrorCodeToString(rv);
}

void dcheck_unlock_result(int rv) {
  DCHECK_EQ(rv, 0) << ". " << strerror(rv);
}
#endif

// 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 BUILDFLAG(IS_NACL) || BUILDFLAG(IS_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()) {
#pragma clang diagnostic push  // Can be removed once our min-sdk is >= 28.
#pragma clang diagnostic ignored "-Wunguarded-availability"
    rv = pthread_mutexattr_setprotocol(&mta, PTHREAD_PRIO_INHERIT);
#pragma clang diagnostic pop
    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);
}

void LockImpl::LockInternal() {
  int rv = pthread_mutex_lock(&native_handle_);
  DCHECK_EQ(rv, 0) << ". " << SystemErrorCodeToString(rv);
}

// static
bool LockImpl::PriorityInheritanceAvailable() {
#if BUILDFLAG(ENABLE_MUTEX_PRIORITY_INHERITANCE) && BUILDFLAG(IS_ANDROID)
  return IsMutexPriorityInheritanceEnabled();
#elif PRIORITY_INHERITANCE_LOCKS_POSSIBLE() && BUILDFLAG(IS_APPLE)
  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

bool KernelSupportsPriorityInheritanceFutex() {
  // https://android-review.googlesource.com/c/3481472 which fixes priority
  // inheritance using rt-mutexes in the kernel landed in the 6.12.13 android
  // kernel and was backported to the 6.1.75 and 6.6.29 kernels. This change
  // hasn't been upstreamed yet.
#if BUILDFLAG(IS_ANDROID)
  auto kernel_version = SysInfo::KernelVersionNumber::Current();
  return (kernel_version > SysInfo::KernelVersionNumber(6, 12, 13)) ||
         ((kernel_version > SysInfo::KernelVersionNumber(6, 6, 29)) &&
          (kernel_version < SysInfo::KernelVersionNumber(6, 6, INT32_MAX))) ||
         ((kernel_version > SysInfo::KernelVersionNumber(6, 1, 75)) &&
          (kernel_version < SysInfo::KernelVersionNumber(6, 1, INT32_MAX)));
#else   // BUILDFLAG(IS_ANDROID)
  return false;
#endif  // BUILDFLAG(IS_ANDROID)
}

}  // namespace base