OLD | NEW |
| (Empty) |
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 | |
5 #include "sandbox/src/handle_closer_agent.h" | |
6 | |
7 #include "base/logging.h" | |
8 #include "sandbox/src/nt_internals.h" | |
9 #include "sandbox/src/win_utils.h" | |
10 | |
11 namespace { | |
12 | |
13 // Returns type infomation for an NT object. This routine is expected to be | |
14 // called for invalid handles so it catches STATUS_INVALID_HANDLE exceptions | |
15 // that can be generated when handle tracing is enabled. | |
16 NTSTATUS QueryObjectTypeInformation(HANDLE handle, | |
17 void* buffer, | |
18 ULONG* size) { | |
19 static NtQueryObject QueryObject = NULL; | |
20 if (!QueryObject) | |
21 ResolveNTFunctionPtr("NtQueryObject", &QueryObject); | |
22 | |
23 NTSTATUS status = STATUS_UNSUCCESSFUL; | |
24 __try { | |
25 status = QueryObject(handle, ObjectTypeInformation, buffer, *size, size); | |
26 } __except(GetExceptionCode() == STATUS_INVALID_HANDLE ? | |
27 EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { | |
28 status = STATUS_INVALID_HANDLE; | |
29 } | |
30 return status; | |
31 } | |
32 | |
33 } // namespace | |
34 | |
35 namespace sandbox { | |
36 | |
37 // Memory buffer mapped from the parent, with the list of handles. | |
38 SANDBOX_INTERCEPT HandleCloserInfo* g_handles_to_close = NULL; | |
39 | |
40 bool HandleCloserAgent::NeedsHandlesClosed() { | |
41 return g_handles_to_close != NULL; | |
42 } | |
43 | |
44 // Reads g_handles_to_close and creates the lookup map. | |
45 void HandleCloserAgent::InitializeHandlesToClose() { | |
46 CHECK(g_handles_to_close != NULL); | |
47 | |
48 // Grab the header. | |
49 HandleListEntry* entry = g_handles_to_close->handle_entries; | |
50 for (size_t i = 0; i < g_handles_to_close->num_handle_types; ++i) { | |
51 // Set the type name. | |
52 char16* input = entry->handle_type; | |
53 HandleMap::mapped_type& handle_names = handles_to_close_[input]; | |
54 input = reinterpret_cast<char16*>(reinterpret_cast<char*>(entry) | |
55 + entry->offset_to_names); | |
56 // Grab all the handle names. | |
57 for (size_t j = 0; j < entry->name_count; ++j) { | |
58 std::pair<HandleMap::mapped_type::iterator, bool> name | |
59 = handle_names.insert(input); | |
60 CHECK(name.second); | |
61 input += name.first->size() + 1; | |
62 } | |
63 | |
64 // Move on to the next entry. | |
65 entry = reinterpret_cast<HandleListEntry*>(reinterpret_cast<char*>(entry) | |
66 + entry->record_bytes); | |
67 | |
68 DCHECK(reinterpret_cast<char16*>(entry) >= input); | |
69 DCHECK(reinterpret_cast<char16*>(entry) - input < | |
70 sizeof(size_t) / sizeof(char16)); | |
71 } | |
72 | |
73 // Clean up the memory we copied over. | |
74 ::VirtualFree(g_handles_to_close, 0, MEM_RELEASE); | |
75 g_handles_to_close = NULL; | |
76 } | |
77 | |
78 bool HandleCloserAgent::CloseHandles() { | |
79 DWORD handle_count = UINT_MAX; | |
80 const int kInvalidHandleThreshold = 100; | |
81 const size_t kHandleOffset = sizeof(HANDLE); | |
82 | |
83 if (!::GetProcessHandleCount(::GetCurrentProcess(), &handle_count)) | |
84 return false; | |
85 | |
86 // Set up buffers for the type info and the name. | |
87 std::vector<BYTE> type_info_buffer(sizeof(OBJECT_TYPE_INFORMATION) + | |
88 32 * sizeof(wchar_t)); | |
89 OBJECT_TYPE_INFORMATION* type_info = | |
90 reinterpret_cast<OBJECT_TYPE_INFORMATION*>(&(type_info_buffer[0])); | |
91 string16 handle_name; | |
92 HANDLE handle = NULL; | |
93 int invalid_count = 0; | |
94 | |
95 // Keep incrementing until we hit the number of handles reported by | |
96 // GetProcessHandleCount(). If we hit a very long sequence of invalid | |
97 // handles we assume that we've run past the end of the table. | |
98 while (handle_count && invalid_count < kInvalidHandleThreshold) { | |
99 reinterpret_cast<size_t&>(handle) += kHandleOffset; | |
100 NTSTATUS rc; | |
101 | |
102 // Get the type name, reusing the buffer. | |
103 ULONG size = static_cast<ULONG>(type_info_buffer.size()); | |
104 rc = QueryObjectTypeInformation(handle, type_info, &size); | |
105 while (rc == STATUS_INFO_LENGTH_MISMATCH || | |
106 rc == STATUS_BUFFER_OVERFLOW) { | |
107 type_info_buffer.resize(size + sizeof(wchar_t)); | |
108 type_info = reinterpret_cast<OBJECT_TYPE_INFORMATION*>( | |
109 &(type_info_buffer[0])); | |
110 rc = QueryObjectTypeInformation(handle, type_info, &size); | |
111 // Leave padding for the nul terminator. | |
112 if (NT_SUCCESS(0) && size == type_info_buffer.size()) | |
113 rc = STATUS_INFO_LENGTH_MISMATCH; | |
114 } | |
115 if (!NT_SUCCESS(rc) || !type_info->Name.Buffer) { | |
116 ++invalid_count; | |
117 continue; | |
118 } | |
119 | |
120 --handle_count; | |
121 type_info->Name.Buffer[type_info->Name.Length / sizeof(wchar_t)] = L'\0'; | |
122 | |
123 // Check if we're looking for this type of handle. | |
124 HandleMap::iterator result = | |
125 handles_to_close_.find(type_info->Name.Buffer); | |
126 if (result != handles_to_close_.end()) { | |
127 HandleMap::mapped_type& names = result->second; | |
128 // Empty set means close all handles of this type; otherwise check name. | |
129 if (!names.empty()) { | |
130 // Move on to the next handle if this name doesn't match. | |
131 if (!GetHandleName(handle, &handle_name) || !names.count(handle_name)) | |
132 continue; | |
133 } | |
134 | |
135 if (!::SetHandleInformation(handle, HANDLE_FLAG_PROTECT_FROM_CLOSE, 0)) | |
136 return false; | |
137 if (!::CloseHandle(handle)) | |
138 return false; | |
139 } | |
140 } | |
141 | |
142 return true; | |
143 } | |
144 | |
145 } // namespace sandbox | |
OLD | NEW |