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 return STATUS_ACCESS_DENIED; 128 } 129 } 130 131 return status; 132 } 133 134 NTSTATUS ProcessPolicy::OpenProcessAction(const ClientInfo& client_info, 135 uint32 desired_access, 136 uint32 process_id, 137 HANDLE* handle) { 138 *handle = NULL; 139 140 NtOpenProcessFunction NtOpenProcess = NULL; 141 ResolveNTFunctionPtr("NtOpenProcess", &NtOpenProcess); 142 143 if (client_info.process_id != process_id) 144 return STATUS_ACCESS_DENIED; 145 146 OBJECT_ATTRIBUTES attributes = {0}; 147 attributes.Length = sizeof(attributes); 148 CLIENT_ID client_id = {0}; 149 client_id.UniqueProcess = reinterpret_cast<PVOID>( 150 static_cast<ULONG_PTR>(client_info.process_id)); 151 HANDLE local_handle; 152 NTSTATUS status = NtOpenProcess(&local_handle, desired_access, &attributes, 153 &client_id); 154 if (NT_SUCCESS(status)) { 155 if (!::DuplicateHandle(::GetCurrentProcess(), local_handle, 156 client_info.process, handle, 0, FALSE, 157 DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) { 158 return STATUS_ACCESS_DENIED; 159 } 160 } 161 162 return status; 163 } 164 165 NTSTATUS ProcessPolicy::OpenProcessTokenAction(const ClientInfo& client_info, 166 HANDLE process, 167 uint32 desired_access, 168 HANDLE* handle) { 169 *handle = NULL; 170 NtOpenProcessTokenFunction NtOpenProcessToken = NULL; 171 ResolveNTFunctionPtr("NtOpenProcessToken", &NtOpenProcessToken); 172 173 if (CURRENT_PROCESS != process) 174 return STATUS_ACCESS_DENIED; 175 176 HANDLE local_handle; 177 NTSTATUS status = NtOpenProcessToken(client_info.process, desired_access, 178 &local_handle); 179 if (NT_SUCCESS(status)) { 180 if (!::DuplicateHandle(::GetCurrentProcess(), local_handle, 181 client_info.process, handle, 0, FALSE, 182 DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) { 183 return STATUS_ACCESS_DENIED; 184 } 185 } 186 return status; 187 } 188 189 NTSTATUS ProcessPolicy::OpenProcessTokenExAction(const ClientInfo& client_info, 190 HANDLE process, 191 uint32 desired_access, 192 uint32 attributes, 193 HANDLE* handle) { 194 *handle = NULL; 195 NtOpenProcessTokenExFunction NtOpenProcessTokenEx = NULL; 196 ResolveNTFunctionPtr("NtOpenProcessTokenEx", &NtOpenProcessTokenEx); 197 198 if (CURRENT_PROCESS != process) 199 return STATUS_ACCESS_DENIED; 200 201 HANDLE local_handle; 202 NTSTATUS status = NtOpenProcessTokenEx(client_info.process, desired_access, 203 attributes, &local_handle); 204 if (NT_SUCCESS(status)) { 205 if (!::DuplicateHandle(::GetCurrentProcess(), local_handle, 206 client_info.process, handle, 0, FALSE, 207 DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) { 208 return STATUS_ACCESS_DENIED; 209 } 210 } 211 return status; 212 } 213 214 DWORD ProcessPolicy::CreateProcessWAction(EvalResult eval_result, 215 const ClientInfo& client_info, 216 const base::string16 &app_name, 217 const base::string16 &command_line, 218 PROCESS_INFORMATION* process_info) { 219 // The only action supported is ASK_BROKER which means create the process. 220 if (GIVE_ALLACCESS != eval_result && GIVE_READONLY != eval_result) { 221 return ERROR_ACCESS_DENIED; 222 } 223 224 STARTUPINFO startup_info = {0}; 225 startup_info.cb = sizeof(startup_info); 226 scoped_ptr<wchar_t, base::FreeDeleter> 227 cmd_line(_wcsdup(command_line.c_str())); 228 229 BOOL should_give_full_access = (GIVE_ALLACCESS == eval_result); 230 if (!CreateProcessExWHelper(client_info.process, should_give_full_access, 231 app_name.c_str(), cmd_line.get(), NULL, NULL, 232 FALSE, 0, NULL, NULL, &startup_info, 233 process_info)) { 234 return ERROR_ACCESS_DENIED; 235 } 236 return ERROR_SUCCESS; 237 } 238 239 } // namespace sandbox 240