scoped_file_linux.cc 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. // Copyright 2021 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. #include "base/files/scoped_file.h"
  5. #include <algorithm>
  6. #include <array>
  7. #include <atomic>
  8. #include "base/compiler_specific.h"
  9. #include "base/debug/stack_trace.h"
  10. #include "base/immediate_crash.h"
  11. #include "base/logging.h"
  12. #include "base/strings/string_piece.h"
  13. namespace {
  14. // We want to avoid any kind of allocations in our close() implementation, so we
  15. // use a fixed-size table. Given our common FD limits and the preference for new
  16. // FD allocations to use the lowest available descriptor, this should be
  17. // sufficient to guard most FD lifetimes. The worst case scenario if someone
  18. // attempts to own a higher FD is that we don't track it.
  19. const int kMaxTrackedFds = 4096;
  20. std::atomic_bool g_is_ownership_enforced{false};
  21. std::array<std::atomic_bool, kMaxTrackedFds> g_is_fd_owned;
  22. NOINLINE void CrashOnFdOwnershipViolation() {
  23. RAW_LOG(ERROR, "Crashing due to FD ownership violation:\n");
  24. base::debug::StackTrace().Print();
  25. IMMEDIATE_CRASH();
  26. }
  27. bool CanTrack(int fd) {
  28. return fd >= 0 && fd < kMaxTrackedFds;
  29. }
  30. void UpdateAndCheckFdOwnership(int fd, bool owned) {
  31. if (CanTrack(fd) &&
  32. g_is_fd_owned[static_cast<size_t>(fd)].exchange(owned) == owned &&
  33. g_is_ownership_enforced) {
  34. CrashOnFdOwnershipViolation();
  35. }
  36. }
  37. } // namespace
  38. namespace base {
  39. namespace internal {
  40. // static
  41. void ScopedFDCloseTraits::Acquire(const ScopedFD& owner, int fd) {
  42. UpdateAndCheckFdOwnership(fd, /*owned=*/true);
  43. }
  44. // static
  45. void ScopedFDCloseTraits::Release(const ScopedFD& owner, int fd) {
  46. UpdateAndCheckFdOwnership(fd, /*owned=*/false);
  47. }
  48. } // namespace internal
  49. namespace subtle {
  50. void EnableFDOwnershipEnforcement(bool enabled) {
  51. g_is_ownership_enforced = enabled;
  52. }
  53. void ResetFDOwnership() {
  54. std::fill(g_is_fd_owned.begin(), g_is_fd_owned.end(), false);
  55. }
  56. } // namespace subtle
  57. bool IsFDOwned(int fd) {
  58. return CanTrack(fd) && g_is_fd_owned[static_cast<size_t>(fd)];
  59. }
  60. } // namespace base
  61. extern "C" {
  62. int __close(int);
  63. __attribute__((visibility("default"), noinline)) int close(int fd) {
  64. if (base::IsFDOwned(fd) && g_is_ownership_enforced)
  65. CrashOnFdOwnershipViolation();
  66. return __close(fd);
  67. }
  68. } // extern "C"