1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/sandbox/win/src/process_thread_policy.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,242 @@ 1.4 +// Copyright (c) 2011 The Chromium Authors. All rights reserved. 1.5 +// Use of this source code is governed by a BSD-style license that can be 1.6 +// found in the LICENSE file. 1.7 + 1.8 +#include "sandbox/win/src/process_thread_policy.h" 1.9 + 1.10 +#include <string> 1.11 + 1.12 +#include "base/memory/scoped_ptr.h" 1.13 +#include "sandbox/win/src/ipc_tags.h" 1.14 +#include "sandbox/win/src/nt_internals.h" 1.15 +#include "sandbox/win/src/policy_engine_opcodes.h" 1.16 +#include "sandbox/win/src/policy_params.h" 1.17 +#include "sandbox/win/src/sandbox_types.h" 1.18 +#include "sandbox/win/src/win_utils.h" 1.19 + 1.20 +namespace { 1.21 + 1.22 +// These are the only safe rights that can be given to a sandboxed 1.23 +// process for the process created by the broker. All others are potential 1.24 +// vectors of privilege elevation. 1.25 +const DWORD kProcessRights = SYNCHRONIZE | 1.26 + PROCESS_QUERY_INFORMATION | 1.27 + PROCESS_QUERY_LIMITED_INFORMATION | 1.28 + PROCESS_TERMINATE | 1.29 + PROCESS_SUSPEND_RESUME; 1.30 + 1.31 +const DWORD kThreadRights = SYNCHRONIZE | 1.32 + THREAD_TERMINATE | 1.33 + THREAD_SUSPEND_RESUME | 1.34 + THREAD_QUERY_INFORMATION | 1.35 + THREAD_QUERY_LIMITED_INFORMATION | 1.36 + THREAD_SET_LIMITED_INFORMATION; 1.37 + 1.38 +// Creates a child process and duplicates the handles to 'target_process'. The 1.39 +// remaining parameters are the same as CreateProcess(). 1.40 +BOOL CreateProcessExWHelper(HANDLE target_process, BOOL give_full_access, 1.41 + LPCWSTR lpApplicationName, LPWSTR lpCommandLine, 1.42 + LPSECURITY_ATTRIBUTES lpProcessAttributes, 1.43 + LPSECURITY_ATTRIBUTES lpThreadAttributes, 1.44 + BOOL bInheritHandles, DWORD dwCreationFlags, 1.45 + LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, 1.46 + LPSTARTUPINFOW lpStartupInfo, 1.47 + LPPROCESS_INFORMATION lpProcessInformation) { 1.48 + if (!::CreateProcessW(lpApplicationName, lpCommandLine, lpProcessAttributes, 1.49 + lpThreadAttributes, bInheritHandles, dwCreationFlags, 1.50 + lpEnvironment, lpCurrentDirectory, lpStartupInfo, 1.51 + lpProcessInformation)) { 1.52 + return FALSE; 1.53 + } 1.54 + 1.55 + DWORD process_access = kProcessRights; 1.56 + DWORD thread_access = kThreadRights; 1.57 + if (give_full_access) { 1.58 + process_access = PROCESS_ALL_ACCESS; 1.59 + thread_access = THREAD_ALL_ACCESS; 1.60 + } 1.61 + if (!::DuplicateHandle(::GetCurrentProcess(), lpProcessInformation->hProcess, 1.62 + target_process, &lpProcessInformation->hProcess, 1.63 + process_access, FALSE, DUPLICATE_CLOSE_SOURCE)) { 1.64 + ::CloseHandle(lpProcessInformation->hThread); 1.65 + return FALSE; 1.66 + } 1.67 + if (!::DuplicateHandle(::GetCurrentProcess(), lpProcessInformation->hThread, 1.68 + target_process, &lpProcessInformation->hThread, 1.69 + thread_access, FALSE, DUPLICATE_CLOSE_SOURCE)) { 1.70 + return FALSE; 1.71 + } 1.72 + return TRUE; 1.73 +} 1.74 + 1.75 +} 1.76 + 1.77 +namespace sandbox { 1.78 + 1.79 +bool ProcessPolicy::GenerateRules(const wchar_t* name, 1.80 + TargetPolicy::Semantics semantics, 1.81 + LowLevelPolicy* policy) { 1.82 + scoped_ptr<PolicyRule> process; 1.83 + switch (semantics) { 1.84 + case TargetPolicy::PROCESS_MIN_EXEC: { 1.85 + process.reset(new PolicyRule(GIVE_READONLY)); 1.86 + break; 1.87 + }; 1.88 + case TargetPolicy::PROCESS_ALL_EXEC: { 1.89 + process.reset(new PolicyRule(GIVE_ALLACCESS)); 1.90 + break; 1.91 + }; 1.92 + default: { 1.93 + return false; 1.94 + }; 1.95 + } 1.96 + 1.97 + if (!process->AddStringMatch(IF, NameBased::NAME, name, CASE_INSENSITIVE)) { 1.98 + return false; 1.99 + } 1.100 + if (!policy->AddRule(IPC_CREATEPROCESSW_TAG, process.get())) { 1.101 + return false; 1.102 + } 1.103 + return true; 1.104 +} 1.105 + 1.106 +NTSTATUS ProcessPolicy::OpenThreadAction(const ClientInfo& client_info, 1.107 + uint32 desired_access, 1.108 + uint32 thread_id, 1.109 + HANDLE* handle) { 1.110 + *handle = NULL; 1.111 + 1.112 + NtOpenThreadFunction NtOpenThread = NULL; 1.113 + ResolveNTFunctionPtr("NtOpenThread", &NtOpenThread); 1.114 + 1.115 + OBJECT_ATTRIBUTES attributes = {0}; 1.116 + attributes.Length = sizeof(attributes); 1.117 + CLIENT_ID client_id = {0}; 1.118 + client_id.UniqueProcess = reinterpret_cast<PVOID>( 1.119 + static_cast<ULONG_PTR>(client_info.process_id)); 1.120 + client_id.UniqueThread = 1.121 + reinterpret_cast<PVOID>(static_cast<ULONG_PTR>(thread_id)); 1.122 + 1.123 + HANDLE local_handle; 1.124 + NTSTATUS status = NtOpenThread(&local_handle, desired_access, &attributes, 1.125 + &client_id); 1.126 + if (NT_SUCCESS(status)) { 1.127 + if (!::DuplicateHandle(::GetCurrentProcess(), local_handle, 1.128 + client_info.process, handle, 0, FALSE, 1.129 + DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) { 1.130 + ::CloseHandle(local_handle); 1.131 + return STATUS_ACCESS_DENIED; 1.132 + } 1.133 + } 1.134 + 1.135 + return status; 1.136 +} 1.137 + 1.138 +NTSTATUS ProcessPolicy::OpenProcessAction(const ClientInfo& client_info, 1.139 + uint32 desired_access, 1.140 + uint32 process_id, 1.141 + HANDLE* handle) { 1.142 + *handle = NULL; 1.143 + 1.144 + NtOpenProcessFunction NtOpenProcess = NULL; 1.145 + ResolveNTFunctionPtr("NtOpenProcess", &NtOpenProcess); 1.146 + 1.147 + if (client_info.process_id != process_id) 1.148 + return STATUS_ACCESS_DENIED; 1.149 + 1.150 + OBJECT_ATTRIBUTES attributes = {0}; 1.151 + attributes.Length = sizeof(attributes); 1.152 + CLIENT_ID client_id = {0}; 1.153 + client_id.UniqueProcess = reinterpret_cast<PVOID>( 1.154 + static_cast<ULONG_PTR>(client_info.process_id)); 1.155 + HANDLE local_handle; 1.156 + NTSTATUS status = NtOpenProcess(&local_handle, desired_access, &attributes, 1.157 + &client_id); 1.158 + if (NT_SUCCESS(status)) { 1.159 + if (!::DuplicateHandle(::GetCurrentProcess(), local_handle, 1.160 + client_info.process, handle, 0, FALSE, 1.161 + DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) { 1.162 + ::CloseHandle(local_handle); 1.163 + return STATUS_ACCESS_DENIED; 1.164 + } 1.165 + } 1.166 + 1.167 + return status; 1.168 +} 1.169 + 1.170 +NTSTATUS ProcessPolicy::OpenProcessTokenAction(const ClientInfo& client_info, 1.171 + HANDLE process, 1.172 + uint32 desired_access, 1.173 + HANDLE* handle) { 1.174 + *handle = NULL; 1.175 + NtOpenProcessTokenFunction NtOpenProcessToken = NULL; 1.176 + ResolveNTFunctionPtr("NtOpenProcessToken", &NtOpenProcessToken); 1.177 + 1.178 + if (CURRENT_PROCESS != process) 1.179 + return STATUS_ACCESS_DENIED; 1.180 + 1.181 + HANDLE local_handle; 1.182 + NTSTATUS status = NtOpenProcessToken(client_info.process, desired_access, 1.183 + &local_handle); 1.184 + if (NT_SUCCESS(status)) { 1.185 + if (!::DuplicateHandle(::GetCurrentProcess(), local_handle, 1.186 + client_info.process, handle, 0, FALSE, 1.187 + DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) { 1.188 + ::CloseHandle(local_handle); 1.189 + return STATUS_ACCESS_DENIED; 1.190 + } 1.191 + } 1.192 + return status; 1.193 +} 1.194 + 1.195 +NTSTATUS ProcessPolicy::OpenProcessTokenExAction(const ClientInfo& client_info, 1.196 + HANDLE process, 1.197 + uint32 desired_access, 1.198 + uint32 attributes, 1.199 + HANDLE* handle) { 1.200 + *handle = NULL; 1.201 + NtOpenProcessTokenExFunction NtOpenProcessTokenEx = NULL; 1.202 + ResolveNTFunctionPtr("NtOpenProcessTokenEx", &NtOpenProcessTokenEx); 1.203 + 1.204 + if (CURRENT_PROCESS != process) 1.205 + return STATUS_ACCESS_DENIED; 1.206 + 1.207 + HANDLE local_handle; 1.208 + NTSTATUS status = NtOpenProcessTokenEx(client_info.process, desired_access, 1.209 + attributes, &local_handle); 1.210 + if (NT_SUCCESS(status)) { 1.211 + if (!::DuplicateHandle(::GetCurrentProcess(), local_handle, 1.212 + client_info.process, handle, 0, FALSE, 1.213 + DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) { 1.214 + ::CloseHandle(local_handle); 1.215 + return STATUS_ACCESS_DENIED; 1.216 + } 1.217 + } 1.218 + return status; 1.219 +} 1.220 + 1.221 +DWORD ProcessPolicy::CreateProcessWAction(EvalResult eval_result, 1.222 + const ClientInfo& client_info, 1.223 + const std::wstring &app_name, 1.224 + const std::wstring &command_line, 1.225 + PROCESS_INFORMATION* process_info) { 1.226 + // The only action supported is ASK_BROKER which means create the process. 1.227 + if (GIVE_ALLACCESS != eval_result && GIVE_READONLY != eval_result) { 1.228 + return ERROR_ACCESS_DENIED; 1.229 + } 1.230 + 1.231 + STARTUPINFO startup_info = {0}; 1.232 + startup_info.cb = sizeof(startup_info); 1.233 + scoped_ptr_malloc<wchar_t> cmd_line(_wcsdup(command_line.c_str())); 1.234 + 1.235 + BOOL should_give_full_access = (GIVE_ALLACCESS == eval_result); 1.236 + if (!CreateProcessExWHelper(client_info.process, should_give_full_access, 1.237 + app_name.c_str(), cmd_line.get(), NULL, NULL, 1.238 + FALSE, 0, NULL, NULL, &startup_info, 1.239 + process_info)) { 1.240 + return ERROR_ACCESS_DENIED; 1.241 + } 1.242 + return ERROR_SUCCESS; 1.243 +} 1.244 + 1.245 +} // namespace sandbox