forked from chromium/chromium
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a sandbox API to allow closing open handles at lockdown.
BUG=58069 BUG=74242 TEST=sbox_integration_tests --gtest_filter=HandleCloserTests.* Review URL: http://codereview.chromium.org/7253054 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@92887 0039d316-1c4b-4281-b951-d872f2087c98
- Loading branch information
jschuh@chromium.org
committed
Jul 18, 2011
1 parent
0a34b6a
commit 404fbfc
Showing
12 changed files
with
590 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
// Copyright (c) 2011 The Chromium Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#include "sandbox/src/handle_closer.h" | ||
|
||
#include "base/logging.h" | ||
#include "base/memory/scoped_ptr.h" | ||
#include "sandbox/src/nt_internals.h" | ||
#include "sandbox/src/win_utils.h" | ||
|
||
namespace sandbox { | ||
|
||
// Memory buffer mapped from the parent, with the list of handles. | ||
SANDBOX_INTERCEPT HandleCloserInfo* g_handles_to_close; | ||
|
||
HandleCloser::HandleCloser() {} | ||
|
||
ResultCode HandleCloser::AddHandle(const char16* handle_type, | ||
const char16* handle_name) { | ||
if (!handle_type) | ||
return SBOX_ERROR_BAD_PARAMS; | ||
|
||
HandleMap::iterator names = handles_to_close_.find(handle_type); | ||
if (names == handles_to_close_.end()) { // We have no entries for this type. | ||
std::pair<HandleMap::iterator, bool> result = handles_to_close_.insert( | ||
HandleMap::value_type(handle_type, HandleMap::mapped_type())); | ||
names = result.first; | ||
if (handle_name) | ||
names->second.insert(handle_name); | ||
} else if (!handle_name) { // Now we need to close all handles of this type. | ||
names->second.clear(); | ||
} else if (!names->second.empty()) { // Add another name for this type. | ||
names->second.insert(handle_name); | ||
} // If we're already closing all handles of type then we're done. | ||
|
||
return SBOX_ALL_OK; | ||
} | ||
|
||
size_t HandleCloser::GetBufferSize() { | ||
size_t bytes_total = offsetof(HandleCloserInfo, handle_entries); | ||
|
||
for (HandleMap::iterator i = handles_to_close_.begin(); | ||
i != handles_to_close_.end(); ++i) { | ||
size_t bytes_entry = offsetof(HandleListEntry, handle_type) + | ||
(i->first.size() + 1) * sizeof(char16); | ||
for (HandleMap::mapped_type::iterator j = i->second.begin(); | ||
j != i->second.end(); ++j) { | ||
bytes_entry += ((*j).size() + 1) * sizeof(char16); | ||
} | ||
|
||
// Round up to the nearest multiple of sizeof(size_t). | ||
if (bytes_entry % sizeof(size_t)) | ||
bytes_entry = (bytes_entry & ~(sizeof(size_t) - 1)) + sizeof(size_t); | ||
|
||
bytes_total += bytes_entry; | ||
} | ||
|
||
return bytes_total; | ||
} | ||
|
||
bool HandleCloser::InitializeTargetHandles(TargetProcess* target) { | ||
// Do nothing on an empty list (global pointer already initialized to NULL). | ||
if (handles_to_close_.empty()) | ||
return true; | ||
|
||
size_t bytes_needed = GetBufferSize(); | ||
scoped_array<size_t> local_buffer( | ||
new size_t[bytes_needed / sizeof(size_t)]); | ||
|
||
if (!SetupHandleList(local_buffer.get(), bytes_needed)) | ||
return false; | ||
|
||
HANDLE child = target->Process(); | ||
|
||
// Allocate memory in the target process without specifying the address | ||
void* remote_data = ::VirtualAllocEx(child, NULL, bytes_needed, | ||
MEM_COMMIT, PAGE_READWRITE); | ||
if (NULL == remote_data) | ||
return false; | ||
|
||
// Copy the handle buffer over. | ||
SIZE_T bytes_written; | ||
BOOL result = ::WriteProcessMemory(child, remote_data, local_buffer.get(), | ||
bytes_needed, &bytes_written); | ||
if (!result || bytes_written != bytes_needed) { | ||
::VirtualFreeEx(child, remote_data, 0, MEM_RELEASE); | ||
return false; | ||
} | ||
|
||
g_handles_to_close = reinterpret_cast<HandleCloserInfo*>(remote_data); | ||
|
||
ResultCode rc = target->TransferVariable("g_handles_to_close", | ||
&g_handles_to_close, | ||
sizeof(g_handles_to_close)); | ||
|
||
return (SBOX_ALL_OK == rc); | ||
} | ||
|
||
bool HandleCloser::SetupHandleList(void* buffer, size_t buffer_bytes) { | ||
::ZeroMemory(buffer, buffer_bytes); | ||
HandleCloserInfo* handle_info = reinterpret_cast<HandleCloserInfo*>(buffer); | ||
handle_info->record_bytes = buffer_bytes; | ||
handle_info->num_handle_types = handles_to_close_.size(); | ||
|
||
char16* output = reinterpret_cast<char16*>(&handle_info->handle_entries[0]); | ||
char16* end = reinterpret_cast<char16*>( | ||
reinterpret_cast<char*>(buffer) + buffer_bytes); | ||
for (HandleMap::iterator i = handles_to_close_.begin(); | ||
i != handles_to_close_.end(); ++i) { | ||
if (output >= end) | ||
return false; | ||
HandleListEntry* list_entry = reinterpret_cast<HandleListEntry*>(output); | ||
output = &list_entry->handle_type[0]; | ||
|
||
// Copy the typename and set the offset and count. | ||
i->first._Copy_s(output, i->first.size(), i->first.size()); | ||
*(output += i->first.size()) = L'\0'; | ||
output++; | ||
list_entry->offset_to_names = reinterpret_cast<char*>(output) - | ||
reinterpret_cast<char*>(list_entry); | ||
list_entry->name_count = i->second.size(); | ||
|
||
// Copy the handle names. | ||
for (HandleMap::mapped_type::iterator j = i->second.begin(); | ||
j != i->second.end(); ++j) { | ||
output = std::copy((*j).begin(), (*j).end(), output) + 1; | ||
} | ||
|
||
// Round up to the nearest multiple of sizeof(size_t). | ||
output += (reinterpret_cast<size_t>(output) % sizeof(size_t)) / | ||
sizeof(char16); | ||
list_entry->record_bytes = reinterpret_cast<char*>(output) - | ||
reinterpret_cast<char*>(list_entry); | ||
} | ||
|
||
DCHECK(output == end); | ||
return output <= end; | ||
} | ||
|
||
bool GetHandleName(HANDLE handle, string16* handle_name) { | ||
static NtQueryObject QueryObject = NULL; | ||
if (!QueryObject) | ||
ResolveNTFunctionPtr("NtQueryObject", &QueryObject); | ||
|
||
ULONG size = MAX_PATH; | ||
scoped_ptr<UNICODE_STRING> name; | ||
NTSTATUS result; | ||
|
||
do { | ||
name.reset(reinterpret_cast<UNICODE_STRING*>(new BYTE[size])); | ||
result = QueryObject(handle, ObjectNameInformation, name.get(), | ||
size, &size); | ||
} while (result == STATUS_INFO_LENGTH_MISMATCH); | ||
|
||
if (NT_SUCCESS(result) && name->Buffer && name->Length) | ||
handle_name->assign(name->Buffer, name->Length / sizeof(wchar_t)); | ||
else | ||
handle_name->clear(); | ||
|
||
return NT_SUCCESS(result); | ||
} | ||
|
||
} // namespace sandbox |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
// Copyright (c) 2011 The Chromium Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#ifndef SANDBOX_SRC_HANDLE_CLOSER_H_ | ||
#define SANDBOX_SRC_HANDLE_CLOSER_H_ | ||
|
||
#include <map> | ||
#include <set> | ||
|
||
#include "base/basictypes.h" | ||
#include "base/string16.h" | ||
#include "sandbox/src/sandbox_types.h" | ||
#include "sandbox/src/target_process.h" | ||
|
||
namespace sandbox { | ||
|
||
// This is a map of handle-types to names that we need to close in the | ||
// target process. A null set means we need to close all handles of the | ||
// given type. | ||
typedef std::map<const string16, std::set<const string16> > HandleMap; | ||
|
||
// Type and set of corresponding handle names to close. | ||
struct HandleListEntry { | ||
size_t record_bytes; // Rounded to sizeof(size_t) bytes. | ||
size_t offset_to_names; // Nul terminated strings of name_count names. | ||
size_t name_count; | ||
char16 handle_type[1]; | ||
}; | ||
|
||
// Global parameters and a pointer to the list of entries. | ||
struct HandleCloserInfo { | ||
size_t record_bytes; // Rounded to sizeof(size_t) bytes. | ||
size_t num_handle_types; | ||
struct HandleListEntry handle_entries[1]; | ||
}; | ||
|
||
SANDBOX_INTERCEPT HandleCloserInfo* g_handle_closer_info; | ||
|
||
// Adds handles to close after lockdown. | ||
class HandleCloser { | ||
public: | ||
HandleCloser(); | ||
|
||
// Adds a handle that will be closed in the target process after lockdown. | ||
// A NULL value for handle_name indicates all handles of the specified type. | ||
// An empty string for handle_name indicates the handle is unnamed. | ||
ResultCode HandleCloser::AddHandle(const char16* handle_type, | ||
const char16* handle_name); | ||
|
||
// Serializes and copies the closer table into the target process. | ||
bool InitializeTargetHandles(TargetProcess* target); | ||
|
||
private: | ||
// Calculates the memory needed to copy the serialized handles list (rounded | ||
// to the nearest machine-word size). | ||
size_t GetBufferSize(); | ||
|
||
// Serializes the handle list into the target process. | ||
bool SetupHandleList(void* buffer, size_t buffer_bytes); | ||
|
||
HandleMap handles_to_close_; | ||
|
||
DISALLOW_COPY_AND_ASSIGN(HandleCloser); | ||
}; | ||
|
||
// Returns the object manager's name associated with a handle | ||
bool GetHandleName(HANDLE handle, string16* handle_name); | ||
|
||
} // namespace sandbox | ||
|
||
#endif // SANDBOX_SRC_HANDLE_CLOSER_H_ |
Oops, something went wrong.