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