handle_closer_agent.cc 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. // Copyright (c) 2012 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 "sandbox/win/src/handle_closer_agent.h"
  5. #include <stddef.h>
  6. #include "base/check.h"
  7. #include "base/logging.h"
  8. #include "base/win/static_constants.h"
  9. #include "base/win/win_util.h"
  10. #include "base/win/windows_version.h"
  11. #include "sandbox/win/src/win_utils.h"
  12. #include "third_party/abseil-cpp/absl/types/optional.h"
  13. namespace sandbox {
  14. // Memory buffer mapped from the parent, with the list of handles.
  15. SANDBOX_INTERCEPT HandleCloserInfo* g_handles_to_close = nullptr;
  16. bool HandleCloserAgent::NeedsHandlesClosed() {
  17. return !!g_handles_to_close;
  18. }
  19. HandleCloserAgent::HandleCloserAgent()
  20. : dummy_handle_(::CreateEvent(nullptr, false, false, nullptr)) {}
  21. HandleCloserAgent::~HandleCloserAgent() {}
  22. // Attempts to stuff |closed_handle| with a duplicated handle for a dummy Event
  23. // with no access. This should allow the handle to be closed, to avoid
  24. // generating EXCEPTION_INVALID_HANDLE on shutdown, but nothing else. For now
  25. // the only supported |type| is Event or File.
  26. bool HandleCloserAgent::AttemptToStuffHandleSlot(HANDLE closed_handle,
  27. const std::wstring& type) {
  28. // Only attempt to stuff Files and Events at the moment.
  29. if (type != L"Event" && type != L"File") {
  30. return true;
  31. }
  32. if (!dummy_handle_.IsValid())
  33. return false;
  34. // This should never happen, as g_dummy is created before closing to_stuff.
  35. DCHECK(dummy_handle_.Get() != closed_handle);
  36. std::vector<HANDLE> to_close;
  37. const DWORD original_proc_num = GetCurrentProcessorNumber();
  38. DWORD proc_num = original_proc_num;
  39. DWORD_PTR original_affinity_mask =
  40. SetThreadAffinityMask(GetCurrentThread(), DWORD_PTR{1} << proc_num);
  41. bool found_handle = false;
  42. BOOL result = FALSE;
  43. // There is per-processor based free list of handles entries. The free handle
  44. // from current processor's freelist is preferred for reusing, so cycling
  45. // through all possible processors to find closed_handle.
  46. // Start searching from current processor which covers usual cases.
  47. do {
  48. DWORD_PTR current_mask = DWORD_PTR{1} << proc_num;
  49. if (original_affinity_mask & current_mask) {
  50. if (proc_num != original_proc_num) {
  51. SetThreadAffinityMask(GetCurrentThread(), current_mask);
  52. }
  53. HANDLE dup_dummy = nullptr;
  54. size_t count = 16;
  55. do {
  56. result =
  57. ::DuplicateHandle(::GetCurrentProcess(), dummy_handle_.Get(),
  58. ::GetCurrentProcess(), &dup_dummy, 0, false, 0);
  59. if (!result) {
  60. break;
  61. }
  62. if (dup_dummy != closed_handle) {
  63. to_close.push_back(dup_dummy);
  64. } else {
  65. found_handle = true;
  66. }
  67. } while (count-- && reinterpret_cast<uintptr_t>(dup_dummy) <
  68. reinterpret_cast<uintptr_t>(closed_handle));
  69. }
  70. proc_num++;
  71. if (proc_num == sizeof(DWORD_PTR) * 8) {
  72. proc_num = 0;
  73. }
  74. if (proc_num == original_proc_num) {
  75. break;
  76. }
  77. } while (result && !found_handle);
  78. SetThreadAffinityMask(GetCurrentThread(), original_affinity_mask);
  79. for (HANDLE h : to_close)
  80. ::CloseHandle(h);
  81. return found_handle;
  82. }
  83. // Reads g_handles_to_close and creates the lookup map.
  84. void HandleCloserAgent::InitializeHandlesToClose(bool* is_csrss_connected) {
  85. CHECK(g_handles_to_close);
  86. // Default to connected state
  87. *is_csrss_connected = true;
  88. // Grab the header.
  89. HandleListEntry* entry = g_handles_to_close->handle_entries;
  90. for (size_t i = 0; i < g_handles_to_close->num_handle_types; ++i) {
  91. // Set the type name.
  92. wchar_t* input = entry->handle_type;
  93. if (!wcscmp(input, L"ALPC Port")) {
  94. *is_csrss_connected = false;
  95. }
  96. HandleMap::mapped_type& handle_names = handles_to_close_[input];
  97. input = reinterpret_cast<wchar_t*>(reinterpret_cast<char*>(entry) +
  98. entry->offset_to_names);
  99. // Grab all the handle names.
  100. for (size_t j = 0; j < entry->name_count; ++j) {
  101. std::pair<HandleMap::mapped_type::iterator, bool> name =
  102. handle_names.insert(input);
  103. CHECK(name.second);
  104. input += name.first->size() + 1;
  105. }
  106. // Move on to the next entry.
  107. entry = reinterpret_cast<HandleListEntry*>(reinterpret_cast<char*>(entry) +
  108. entry->record_bytes);
  109. DCHECK(reinterpret_cast<wchar_t*>(entry) >= input);
  110. DCHECK(reinterpret_cast<wchar_t*>(entry) - input <
  111. static_cast<ptrdiff_t>(sizeof(size_t) / sizeof(wchar_t)));
  112. }
  113. // Clean up the memory we copied over.
  114. ::VirtualFree(g_handles_to_close, 0, MEM_RELEASE);
  115. g_handles_to_close = nullptr;
  116. }
  117. bool HandleCloserAgent::CloseHandles() {
  118. // Skip closing these handles when Application Verifier is in use in order to
  119. // avoid invalid-handle exceptions.
  120. if (base::win::IsAppVerifierLoaded())
  121. return true;
  122. // If the accurate handle enumeration fails then fallback to the old brute
  123. // force approach. This should only happen on Windows 7 and 8.0.
  124. absl::optional<ProcessHandleMap> handle_map = GetCurrentProcessHandles();
  125. if (!handle_map) {
  126. DCHECK(base::win::GetVersion() < base::win::Version::WIN8_1);
  127. handle_map = GetCurrentProcessHandlesWin7();
  128. }
  129. if (!handle_map)
  130. return false;
  131. for (const HandleMap::value_type& handle_to_close : handles_to_close_) {
  132. ProcessHandleMap::iterator result = handle_map->find(handle_to_close.first);
  133. if (result == handle_map->end())
  134. continue;
  135. const HandleMap::mapped_type& names = handle_to_close.second;
  136. for (HANDLE handle : result->second) {
  137. // Empty set means close all handles of this type; otherwise check name.
  138. if (!names.empty()) {
  139. std::wstring handle_name;
  140. // Move on to the next handle if this name doesn't match.
  141. if (!GetPathFromHandle(handle, &handle_name) ||
  142. !names.count(handle_name)) {
  143. continue;
  144. }
  145. }
  146. // If we can't unprotect or close the handle we should keep going.
  147. if (!::SetHandleInformation(handle, HANDLE_FLAG_PROTECT_FROM_CLOSE, 0))
  148. continue;
  149. if (!::CloseHandle(handle))
  150. continue;
  151. // Attempt to stuff this handle with a new dummy Event.
  152. AttemptToStuffHandleSlot(handle, result->first);
  153. }
  154. }
  155. return true;
  156. }
  157. } // namespace sandbox