Home | History | Annotate | Download | only in src
      1 // Copyright (c) 2011 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/win/src/handle_closer.h"
      6 
      7 #include "base/logging.h"
      8 #include "base/memory/scoped_ptr.h"
      9 #include "base/win/windows_version.h"
     10 #include "sandbox/win/src/interceptors.h"
     11 #include "sandbox/win/src/internal_types.h"
     12 #include "sandbox/win/src/nt_internals.h"
     13 #include "sandbox/win/src/process_thread_interception.h"
     14 #include "sandbox/win/src/win_utils.h"
     15 
     16 namespace {
     17 
     18 template<typename T> T RoundUpToWordSize(T v) {
     19   if (size_t mod = v % sizeof(size_t))
     20     v += sizeof(size_t) - mod;
     21   return v;
     22 }
     23 
     24 template<typename T> T* RoundUpToWordSize(T* v) {
     25   return reinterpret_cast<T*>(RoundUpToWordSize(reinterpret_cast<size_t>(v)));
     26 }
     27 
     28 }  // namespace
     29 
     30 namespace sandbox {
     31 
     32 // Memory buffer mapped from the parent, with the list of handles.
     33 SANDBOX_INTERCEPT HandleCloserInfo* g_handles_to_close;
     34 
     35 HandleCloser::HandleCloser() {}
     36 
     37 ResultCode HandleCloser::AddHandle(const base::char16* handle_type,
     38                                    const base::char16* handle_name) {
     39   if (!handle_type)
     40     return SBOX_ERROR_BAD_PARAMS;
     41 
     42   base::string16 resolved_name;
     43   if (handle_name) {
     44     resolved_name = handle_name;
     45     if (handle_type == base::string16(L"Key"))
     46       if (!ResolveRegistryName(resolved_name, &resolved_name))
     47         return SBOX_ERROR_BAD_PARAMS;
     48   }
     49 
     50   HandleMap::iterator names = handles_to_close_.find(handle_type);
     51   if (names == handles_to_close_.end()) {  // We have no entries for this type.
     52     std::pair<HandleMap::iterator, bool> result = handles_to_close_.insert(
     53         HandleMap::value_type(handle_type, HandleMap::mapped_type()));
     54     names = result.first;
     55     if (handle_name)
     56       names->second.insert(resolved_name);
     57   } else if (!handle_name) {  // Now we need to close all handles of this type.
     58     names->second.clear();
     59   } else if (!names->second.empty()) {  // Add another name for this type.
     60     names->second.insert(resolved_name);
     61   }  // If we're already closing all handles of type then we're done.
     62 
     63   return SBOX_ALL_OK;
     64 }
     65 
     66 size_t HandleCloser::GetBufferSize() {
     67   size_t bytes_total = offsetof(HandleCloserInfo, handle_entries);
     68 
     69   for (HandleMap::iterator i = handles_to_close_.begin();
     70        i != handles_to_close_.end(); ++i) {
     71     size_t bytes_entry = offsetof(HandleListEntry, handle_type) +
     72         (i->first.size() + 1) * sizeof(base::char16);
     73     for (HandleMap::mapped_type::iterator j = i->second.begin();
     74          j != i->second.end(); ++j) {
     75       bytes_entry += ((*j).size() + 1) * sizeof(base::char16);
     76     }
     77 
     78     // Round up to the nearest multiple of word size.
     79     bytes_entry = RoundUpToWordSize(bytes_entry);
     80     bytes_total += bytes_entry;
     81   }
     82 
     83   return bytes_total;
     84 }
     85 
     86 bool HandleCloser::InitializeTargetHandles(TargetProcess* target) {
     87   // Do nothing on an empty list (global pointer already initialized to NULL).
     88   if (handles_to_close_.empty())
     89     return true;
     90 
     91   size_t bytes_needed = GetBufferSize();
     92   scoped_ptr<size_t[]> local_buffer(
     93       new size_t[bytes_needed / sizeof(size_t)]);
     94 
     95   if (!SetupHandleList(local_buffer.get(), bytes_needed))
     96     return false;
     97 
     98   HANDLE child = target->Process();
     99 
    100   // Allocate memory in the target process without specifying the address
    101   void* remote_data = ::VirtualAllocEx(child, NULL, bytes_needed,
    102                                        MEM_COMMIT, PAGE_READWRITE);
    103   if (NULL == remote_data)
    104     return false;
    105 
    106   // Copy the handle buffer over.
    107   SIZE_T bytes_written;
    108   BOOL result = ::WriteProcessMemory(child, remote_data, local_buffer.get(),
    109                                      bytes_needed, &bytes_written);
    110   if (!result || bytes_written != bytes_needed) {
    111     ::VirtualFreeEx(child, remote_data, 0, MEM_RELEASE);
    112     return false;
    113   }
    114 
    115   g_handles_to_close = reinterpret_cast<HandleCloserInfo*>(remote_data);
    116 
    117   ResultCode rc = target->TransferVariable("g_handles_to_close",
    118                                            &g_handles_to_close,
    119                                            sizeof(g_handles_to_close));
    120 
    121   return (SBOX_ALL_OK == rc);
    122 }
    123 
    124 bool HandleCloser::SetupHandleList(void* buffer, size_t buffer_bytes) {
    125   ::ZeroMemory(buffer, buffer_bytes);
    126   HandleCloserInfo* handle_info = reinterpret_cast<HandleCloserInfo*>(buffer);
    127   handle_info->record_bytes = buffer_bytes;
    128   handle_info->num_handle_types = handles_to_close_.size();
    129 
    130   base::char16* output = reinterpret_cast<base::char16*>(
    131       &handle_info->handle_entries[0]);
    132   base::char16* end = reinterpret_cast<base::char16*>(
    133       reinterpret_cast<char*>(buffer) + buffer_bytes);
    134   for (HandleMap::iterator i = handles_to_close_.begin();
    135        i != handles_to_close_.end(); ++i) {
    136     if (output >= end)
    137       return false;
    138     HandleListEntry* list_entry = reinterpret_cast<HandleListEntry*>(output);
    139     output = &list_entry->handle_type[0];
    140 
    141     // Copy the typename and set the offset and count.
    142     i->first._Copy_s(output, i->first.size(), i->first.size());
    143     *(output += i->first.size()) = L'\0';
    144     output++;
    145     list_entry->offset_to_names = reinterpret_cast<char*>(output) -
    146         reinterpret_cast<char*>(list_entry);
    147     list_entry->name_count = i->second.size();
    148 
    149     // Copy the handle names.
    150     for (HandleMap::mapped_type::iterator j = i->second.begin();
    151          j != i->second.end(); ++j) {
    152       output = std::copy((*j).begin(), (*j).end(), output) + 1;
    153     }
    154 
    155     // Round up to the nearest multiple of sizeof(size_t).
    156     output = RoundUpToWordSize(output);
    157     list_entry->record_bytes = reinterpret_cast<char*>(output) -
    158         reinterpret_cast<char*>(list_entry);
    159   }
    160 
    161   DCHECK_EQ(reinterpret_cast<size_t>(output), reinterpret_cast<size_t>(end));
    162   return output <= end;
    163 }
    164 
    165 bool GetHandleName(HANDLE handle, base::string16* handle_name) {
    166   static NtQueryObject QueryObject = NULL;
    167   if (!QueryObject)
    168     ResolveNTFunctionPtr("NtQueryObject", &QueryObject);
    169 
    170   ULONG size = MAX_PATH;
    171   scoped_ptr<UNICODE_STRING, base::FreeDeleter> name;
    172   NTSTATUS result;
    173 
    174   do {
    175     name.reset(static_cast<UNICODE_STRING*>(malloc(size)));
    176     DCHECK(name.get());
    177     result = QueryObject(handle, ObjectNameInformation, name.get(),
    178                          size, &size);
    179   } while (result == STATUS_INFO_LENGTH_MISMATCH ||
    180            result == STATUS_BUFFER_OVERFLOW);
    181 
    182   if (NT_SUCCESS(result) && name->Buffer && name->Length)
    183     handle_name->assign(name->Buffer, name->Length / sizeof(wchar_t));
    184   else
    185     handle_name->clear();
    186 
    187   return NT_SUCCESS(result);
    188 }
    189 
    190 }  // namespace sandbox
    191