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