diff options
author | jschuh@chromium.org <jschuh@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-07-19 22:21:26 +0000 |
---|---|---|
committer | jschuh@chromium.org <jschuh@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-07-19 22:21:26 +0000 |
commit | d9b5d1768be62ec8584fae70d15d0b902a790abc (patch) | |
tree | 7bceb03f01ee7839dc04b3553527ee1be1284086 /sandbox | |
parent | e7007a7941e75d985b9b78ef5a80b9743f890809 (diff) | |
download | chromium_src-d9b5d1768be62ec8584fae70d15d0b902a790abc.zip chromium_src-d9b5d1768be62ec8584fae70d15d0b902a790abc.tar.gz chromium_src-d9b5d1768be62ec8584fae70d15d0b902a790abc.tar.bz2 |
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@93113 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'sandbox')
-rw-r--r-- | sandbox/sandbox.gyp | 5 | ||||
-rw-r--r-- | sandbox/src/handle_closer.cc | 164 | ||||
-rw-r--r-- | sandbox/src/handle_closer.h | 72 | ||||
-rw-r--r-- | sandbox/src/handle_closer_agent.cc | 124 | ||||
-rw-r--r-- | sandbox/src/handle_closer_agent.h | 37 | ||||
-rw-r--r-- | sandbox/src/handle_closer_test.cc | 125 | ||||
-rw-r--r-- | sandbox/src/sandbox_policy.h | 8 | ||||
-rw-r--r-- | sandbox/src/sandbox_policy_base.cc | 9 | ||||
-rw-r--r-- | sandbox/src/sandbox_policy_base.h | 24 | ||||
-rw-r--r-- | sandbox/src/sandbox_types.h | 3 | ||||
-rw-r--r-- | sandbox/src/target_services.cc | 20 |
11 files changed, 582 insertions, 9 deletions
diff --git a/sandbox/sandbox.gyp b/sandbox/sandbox.gyp index a9ea6f4..6832c8a 100644 --- a/sandbox/sandbox.gyp +++ b/sandbox/sandbox.gyp @@ -33,6 +33,10 @@ 'src/filesystem_interception.h', 'src/filesystem_policy.cc', 'src/filesystem_policy.h', + 'src/handle_closer.cc', + 'src/handle_closer.h', + 'src/handle_closer_agent.cc', + 'src/handle_closer_agent.h', 'src/handle_table.cc', 'src/handle_table.h', 'src/interception.cc', @@ -283,6 +287,7 @@ 'src/dep_test.cc', 'src/file_policy_test.cc', 'tests/integration_tests/integration_tests_test.cc', + 'src/handle_closer_test.cc', 'src/integrity_level_test.cc', 'src/ipc_ping_test.cc', 'src/named_pipe_policy_test.cc', diff --git a/sandbox/src/handle_closer.cc b/sandbox/src/handle_closer.cc new file mode 100644 index 0000000..ee201de --- /dev/null +++ b/sandbox/src/handle_closer.cc @@ -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 diff --git a/sandbox/src/handle_closer.h b/sandbox/src/handle_closer.h new file mode 100644 index 0000000..7252968 --- /dev/null +++ b/sandbox/src/handle_closer.h @@ -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_ diff --git a/sandbox/src/handle_closer_agent.cc b/sandbox/src/handle_closer_agent.cc new file mode 100644 index 0000000..b640c08 --- /dev/null +++ b/sandbox/src/handle_closer_agent.cc @@ -0,0 +1,124 @@ +// 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_agent.h" + +#include "base/logging.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 = NULL; + +bool HandleCloserAgent::NeedsHandlesClosed() { + return g_handles_to_close != NULL; +} + +// Reads g_handles_to_close and creates the lookup map. +void HandleCloserAgent::InitializeHandlesToClose() { + CHECK(g_handles_to_close != NULL); + + // Grab the header. + HandleListEntry* entry = g_handles_to_close->handle_entries; + for (size_t i = 0; i < g_handles_to_close->num_handle_types; ++i) { + // Set the type name. + char16* input = entry->handle_type; + HandleMap::mapped_type& handle_names = handles_to_close_[input]; + input = reinterpret_cast<char16*>(reinterpret_cast<char*>(entry) + + entry->offset_to_names); + // Grab all the handle names. + for (size_t j = 0; j < entry->name_count; ++j) { + std::pair<HandleMap::mapped_type::iterator, bool> name + = handle_names.insert(input); + CHECK(name.second); + input += name.first->size() + 1; + } + + // Move on to the next entry. + entry = reinterpret_cast<HandleListEntry*>(reinterpret_cast<char*>(entry) + + entry->record_bytes); + + DCHECK(reinterpret_cast<char16*>(entry) >= input); + DCHECK(reinterpret_cast<char16*>(entry) - input < + sizeof(size_t) / sizeof(char16)); + } + + // Clean up the memory we copied over. + ::VirtualFree(g_handles_to_close, 0, MEM_RELEASE); + g_handles_to_close = NULL; +} + +bool HandleCloserAgent::CloseHandles() { + DWORD handle_count = UINT_MAX; + const int kInvalidHandleThreshold = 100; + const size_t kHandleOffset = sizeof(HANDLE); + + if (!::GetProcessHandleCount(::GetCurrentProcess(), &handle_count)) + return false; + + static NtQueryObject QueryObject = NULL; + if (!QueryObject) + ResolveNTFunctionPtr("NtQueryObject", &QueryObject); + + // Set up buffers for the type info and the name. + std::vector<BYTE> type_info_buffer(sizeof(OBJECT_TYPE_INFORMATION) + + 32 * sizeof(wchar_t)); + OBJECT_TYPE_INFORMATION* type_info = + reinterpret_cast<OBJECT_TYPE_INFORMATION*>(&(type_info_buffer[0])); + string16 handle_name; + HANDLE handle = NULL; + int invalid_count = 0; + + // Keep incrementing until we hit the number of handles reported by + // GetProcessHandleCount(). If we hit a very long sequence of invalid + // handles we assume that we've run past the end of the table. + while (handle_count && invalid_count < kInvalidHandleThreshold) { + reinterpret_cast<size_t&>(handle) += kHandleOffset; + NTSTATUS rc; + + // Get the type name, reusing the buffer. + ULONG size = static_cast<ULONG>(type_info_buffer.size()); + rc = QueryObject(handle, ObjectTypeInformation, type_info, size, &size); + while (rc == STATUS_INFO_LENGTH_MISMATCH) { + type_info_buffer.resize(size + sizeof(wchar_t)); + type_info = reinterpret_cast<OBJECT_TYPE_INFORMATION*>( + &(type_info_buffer[0])); + rc = QueryObject(handle, ObjectTypeInformation, type_info, size, &size); + // Leave padding for the nul terminator. + if (NT_SUCCESS(0) && size == type_info_buffer.size()) + rc = STATUS_INFO_LENGTH_MISMATCH; + } + if (!NT_SUCCESS(rc)) { + ++invalid_count; + continue; + } + + --handle_count; + type_info->Name.Buffer[type_info->Name.Length / sizeof(wchar_t)] = L'\0'; + + // Check if we're looking for this type of handle. + HandleMap::iterator result = + handles_to_close_.find(type_info->Name.Buffer); + if (result != handles_to_close_.end()) { + HandleMap::mapped_type& names = result->second; + // Empty set means close all handles of this type; otherwise check name. + if (!names.empty()) { + // Move on to the next handle if this name doesn't match. + if (!GetHandleName(handle, &handle_name) || !names.count(handle_name)) + continue; + } + + if (!::SetHandleInformation(handle, HANDLE_FLAG_PROTECT_FROM_CLOSE, 0)) + return false; + if (!::CloseHandle(handle)) + return false; + } + } + + return true; +} + +} // namespace sandbox diff --git a/sandbox/src/handle_closer_agent.h b/sandbox/src/handle_closer_agent.h new file mode 100644 index 0000000..c74987c --- /dev/null +++ b/sandbox/src/handle_closer_agent.h @@ -0,0 +1,37 @@ +// 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_AGENT_H_ +#define SANDBOX_SRC_HANDLE_CLOSER_AGENT_H_ + +#include "base/basictypes.h" +#include "base/string16.h" +#include "sandbox/src/handle_closer.h" +#include "sandbox/src/sandbox_types.h" + +namespace sandbox { + +// Target process code to close the handle list copied over from the broker. +class HandleCloserAgent { + public: + HandleCloserAgent() {} + + // Reads the serialized list from the broker and creates the lookup map. + void InitializeHandlesToClose(); + + // Closes any handles matching those in the lookup map. + bool CloseHandles(); + + // True if we have handles waiting to be closed + static bool NeedsHandlesClosed(); + + private: + HandleMap handles_to_close_; + + DISALLOW_COPY_AND_ASSIGN(HandleCloserAgent); +}; + +} // namespace sandbox + +#endif // SANDBOX_SRC_HANDLE_CLOSER_AGENT_H_ diff --git a/sandbox/src/handle_closer_test.cc b/sandbox/src/handle_closer_test.cc new file mode 100644 index 0000000..4e2bf99 --- /dev/null +++ b/sandbox/src/handle_closer_test.cc @@ -0,0 +1,125 @@ +// 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 "base/stringprintf.h" +#include "base/win/scoped_handle.h" +#include "sandbox/src/handle_closer_agent.h" +#include "sandbox/src/sandbox.h" +#include "sandbox/src/sandbox_factory.h" +#include "sandbox/src/target_services.h" +#include "sandbox/tests/common/controller.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +// Returns a handle to a unique marker file that can be retrieved between runs. +HANDLE GetMarkerFile() { + wchar_t path_buffer[MAX_PATH + 1]; + CHECK(::GetTempPath(MAX_PATH, path_buffer)); + string16 marker_path = path_buffer; + marker_path += L"\\sbox_marker_"; + + // Generate a unique value from the exe's size and timestamp. + CHECK(::GetModuleFileName(NULL, path_buffer, MAX_PATH)); + base::win::ScopedHandle module(::CreateFile(path_buffer, + FILE_READ_ATTRIBUTES, FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)); + CHECK(module.IsValid()); + FILETIME timestamp; + CHECK(::GetFileTime(module, ×tamp, NULL, NULL)); + marker_path += base::StringPrintf(L"%08x%08x%08x", + ::GetFileSize(module, NULL), + timestamp.dwLowDateTime, + timestamp.dwHighDateTime); + + // Make the file delete-on-close so cleanup is automatic. + return CreateFile(marker_path.c_str(), FILE_ALL_ACCESS, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, OPEN_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, NULL); +} + +} // namespace + +namespace sandbox { + +// Checks for the presence of a file (in object path form). +// Format: CheckForFileHandle \path\to\file (Y|N) +// - Y or N depending if the file should exist or not. +SBOX_TESTS_COMMAND int CheckForFileHandle(int argc, wchar_t **argv) { + if (argc != 2) + return SBOX_TEST_FAILED_TO_RUN_TEST; + bool should_find = argv[1][0] == L'Y'; + if (argv[1][1] != L'\0' || !should_find && argv[1][0] != L'N') + return SBOX_TEST_FAILED_TO_RUN_TEST; + + static int state = BEFORE_INIT; + switch (state++) { + case BEFORE_INIT: + // Create a unique marker file that is open while the test is running. + // The handle leaks, but it will be closed by the test or on exit. + EXPECT_NE(GetMarkerFile(), INVALID_HANDLE_VALUE); + return SBOX_TEST_SUCCEEDED; + + case AFTER_REVERT: { + // Brute force the handle table to find what we're looking for. + DWORD handle_count = UINT_MAX; + const int kInvalidHandleThreshold = 100; + const size_t kHandleOffset = sizeof(HANDLE); + HANDLE handle = NULL; + int invalid_count = 0; + string16 handle_name; + + if (!::GetProcessHandleCount(::GetCurrentProcess(), &handle_count)) + return SBOX_TEST_FAILED_TO_RUN_TEST; + + while (handle_count && invalid_count < kInvalidHandleThreshold) { + reinterpret_cast<size_t&>(handle) += kHandleOffset; + if (GetHandleName(handle, &handle_name)) { + if (handle_name == argv[0]) + return should_find ? SBOX_TEST_SUCCEEDED : SBOX_TEST_FAILED; + --handle_count; + } else { + ++invalid_count; + } + } + + return should_find ? SBOX_TEST_FAILED : SBOX_TEST_SUCCEEDED; + } + } + + return SBOX_TEST_SUCCEEDED; +} + +TEST(HandleCloserTest, CheckForMarkerFile) { + TestRunner runner; + runner.SetTimeout(2000); + runner.SetTestState(EVERY_STATE); + sandbox::TargetPolicy* policy = runner.GetPolicy(); + + base::win::ScopedHandle marker(GetMarkerFile()); + EXPECT_TRUE(marker.IsValid()); + string16 handle_name; + EXPECT_TRUE(sandbox::GetHandleName(marker, &handle_name)); + string16 command = string16(L"CheckForFileHandle ") + handle_name + L" Y"; + EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(command.c_str())) << + "Could not find: " << handle_name; +} + +TEST(HandleCloserTest, CloseMarkerFile) { + TestRunner runner; + runner.SetTimeout(2000); + runner.SetTestState(EVERY_STATE); + sandbox::TargetPolicy* policy = runner.GetPolicy(); + + base::win::ScopedHandle marker(GetMarkerFile()); + EXPECT_TRUE(marker.IsValid()); + string16 handle_name; + EXPECT_TRUE(sandbox::GetHandleName(marker, &handle_name)); + policy->AddKernelObjectToClose(L"File", handle_name.c_str()); + string16 command = string16(L"CheckForFileHandle ") + handle_name + L" N"; + EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(command.c_str())) << + "Failed closing: " << handle_name; +} + +} // namespace sandbox diff --git a/sandbox/src/sandbox_policy.h b/sandbox/src/sandbox_policy.h index 716cefa..4f21158 100644 --- a/sandbox/src/sandbox_policy.h +++ b/sandbox/src/sandbox_policy.h @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2006-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. @@ -172,6 +172,12 @@ class TargetPolicy { // a chance to initialize itself. Typically, dlls that cause the target // to crash go here. virtual ResultCode AddDllToUnload(const wchar_t* dll_name) = 0; + + // 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. + virtual ResultCode AddKernelObjectToClose(const wchar_t* handle_type, + const wchar_t* handle_name) = 0; }; } // namespace sandbox diff --git a/sandbox/src/sandbox_policy_base.cc b/sandbox/src/sandbox_policy_base.cc index ec9ffac..8e25b71 100644 --- a/sandbox/src/sandbox_policy_base.cc +++ b/sandbox/src/sandbox_policy_base.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2006-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. @@ -227,6 +227,9 @@ bool PolicyBase::AddTarget(TargetProcess* target) { if (!SetupAllInterceptions(target)) return false; + if (!SetupHandleCloser(target)) + return false; + // Initialize the sandbox infrastructure for the target. if (ERROR_SUCCESS != target->Init(this, policy_, kIPCMemSize, kPolMemSize)) return false; @@ -448,4 +451,8 @@ bool PolicyBase::SetupAllInterceptions(TargetProcess* target) { return SetupNtdllImports(target); } +bool PolicyBase::SetupHandleCloser(TargetProcess* target) { + return handle_closer_.InitializeTargetHandles(target); +} + } // namespace sandbox diff --git a/sandbox/src/sandbox_policy_base.h b/sandbox/src/sandbox_policy_base.h index 6294ed8..b9afc6e 100644 --- a/sandbox/src/sandbox_policy_base.h +++ b/sandbox/src/sandbox_policy_base.h @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2006-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. @@ -7,15 +7,17 @@ #include <windows.h> #include <list> +#include <vector> #include "base/basictypes.h" +#include "base/string16.h" +#include "sandbox/src/crosscall_server.h" +#include "sandbox/src/handle_closer.h" #include "sandbox/src/ipc_tags.h" +#include "sandbox/src/policy_engine_opcodes.h" +#include "sandbox/src/policy_engine_params.h" #include "sandbox/src/sandbox_policy.h" #include "sandbox/src/win_utils.h" -#include "sandbox/src/crosscall_server.h" - -#include "sandbox/src/policy_engine_params.h" -#include "sandbox/src/policy_engine_opcodes.h" namespace sandbox { @@ -100,6 +102,11 @@ class PolicyBase : public Dispatcher, public TargetPolicy { return SBOX_ALL_OK; } + virtual ResultCode AddKernelObjectToClose(const char16* handle_type, + const char16* handle_name) { + return handle_closer_.AddHandle(handle_type, handle_name); + } + // Creates a Job object with the level specified in a previous call to // SetJobLevel(). Returns the standard windows of ::GetLastError(). DWORD MakeJobObject(HANDLE* job); @@ -134,6 +141,9 @@ class PolicyBase : public Dispatcher, public TargetPolicy { // Sets up interceptions for a new target. bool SetupAllInterceptions(TargetProcess* target); + // Sets up the handle closer for a new target. + bool SetupHandleCloser(TargetProcess* target); + // This lock synchronizes operations on the targets_ collection. CRITICAL_SECTION lock_; // Maintains the list of target process associated with this policy. @@ -163,6 +173,10 @@ class PolicyBase : public Dispatcher, public TargetPolicy { bool relaxed_interceptions_; // The list of dlls to unload in the target process. std::vector<std::wstring> blacklisted_dlls_; + // 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. + HandleCloser handle_closer_; static HDESK alternate_desktop_handle_; static HWINSTA alternate_winstation_handle_; diff --git a/sandbox/src/sandbox_types.h b/sandbox/src/sandbox_types.h index 898f107..dee1838 100644 --- a/sandbox/src/sandbox_types.h +++ b/sandbox/src/sandbox_types.h @@ -47,7 +47,8 @@ enum TerminationCodes { SBOX_FATAL_INTEGRITY = 7006, // Could not set the integrity level. SBOX_FATAL_DROPTOKEN = 7007, // Could not lower the token. SBOX_FATAL_FLUSHANDLES = 7008, // Failed to flush registry handles. - SBOX_FATAL_CACHEDISABLE = 7009 // Failed to forbid HCKU caching. + SBOX_FATAL_CACHEDISABLE = 7009, // Failed to forbid HCKU caching. + SBOX_FATAL_CLOSEHANDLES = 7010 // Failed to close pending handles. }; class TargetServices; diff --git a/sandbox/src/target_services.cc b/sandbox/src/target_services.cc index 72f6d4c..9b91a1c 100644 --- a/sandbox/src/target_services.cc +++ b/sandbox/src/target_services.cc @@ -1,11 +1,14 @@ -// Copyright (c) 2006-2010 The Chromium Authors. All rights reserved. +// 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/target_services.h" +#include <process.h> + #include "base/basictypes.h" #include "sandbox/src/crosscall_client.h" +#include "sandbox/src/handle_closer_agent.h" #include "sandbox/src/ipc_tags.h" #include "sandbox/src/restricted_token_utils.h" #include "sandbox/src/sandbox.h" @@ -38,6 +41,19 @@ bool FlushCachedRegHandles() { FlushRegKey(HKEY_USERS)); } +// Checks if we have handle entries pending and runs the closer. +bool CloseOpenHandles() { + if (sandbox::HandleCloserAgent::NeedsHandlesClosed()) { + sandbox::HandleCloserAgent handle_closer; + + handle_closer.InitializeHandlesToClose(); + if (!handle_closer.CloseHandles()) + return false; + } + + return true; +} + } // namespace namespace sandbox { @@ -67,6 +83,8 @@ void TargetServicesBase::LowerToken() { ::TerminateProcess(::GetCurrentProcess(), SBOX_FATAL_FLUSHANDLES); if (ERROR_SUCCESS != ::RegDisablePredefinedCache()) ::TerminateProcess(::GetCurrentProcess(), SBOX_FATAL_CACHEDISABLE); + if (!CloseOpenHandles()) + ::TerminateProcess(::GetCurrentProcess(), SBOX_FATAL_CLOSEHANDLES); } ProcessState* TargetServicesBase::GetState() { |