diff options
Diffstat (limited to 'sandbox/src/process_thread_policy.cc')
-rw-r--r-- | sandbox/src/process_thread_policy.cc | 276 |
1 files changed, 276 insertions, 0 deletions
diff --git a/sandbox/src/process_thread_policy.cc b/sandbox/src/process_thread_policy.cc new file mode 100644 index 0000000..07f8182 --- /dev/null +++ b/sandbox/src/process_thread_policy.cc @@ -0,0 +1,276 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "sandbox/src/process_thread_policy.h" + +#include <string> + +#include "base/logging.h" +#include "base/scoped_ptr.h" +#include "sandbox/src/ipc_tags.h" +#include "sandbox/src/nt_internals.h" +#include "sandbox/src/policy_engine_opcodes.h" +#include "sandbox/src/policy_params.h" +#include "sandbox/src/sandbox_types.h" +#include "sandbox/src/win_utils.h" + +namespace { + +// These are the only safe rights that can be given to a sandboxed +// process for the process created by the broker. All others are potential +// vectors of privilege elevation. +const DWORD kProcessRights = SYNCHRONIZE | + PROCESS_QUERY_INFORMATION | + PROCESS_QUERY_LIMITED_INFORMATION | + PROCESS_TERMINATE | + PROCESS_SUSPEND_RESUME; + +const DWORD kThreadRights = SYNCHRONIZE | + THREAD_TERMINATE | + THREAD_SUSPEND_RESUME | + THREAD_QUERY_INFORMATION | + THREAD_QUERY_LIMITED_INFORMATION | + THREAD_SET_LIMITED_INFORMATION; + +// Creates a child process and duplicates the handles to 'target_process'. The +// remaining parameters are the same as CreateProcess(). +BOOL CreateProcessExWHelper(HANDLE target_process, BOOL give_full_access, + LPCWSTR lpApplicationName, LPWSTR lpCommandLine, + LPSECURITY_ATTRIBUTES lpProcessAttributes, + LPSECURITY_ATTRIBUTES lpThreadAttributes, + BOOL bInheritHandles, DWORD dwCreationFlags, + LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, + LPSTARTUPINFOW lpStartupInfo, + LPPROCESS_INFORMATION lpProcessInformation) { + if (!::CreateProcessW(lpApplicationName, lpCommandLine, lpProcessAttributes, + lpThreadAttributes, bInheritHandles, dwCreationFlags, + lpEnvironment, lpCurrentDirectory, lpStartupInfo, + lpProcessInformation)) { + return FALSE; + } + + DWORD process_access = kProcessRights; + DWORD thread_access = kThreadRights; + if (give_full_access) { + process_access = PROCESS_ALL_ACCESS; + thread_access = THREAD_ALL_ACCESS; + } + if (!::DuplicateHandle(::GetCurrentProcess(), lpProcessInformation->hProcess, + target_process, &lpProcessInformation->hProcess, + process_access, FALSE, DUPLICATE_CLOSE_SOURCE)) { + ::CloseHandle(lpProcessInformation->hThread); + return FALSE; + } + if (!::DuplicateHandle(::GetCurrentProcess(), lpProcessInformation->hThread, + target_process, &lpProcessInformation->hThread, + thread_access, FALSE, DUPLICATE_CLOSE_SOURCE)) { + return FALSE; + } + return TRUE; +} + +} + +namespace sandbox { + +bool ProcessPolicy::GenerateRules(const wchar_t* name, + TargetPolicy::Semantics semantics, + LowLevelPolicy* policy) { + scoped_ptr<PolicyRule> process; + switch (semantics) { + case TargetPolicy::PROCESS_MIN_EXEC: { + process.reset(new PolicyRule(GIVE_READONLY)); + break; + }; + case TargetPolicy::PROCESS_ALL_EXEC: { + process.reset(new PolicyRule(GIVE_ALLACCESS)); + break; + }; + default: { + return false; + }; + } + + if (!process->AddStringMatch(IF, NameBased::NAME, name, CASE_INSENSITIVE)) { + return false; + } + if (!policy->AddRule(IPC_CREATEPROCESSW_TAG, process.get())) { + return false; + } + return true; +} + +NTSTATUS ProcessPolicy::OpenThreadAction(const ClientInfo& client_info, + uint32 desired_access, + uint32 thread_id, + HANDLE *handle) { + *handle = NULL; + + NtOpenThreadFunction NtOpenThread = NULL; + ResolveNTFunctionPtr("NtOpenThread", &NtOpenThread); + + OBJECT_ATTRIBUTES attributes = {0}; + attributes.Length = sizeof(attributes); + CLIENT_ID client_id = {0}; + client_id.UniqueProcess = reinterpret_cast<PVOID>( + static_cast<ULONG_PTR>(client_info.process_id)); + client_id.UniqueThread = + reinterpret_cast<PVOID>(static_cast<ULONG_PTR>(thread_id)); + + HANDLE local_handle; + NTSTATUS status = NtOpenThread(&local_handle, desired_access, &attributes, + &client_id); + if (NT_SUCCESS(status)) { + if (!::DuplicateHandle(::GetCurrentProcess(), local_handle, + client_info.process, handle, 0, FALSE, + DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) { + ::CloseHandle(local_handle); + return STATUS_ACCESS_DENIED; + } + } + + return status; +} + +NTSTATUS ProcessPolicy::OpenProcessAction(const ClientInfo& client_info, + uint32 desired_access, + uint32 process_id, + HANDLE *handle) { + *handle = NULL; + + NtOpenProcessFunction NtOpenProcess = NULL; + ResolveNTFunctionPtr("NtOpenProcess", &NtOpenProcess); + + if (client_info.process_id != process_id) + return STATUS_ACCESS_DENIED; + + OBJECT_ATTRIBUTES attributes = {0}; + attributes.Length = sizeof(attributes); + CLIENT_ID client_id = {0}; + client_id.UniqueProcess = reinterpret_cast<PVOID>( + static_cast<ULONG_PTR>(client_info.process_id)); + HANDLE local_handle; + NTSTATUS status = NtOpenProcess(&local_handle, desired_access, &attributes, + &client_id); + if (NT_SUCCESS(status)) { + if (!::DuplicateHandle(::GetCurrentProcess(), local_handle, + client_info.process, handle, 0, FALSE, + DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) { + ::CloseHandle(local_handle); + return STATUS_ACCESS_DENIED; + } + } + + return status; +} + +NTSTATUS ProcessPolicy::OpenProcessTokenAction(const ClientInfo& client_info, + uint32 process_requested, + uint32 desired_access, + HANDLE *handle) { + *handle = NULL; + + NtOpenProcessTokenFunction NtOpenProcessToken = NULL; + ResolveNTFunctionPtr("NtOpenProcessToken", &NtOpenProcessToken); + + HANDLE process = reinterpret_cast<HANDLE>( + static_cast<ULONG_PTR>(process_requested)); + if (CURRENT_PROCESS != process) + return STATUS_ACCESS_DENIED; + + HANDLE local_handle; + NTSTATUS status = NtOpenProcessToken(client_info.process, desired_access, + &local_handle); + if (NT_SUCCESS(status)) { + if (!::DuplicateHandle(::GetCurrentProcess(), local_handle, + client_info.process, handle, 0, FALSE, + DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) { + ::CloseHandle(local_handle); + return STATUS_ACCESS_DENIED; + } + } + + return status; +} + +NTSTATUS ProcessPolicy::OpenProcessTokenExAction(const ClientInfo& client_info, + uint32 process_requested, + uint32 desired_access, + uint32 attributes, + HANDLE *handle) { + *handle = NULL; + NtOpenProcessTokenExFunction NtOpenProcessTokenEx = NULL; + ResolveNTFunctionPtr("NtOpenProcessTokenEx", &NtOpenProcessTokenEx); + + HANDLE process = reinterpret_cast<HANDLE>( + static_cast<ULONG_PTR>(process_requested)); + if (CURRENT_PROCESS != process) + return STATUS_ACCESS_DENIED; + + HANDLE local_handle; + NTSTATUS status = NtOpenProcessTokenEx(client_info.process, desired_access, + attributes, &local_handle); + if (NT_SUCCESS(status)) { + if (!::DuplicateHandle(::GetCurrentProcess(), local_handle, + client_info.process, handle, 0, FALSE, + DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) { + ::CloseHandle(local_handle); + return STATUS_ACCESS_DENIED; + } + } + + return status; +} + +DWORD ProcessPolicy::CreateProcessWAction(EvalResult eval_result, + const ClientInfo& client_info, + const std::wstring &app_name, + const std::wstring &command_line, + PROCESS_INFORMATION* process_info) { + // The only action supported is ASK_BROKER which means create the process. + if (GIVE_ALLACCESS != eval_result && GIVE_READONLY != eval_result) { + return ERROR_ACCESS_DENIED; + } + + STARTUPINFO startup_info = {0}; + startup_info.cb = sizeof(startup_info); + scoped_ptr_malloc<wchar_t> cmd_line(_wcsdup(command_line.c_str())); + + BOOL should_give_full_access = (GIVE_ALLACCESS == eval_result); + if (!CreateProcessExWHelper(client_info.process, should_give_full_access, + app_name.c_str(), cmd_line.get(), NULL, NULL, + FALSE, 0, NULL, NULL, &startup_info, + process_info)) { + return ERROR_ACCESS_DENIED; + } + return ERROR_SUCCESS; +} + +} // namespace sandbox + |