xref: /aosp_15_r20/external/cronet/base/files/scoped_file_linux.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2021 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #include "base/files/scoped_file.h"
6*6777b538SAndroid Build Coastguard Worker 
7*6777b538SAndroid Build Coastguard Worker #include <dlfcn.h>
8*6777b538SAndroid Build Coastguard Worker 
9*6777b538SAndroid Build Coastguard Worker #include <algorithm>
10*6777b538SAndroid Build Coastguard Worker #include <array>
11*6777b538SAndroid Build Coastguard Worker #include <atomic>
12*6777b538SAndroid Build Coastguard Worker 
13*6777b538SAndroid Build Coastguard Worker #include "base/compiler_specific.h"
14*6777b538SAndroid Build Coastguard Worker #include "base/debug/stack_trace.h"
15*6777b538SAndroid Build Coastguard Worker #include "base/immediate_crash.h"
16*6777b538SAndroid Build Coastguard Worker #include "base/logging.h"
17*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_piece.h"
18*6777b538SAndroid Build Coastguard Worker 
19*6777b538SAndroid Build Coastguard Worker namespace {
20*6777b538SAndroid Build Coastguard Worker 
21*6777b538SAndroid Build Coastguard Worker // We want to avoid any kind of allocations in our close() implementation, so we
22*6777b538SAndroid Build Coastguard Worker // use a fixed-size table. Given our common FD limits and the preference for new
23*6777b538SAndroid Build Coastguard Worker // FD allocations to use the lowest available descriptor, this should be
24*6777b538SAndroid Build Coastguard Worker // sufficient to guard most FD lifetimes. The worst case scenario if someone
25*6777b538SAndroid Build Coastguard Worker // attempts to own a higher FD is that we don't track it.
26*6777b538SAndroid Build Coastguard Worker const int kMaxTrackedFds = 4096;
27*6777b538SAndroid Build Coastguard Worker 
28*6777b538SAndroid Build Coastguard Worker std::atomic_bool g_is_ownership_enforced{false};
29*6777b538SAndroid Build Coastguard Worker std::array<std::atomic_bool, kMaxTrackedFds> g_is_fd_owned;
30*6777b538SAndroid Build Coastguard Worker 
CrashOnFdOwnershipViolation()31*6777b538SAndroid Build Coastguard Worker NOINLINE void CrashOnFdOwnershipViolation() {
32*6777b538SAndroid Build Coastguard Worker   RAW_LOG(ERROR, "Crashing due to FD ownership violation:\n");
33*6777b538SAndroid Build Coastguard Worker   base::debug::StackTrace().Print();
34*6777b538SAndroid Build Coastguard Worker   base::ImmediateCrash();
35*6777b538SAndroid Build Coastguard Worker }
36*6777b538SAndroid Build Coastguard Worker 
CanTrack(int fd)37*6777b538SAndroid Build Coastguard Worker bool CanTrack(int fd) {
38*6777b538SAndroid Build Coastguard Worker   return fd >= 0 && fd < kMaxTrackedFds;
39*6777b538SAndroid Build Coastguard Worker }
40*6777b538SAndroid Build Coastguard Worker 
UpdateAndCheckFdOwnership(int fd,bool owned)41*6777b538SAndroid Build Coastguard Worker void UpdateAndCheckFdOwnership(int fd, bool owned) {
42*6777b538SAndroid Build Coastguard Worker   if (CanTrack(fd) &&
43*6777b538SAndroid Build Coastguard Worker       g_is_fd_owned[static_cast<size_t>(fd)].exchange(owned) == owned &&
44*6777b538SAndroid Build Coastguard Worker       g_is_ownership_enforced) {
45*6777b538SAndroid Build Coastguard Worker     CrashOnFdOwnershipViolation();
46*6777b538SAndroid Build Coastguard Worker   }
47*6777b538SAndroid Build Coastguard Worker }
48*6777b538SAndroid Build Coastguard Worker 
49*6777b538SAndroid Build Coastguard Worker }  // namespace
50*6777b538SAndroid Build Coastguard Worker 
51*6777b538SAndroid Build Coastguard Worker namespace base {
52*6777b538SAndroid Build Coastguard Worker namespace internal {
53*6777b538SAndroid Build Coastguard Worker 
54*6777b538SAndroid Build Coastguard Worker // static
Acquire(const ScopedFD & owner,int fd)55*6777b538SAndroid Build Coastguard Worker void ScopedFDCloseTraits::Acquire(const ScopedFD& owner, int fd) {
56*6777b538SAndroid Build Coastguard Worker   UpdateAndCheckFdOwnership(fd, /*owned=*/true);
57*6777b538SAndroid Build Coastguard Worker }
58*6777b538SAndroid Build Coastguard Worker 
59*6777b538SAndroid Build Coastguard Worker // static
Release(const ScopedFD & owner,int fd)60*6777b538SAndroid Build Coastguard Worker void ScopedFDCloseTraits::Release(const ScopedFD& owner, int fd) {
61*6777b538SAndroid Build Coastguard Worker   UpdateAndCheckFdOwnership(fd, /*owned=*/false);
62*6777b538SAndroid Build Coastguard Worker }
63*6777b538SAndroid Build Coastguard Worker 
64*6777b538SAndroid Build Coastguard Worker }  // namespace internal
65*6777b538SAndroid Build Coastguard Worker 
66*6777b538SAndroid Build Coastguard Worker namespace subtle {
67*6777b538SAndroid Build Coastguard Worker 
EnableFDOwnershipEnforcement(bool enabled)68*6777b538SAndroid Build Coastguard Worker void EnableFDOwnershipEnforcement(bool enabled) {
69*6777b538SAndroid Build Coastguard Worker   g_is_ownership_enforced = enabled;
70*6777b538SAndroid Build Coastguard Worker }
71*6777b538SAndroid Build Coastguard Worker 
ResetFDOwnership()72*6777b538SAndroid Build Coastguard Worker void ResetFDOwnership() {
73*6777b538SAndroid Build Coastguard Worker   std::fill(g_is_fd_owned.begin(), g_is_fd_owned.end(), false);
74*6777b538SAndroid Build Coastguard Worker }
75*6777b538SAndroid Build Coastguard Worker 
76*6777b538SAndroid Build Coastguard Worker }  // namespace subtle
77*6777b538SAndroid Build Coastguard Worker 
IsFDOwned(int fd)78*6777b538SAndroid Build Coastguard Worker bool IsFDOwned(int fd) {
79*6777b538SAndroid Build Coastguard Worker   return CanTrack(fd) && g_is_fd_owned[static_cast<size_t>(fd)];
80*6777b538SAndroid Build Coastguard Worker }
81*6777b538SAndroid Build Coastguard Worker 
82*6777b538SAndroid Build Coastguard Worker }  // namespace base
83*6777b538SAndroid Build Coastguard Worker 
84*6777b538SAndroid Build Coastguard Worker using LibcCloseFuncPtr = int (*)(int);
85*6777b538SAndroid Build Coastguard Worker 
86*6777b538SAndroid Build Coastguard Worker // Load the libc close symbol to forward to from the close wrapper.
LoadCloseSymbol()87*6777b538SAndroid Build Coastguard Worker LibcCloseFuncPtr LoadCloseSymbol() {
88*6777b538SAndroid Build Coastguard Worker #if defined(THREAD_SANITIZER)
89*6777b538SAndroid Build Coastguard Worker   // If TSAN is enabled use __interceptor___close first to make sure the TSAN
90*6777b538SAndroid Build Coastguard Worker   // wrapper gets called.
91*6777b538SAndroid Build Coastguard Worker   return reinterpret_cast<LibcCloseFuncPtr>(
92*6777b538SAndroid Build Coastguard Worker       dlsym(RTLD_DEFAULT, "__interceptor___close"));
93*6777b538SAndroid Build Coastguard Worker #else
94*6777b538SAndroid Build Coastguard Worker   return reinterpret_cast<LibcCloseFuncPtr>(dlsym(RTLD_NEXT, "close"));
95*6777b538SAndroid Build Coastguard Worker #endif
96*6777b538SAndroid Build Coastguard Worker }
97*6777b538SAndroid Build Coastguard Worker 
98*6777b538SAndroid Build Coastguard Worker extern "C" {
99*6777b538SAndroid Build Coastguard Worker 
100*6777b538SAndroid Build Coastguard Worker NO_SANITIZE("cfi-icall")
close(int fd)101*6777b538SAndroid Build Coastguard Worker __attribute__((visibility("default"), noinline)) int close(int fd) {
102*6777b538SAndroid Build Coastguard Worker   static LibcCloseFuncPtr libc_close = LoadCloseSymbol();
103*6777b538SAndroid Build Coastguard Worker   if (base::IsFDOwned(fd) && g_is_ownership_enforced)
104*6777b538SAndroid Build Coastguard Worker     CrashOnFdOwnershipViolation();
105*6777b538SAndroid Build Coastguard Worker   if (libc_close == nullptr) {
106*6777b538SAndroid Build Coastguard Worker     RAW_LOG(ERROR, "close symbol missing\n");
107*6777b538SAndroid Build Coastguard Worker     base::ImmediateCrash();
108*6777b538SAndroid Build Coastguard Worker   }
109*6777b538SAndroid Build Coastguard Worker   return libc_close(fd);
110*6777b538SAndroid Build Coastguard Worker }
111*6777b538SAndroid Build Coastguard Worker 
112*6777b538SAndroid Build Coastguard Worker }  // extern "C"
113