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/process_thread_policy.h" 6 7 #include <string> 8 9 #include "base/memory/scoped_ptr.h" 10 #include "sandbox/win/src/ipc_tags.h" 11 #include "sandbox/win/src/nt_internals.h" 12 #include "sandbox/win/src/policy_engine_opcodes.h" 13 #include "sandbox/win/src/policy_params.h" 14 #include "sandbox/win/src/sandbox_types.h" 15 #include "sandbox/win/src/win_utils.h" 16 17 namespace { 18 19 // These are the only safe rights that can be given to a sandboxed 20 // process for the process created by the broker. All others are potential 21 // vectors of privilege elevation. 22 const DWORD kProcessRights = SYNCHRONIZE | 23 PROCESS_QUERY_INFORMATION | 24 PROCESS_QUERY_LIMITED_INFORMATION | 25 PROCESS_TERMINATE | 26 PROCESS_SUSPEND_RESUME; 27 28 const DWORD kThreadRights = SYNCHRONIZE | 29 THREAD_TERMINATE | 30 THREAD_SUSPEND_RESUME | 31 THREAD_QUERY_INFORMATION | 32 THREAD_QUERY_LIMITED_INFORMATION | 33 THREAD_SET_LIMITED_INFORMATION; 34 35 // Creates a child process and duplicates the handles to 'target_process'. The 36 // remaining parameters are the same as CreateProcess(). 37 BOOL CreateProcessExWHelper(HANDLE target_process, BOOL give_full_access, 38 LPCWSTR lpApplicationName, LPWSTR lpCommandLine, 39 LPSECURITY_ATTRIBUTES lpProcessAttributes, 40 LPSECURITY_ATTRIBUTES lpThreadAttributes, 41 BOOL bInheritHandles, DWORD dwCreationFlags, 42 LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, 43 LPSTARTUPINFOW lpStartupInfo, 44 LPPROCESS_INFORMATION lpProcessInformation) { 45 if (!::CreateProcessW(lpApplicationName, lpCommandLine, lpProcessAttributes, 46 lpThreadAttributes, bInheritHandles, dwCreationFlags, 47 lpEnvironment, lpCurrentDirectory, lpStartupInfo, 48 lpProcessInformation)) { 49 return FALSE; 50 } 51 52 DWORD process_access = kProcessRights; 53 DWORD thread_access = kThreadRights; 54 if (give_full_access) { 55 process_access = PROCESS_ALL_ACCESS; 56 thread_access = THREAD_ALL_ACCESS; 57 } 58 if (!::DuplicateHandle(::GetCurrentProcess(), lpProcessInformation->hProcess, 59 target_process, &lpProcessInformation->hProcess, 60 process_access, FALSE, DUPLICATE_CLOSE_SOURCE)) { 61 ::CloseHandle(lpProcessInformation->hThread); 62 return FALSE; 63 } 64 if (!::DuplicateHandle(::GetCurrentProcess(), lpProcessInformation->hThread, 65 target_process, &lpProcessInformation->hThread, 66 thread_access, FALSE, DUPLICATE_CLOSE_SOURCE)) { 67 return FALSE; 68 } 69 return TRUE; 70 } 71 72 } 73 74 namespace sandbox { 75 76 bool ProcessPolicy::GenerateRules(const wchar_t* name, 77 TargetPolicy::Semantics semantics, 78 LowLevelPolicy* policy) { 79 scoped_ptr<PolicyRule> process; 80 switch (semantics) { 81 case TargetPolicy::PROCESS_MIN_EXEC: { 82 process.reset(new PolicyRule(GIVE_READONLY)); 83 break; 84 }; 85 case TargetPolicy::PROCESS_ALL_EXEC: { 86 process.reset(new PolicyRule(GIVE_ALLACCESS)); 87 break; 88 }; 89 default: { 90 return false; 91 }; 92 } 93 94 if (!process->AddStringMatch(IF, NameBased::NAME, name, CASE_INSENSITIVE)) { 95 return false; 96 } 97 if (!policy->AddRule(IPC_CREATEPROCESSW_TAG, process.get())) { 98 return false; 99 } 100 return true; 101 } 102 103 NTSTATUS ProcessPolicy::OpenThreadAction(const ClientInfo& client_info, 104 uint32 desired_access, 105 uint32 thread_id, 106 HANDLE* handle) { 107 *handle = NULL; 108 109 NtOpenThreadFunction NtOpenThread = NULL; 110 ResolveNTFunctionPtr("NtOpenThread", &NtOpenThread); 111 112 OBJECT_ATTRIBUTES attributes = {0}; 113 attributes.Length = sizeof(attributes); 114 CLIENT_ID client_id = {0}; 115 client_id.UniqueProcess = reinterpret_cast<PVOID>( 116 static_cast<ULONG_PTR>(client_info.process_id)); 117 client_id.UniqueThread = 118 reinterpret_cast<PVOID>(static_cast<ULONG_PTR>(thread_id)); 119 120 HANDLE local_handle; 121 NTSTATUS status = NtOpenThread(&local_handle, desired_access, &attributes, 122 &client_id); 123 if (NT_SUCCESS(status)) { 124 if (!::DuplicateHandle(::GetCurrentProcess(), local_handle, 125 client_info.process, handle, 0, FALSE, 126 DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) { 127 ::CloseHandle(local_handle); 128 return STATUS_ACCESS_DENIED; 129 } 130 } 131 132 return status; 133 } 134 135 NTSTATUS ProcessPolicy::OpenProcessAction(const ClientInfo& client_info, 136 uint32 desired_access, 137 uint32 process_id, 138 HANDLE* handle) { 139 *handle = NULL; 140 141 NtOpenProcessFunction NtOpenProcess = NULL; 142 ResolveNTFunctionPtr("NtOpenProcess", &NtOpenProcess); 143 144 if (client_info.process_id != process_id) 145 return STATUS_ACCESS_DENIED; 146 147 OBJECT_ATTRIBUTES attributes = {0}; 148 attributes.Length = sizeof(attributes); 149 CLIENT_ID client_id = {0}; 150 client_id.UniqueProcess = reinterpret_cast<PVOID>( 151 static_cast<ULONG_PTR>(client_info.process_id)); 152 HANDLE local_handle; 153 NTSTATUS status = NtOpenProcess(&local_handle, desired_access, &attributes, 154 &client_id); 155 if (NT_SUCCESS(status)) { 156 if (!::DuplicateHandle(::GetCurrentProcess(), local_handle, 157 client_info.process, handle, 0, FALSE, 158 DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) { 159 ::CloseHandle(local_handle); 160 return STATUS_ACCESS_DENIED; 161 } 162 } 163 164 return status; 165 } 166 167 NTSTATUS ProcessPolicy::OpenProcessTokenAction(const ClientInfo& client_info, 168 HANDLE process, 169 uint32 desired_access, 170 HANDLE* handle) { 171 *handle = NULL; 172 NtOpenProcessTokenFunction NtOpenProcessToken = NULL; 173 ResolveNTFunctionPtr("NtOpenProcessToken", &NtOpenProcessToken); 174 175 if (CURRENT_PROCESS != process) 176 return STATUS_ACCESS_DENIED; 177 178 HANDLE local_handle; 179 NTSTATUS status = NtOpenProcessToken(client_info.process, desired_access, 180 &local_handle); 181 if (NT_SUCCESS(status)) { 182 if (!::DuplicateHandle(::GetCurrentProcess(), local_handle, 183 client_info.process, handle, 0, FALSE, 184 DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) { 185 ::CloseHandle(local_handle); 186 return STATUS_ACCESS_DENIED; 187 } 188 } 189 return status; 190 } 191 192 NTSTATUS ProcessPolicy::OpenProcessTokenExAction(const ClientInfo& client_info, 193 HANDLE process, 194 uint32 desired_access, 195 uint32 attributes, 196 HANDLE* handle) { 197 *handle = NULL; 198 NtOpenProcessTokenExFunction NtOpenProcessTokenEx = NULL; 199 ResolveNTFunctionPtr("NtOpenProcessTokenEx", &NtOpenProcessTokenEx); 200 201 if (CURRENT_PROCESS != process) 202 return STATUS_ACCESS_DENIED; 203 204 HANDLE local_handle; 205 NTSTATUS status = NtOpenProcessTokenEx(client_info.process, desired_access, 206 attributes, &local_handle); 207 if (NT_SUCCESS(status)) { 208 if (!::DuplicateHandle(::GetCurrentProcess(), local_handle, 209 client_info.process, handle, 0, FALSE, 210 DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) { 211 ::CloseHandle(local_handle); 212 return STATUS_ACCESS_DENIED; 213 } 214 } 215 return status; 216 } 217 218 DWORD ProcessPolicy::CreateProcessWAction(EvalResult eval_result, 219 const ClientInfo& client_info, 220 const base::string16 &app_name, 221 const base::string16 &command_line, 222 PROCESS_INFORMATION* process_info) { 223 // The only action supported is ASK_BROKER which means create the process. 224 if (GIVE_ALLACCESS != eval_result && GIVE_READONLY != eval_result) { 225 return ERROR_ACCESS_DENIED; 226 } 227 228 STARTUPINFO startup_info = {0}; 229 startup_info.cb = sizeof(startup_info); 230 scoped_ptr_malloc<wchar_t> cmd_line(_wcsdup(command_line.c_str())); 231 232 BOOL should_give_full_access = (GIVE_ALLACCESS == eval_result); 233 if (!CreateProcessExWHelper(client_info.process, should_give_full_access, 234 app_name.c_str(), cmd_line.get(), NULL, NULL, 235 FALSE, 0, NULL, NULL, &startup_info, 236 process_info)) { 237 return ERROR_ACCESS_DENIED; 238 } 239 return ERROR_SUCCESS; 240 } 241 242 } // namespace sandbox 243