security/sandbox/win/src/handle_closer_agent.cc

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/security/sandbox/win/src/handle_closer_agent.cc	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,145 @@
     1.4 +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
     1.5 +// Use of this source code is governed by a BSD-style license that can be
     1.6 +// found in the LICENSE file.
     1.7 +
     1.8 +#include "sandbox/win/src/handle_closer_agent.h"
     1.9 +
    1.10 +#include "base/logging.h"
    1.11 +#include "sandbox/win/src/nt_internals.h"
    1.12 +#include "sandbox/win/src/win_utils.h"
    1.13 +
    1.14 +namespace {
    1.15 +
    1.16 +// Returns type infomation for an NT object. This routine is expected to be
    1.17 +// called for invalid handles so it catches STATUS_INVALID_HANDLE exceptions
    1.18 +// that can be generated when handle tracing is enabled.
    1.19 +NTSTATUS QueryObjectTypeInformation(HANDLE handle,
    1.20 +                                    void* buffer,
    1.21 +                                    ULONG* size) {
    1.22 +  static NtQueryObject QueryObject = NULL;
    1.23 +  if (!QueryObject)
    1.24 +    ResolveNTFunctionPtr("NtQueryObject", &QueryObject);
    1.25 +
    1.26 +  NTSTATUS status = STATUS_UNSUCCESSFUL;
    1.27 +  __try {
    1.28 +    status = QueryObject(handle, ObjectTypeInformation, buffer, *size, size);
    1.29 +  } __except(GetExceptionCode() == STATUS_INVALID_HANDLE ?
    1.30 +                 EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
    1.31 +    status = STATUS_INVALID_HANDLE;
    1.32 +  }
    1.33 +  return status;
    1.34 +}
    1.35 +
    1.36 +}  // namespace
    1.37 +
    1.38 +namespace sandbox {
    1.39 +
    1.40 +// Memory buffer mapped from the parent, with the list of handles.
    1.41 +SANDBOX_INTERCEPT HandleCloserInfo* g_handles_to_close = NULL;
    1.42 +
    1.43 +bool HandleCloserAgent::NeedsHandlesClosed() {
    1.44 +  return g_handles_to_close != NULL;
    1.45 +}
    1.46 +
    1.47 +// Reads g_handles_to_close and creates the lookup map.
    1.48 +void HandleCloserAgent::InitializeHandlesToClose() {
    1.49 +  CHECK(g_handles_to_close != NULL);
    1.50 +
    1.51 +  // Grab the header.
    1.52 +  HandleListEntry* entry = g_handles_to_close->handle_entries;
    1.53 +  for (size_t i = 0; i < g_handles_to_close->num_handle_types; ++i) {
    1.54 +    // Set the type name.
    1.55 +    char16* input = entry->handle_type;
    1.56 +    HandleMap::mapped_type& handle_names = handles_to_close_[input];
    1.57 +    input = reinterpret_cast<char16*>(reinterpret_cast<char*>(entry)
    1.58 +        + entry->offset_to_names);
    1.59 +    // Grab all the handle names.
    1.60 +    for (size_t j = 0; j < entry->name_count; ++j) {
    1.61 +      std::pair<HandleMap::mapped_type::iterator, bool> name
    1.62 +          = handle_names.insert(input);
    1.63 +      CHECK(name.second);
    1.64 +      input += name.first->size() + 1;
    1.65 +    }
    1.66 +
    1.67 +    // Move on to the next entry.
    1.68 +    entry = reinterpret_cast<HandleListEntry*>(reinterpret_cast<char*>(entry)
    1.69 +        + entry->record_bytes);
    1.70 +
    1.71 +    DCHECK(reinterpret_cast<char16*>(entry) >= input);
    1.72 +    DCHECK(reinterpret_cast<char16*>(entry) - input <
    1.73 +           sizeof(size_t) / sizeof(char16));
    1.74 +  }
    1.75 +
    1.76 +  // Clean up the memory we copied over.
    1.77 +  ::VirtualFree(g_handles_to_close, 0, MEM_RELEASE);
    1.78 +  g_handles_to_close = NULL;
    1.79 +}
    1.80 +
    1.81 +bool HandleCloserAgent::CloseHandles() {
    1.82 +  DWORD handle_count = UINT_MAX;
    1.83 +  const int kInvalidHandleThreshold = 100;
    1.84 +  const size_t kHandleOffset = sizeof(HANDLE);
    1.85 +
    1.86 +  if (!::GetProcessHandleCount(::GetCurrentProcess(), &handle_count))
    1.87 +    return false;
    1.88 +
    1.89 +  // Set up buffers for the type info and the name.
    1.90 +  std::vector<BYTE> type_info_buffer(sizeof(OBJECT_TYPE_INFORMATION) +
    1.91 +                                     32 * sizeof(wchar_t));
    1.92 +  OBJECT_TYPE_INFORMATION* type_info =
    1.93 +      reinterpret_cast<OBJECT_TYPE_INFORMATION*>(&(type_info_buffer[0]));
    1.94 +  string16 handle_name;
    1.95 +  HANDLE handle = NULL;
    1.96 +  int invalid_count = 0;
    1.97 +
    1.98 +  // Keep incrementing until we hit the number of handles reported by
    1.99 +  // GetProcessHandleCount(). If we hit a very long sequence of invalid
   1.100 +  // handles we assume that we've run past the end of the table.
   1.101 +  while (handle_count && invalid_count < kInvalidHandleThreshold) {
   1.102 +    reinterpret_cast<size_t&>(handle) += kHandleOffset;
   1.103 +    NTSTATUS rc;
   1.104 +
   1.105 +    // Get the type name, reusing the buffer.
   1.106 +    ULONG size = static_cast<ULONG>(type_info_buffer.size());
   1.107 +    rc = QueryObjectTypeInformation(handle, type_info, &size);
   1.108 +    while (rc == STATUS_INFO_LENGTH_MISMATCH ||
   1.109 +           rc == STATUS_BUFFER_OVERFLOW) {
   1.110 +      type_info_buffer.resize(size + sizeof(wchar_t));
   1.111 +      type_info = reinterpret_cast<OBJECT_TYPE_INFORMATION*>(
   1.112 +          &(type_info_buffer[0]));
   1.113 +      rc = QueryObjectTypeInformation(handle, type_info, &size);
   1.114 +      // Leave padding for the nul terminator.
   1.115 +      if (NT_SUCCESS(rc) && size == type_info_buffer.size())
   1.116 +        rc = STATUS_INFO_LENGTH_MISMATCH;
   1.117 +    }
   1.118 +    if (!NT_SUCCESS(rc) || !type_info->Name.Buffer) {
   1.119 +      ++invalid_count;
   1.120 +      continue;
   1.121 +    }
   1.122 +
   1.123 +    --handle_count;
   1.124 +    type_info->Name.Buffer[type_info->Name.Length / sizeof(wchar_t)] = L'\0';
   1.125 +
   1.126 +    // Check if we're looking for this type of handle.
   1.127 +    HandleMap::iterator result =
   1.128 +        handles_to_close_.find(type_info->Name.Buffer);
   1.129 +    if (result != handles_to_close_.end()) {
   1.130 +      HandleMap::mapped_type& names = result->second;
   1.131 +      // Empty set means close all handles of this type; otherwise check name.
   1.132 +      if (!names.empty()) {
   1.133 +        // Move on to the next handle if this name doesn't match.
   1.134 +        if (!GetHandleName(handle, &handle_name) || !names.count(handle_name))
   1.135 +          continue;
   1.136 +      }
   1.137 +
   1.138 +      if (!::SetHandleInformation(handle, HANDLE_FLAG_PROTECT_FROM_CLOSE, 0))
   1.139 +        return false;
   1.140 +      if (!::CloseHandle(handle))
   1.141 +        return false;
   1.142 +    }
   1.143 +  }
   1.144 +
   1.145 +  return true;
   1.146 +}
   1.147 +
   1.148 +}  // namespace sandbox

mercurial