15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sandbox/win/src/handle_closer_agent.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sandbox/win/src/nt_internals.h" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sandbox/win/src/win_utils.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns type infomation for an NT object. This routine is expected to be 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// called for invalid handles so it catches STATUS_INVALID_HANDLE exceptions 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// that can be generated when handle tracing is enabled. 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NTSTATUS QueryObjectTypeInformation(HANDLE handle, 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void* buffer, 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ULONG* size) { 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static NtQueryObject QueryObject = NULL; 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!QueryObject) 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ResolveNTFunctionPtr("NtQueryObject", &QueryObject); 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NTSTATUS status = STATUS_UNSUCCESSFUL; 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) __try { 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) status = QueryObject(handle, ObjectTypeInformation, buffer, *size, size); 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } __except(GetExceptionCode() == STATUS_INVALID_HANDLE ? 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) status = STATUS_INVALID_HANDLE; 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return status; 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace sandbox { 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Memory buffer mapped from the parent, with the list of handles. 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SANDBOX_INTERCEPT HandleCloserInfo* g_handles_to_close = NULL; 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HandleCloserAgent::NeedsHandlesClosed() { 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return g_handles_to_close != NULL; 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Reads g_handles_to_close and creates the lookup map. 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HandleCloserAgent::InitializeHandlesToClose() { 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(g_handles_to_close != NULL); 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Grab the header. 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HandleListEntry* entry = g_handles_to_close->handle_entries; 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < g_handles_to_close->num_handle_types; ++i) { 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Set the type name. 525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::char16* input = entry->handle_type; 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HandleMap::mapped_type& handle_names = handles_to_close_[input]; 545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) input = reinterpret_cast<base::char16*>(reinterpret_cast<char*>(entry) 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) + entry->offset_to_names); 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Grab all the handle names. 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t j = 0; j < entry->name_count; ++j) { 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::pair<HandleMap::mapped_type::iterator, bool> name 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) = handle_names.insert(input); 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(name.second); 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) input += name.first->size() + 1; 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Move on to the next entry. 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry = reinterpret_cast<HandleListEntry*>(reinterpret_cast<char*>(entry) 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) + entry->record_bytes); 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(reinterpret_cast<base::char16*>(entry) >= input); 695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(reinterpret_cast<base::char16*>(entry) - input < 705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) sizeof(size_t) / sizeof(base::char16)); 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Clean up the memory we copied over. 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ::VirtualFree(g_handles_to_close, 0, MEM_RELEASE); 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_handles_to_close = NULL; 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HandleCloserAgent::CloseHandles() { 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD handle_count = UINT_MAX; 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int kInvalidHandleThreshold = 100; 815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const size_t kHandleOffset = 4; // Handles are always a multiple of 4. 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!::GetProcessHandleCount(::GetCurrentProcess(), &handle_count)) 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Set up buffers for the type info and the name. 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<BYTE> type_info_buffer(sizeof(OBJECT_TYPE_INFORMATION) + 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 32 * sizeof(wchar_t)); 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OBJECT_TYPE_INFORMATION* type_info = 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reinterpret_cast<OBJECT_TYPE_INFORMATION*>(&(type_info_buffer[0])); 915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::string16 handle_name; 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HANDLE handle = NULL; 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int invalid_count = 0; 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Keep incrementing until we hit the number of handles reported by 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // GetProcessHandleCount(). If we hit a very long sequence of invalid 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // handles we assume that we've run past the end of the table. 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (handle_count && invalid_count < kInvalidHandleThreshold) { 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reinterpret_cast<size_t&>(handle) += kHandleOffset; 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NTSTATUS rc; 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Get the type name, reusing the buffer. 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ULONG size = static_cast<ULONG>(type_info_buffer.size()); 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rc = QueryObjectTypeInformation(handle, type_info, &size); 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (rc == STATUS_INFO_LENGTH_MISMATCH || 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rc == STATUS_BUFFER_OVERFLOW) { 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type_info_buffer.resize(size + sizeof(wchar_t)); 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type_info = reinterpret_cast<OBJECT_TYPE_INFORMATION*>( 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &(type_info_buffer[0])); 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rc = QueryObjectTypeInformation(handle, type_info, &size); 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Leave padding for the nul terminator. 112a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if (NT_SUCCESS(rc) && size == type_info_buffer.size()) 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rc = STATUS_INFO_LENGTH_MISMATCH; 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!NT_SUCCESS(rc) || !type_info->Name.Buffer) { 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++invalid_count; 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) --handle_count; 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type_info->Name.Buffer[type_info->Name.Length / sizeof(wchar_t)] = L'\0'; 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check if we're looking for this type of handle. 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HandleMap::iterator result = 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) handles_to_close_.find(type_info->Name.Buffer); 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (result != handles_to_close_.end()) { 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HandleMap::mapped_type& names = result->second; 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Empty set means close all handles of this type; otherwise check name. 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!names.empty()) { 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Move on to the next handle if this name doesn't match. 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!GetHandleName(handle, &handle_name) || !names.count(handle_name)) 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!::SetHandleInformation(handle, HANDLE_FLAG_PROTECT_FROM_CLOSE, 0)) 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!::CloseHandle(handle)) 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace sandbox 146