| OLD | NEW | 
|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be | 
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. | 
| 4 | 4 | 
| 5 #include "sandbox/win/src/target_process.h" | 5 #include "sandbox/win/src/target_process.h" | 
| 6 | 6 | 
| 7 #include <stddef.h> | 7 #include <stddef.h> | 
| 8 #include <stdint.h> | 8 #include <stdint.h> | 
| 9 | 9 | 
| 10 #include <memory> | 10 #include <memory> | 
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 112     } | 112     } | 
| 113   } | 113   } | 
| 114 | 114 | 
| 115   // ipc_server_ references our process handle, so make sure the former is shut | 115   // ipc_server_ references our process handle, so make sure the former is shut | 
| 116   // down before the latter is closed (by ScopedProcessInformation). | 116   // down before the latter is closed (by ScopedProcessInformation). | 
| 117   ipc_server_.reset(); | 117   ipc_server_.reset(); | 
| 118 } | 118 } | 
| 119 | 119 | 
| 120 // Creates the target (child) process suspended and assigns it to the job | 120 // Creates the target (child) process suspended and assigns it to the job | 
| 121 // object. | 121 // object. | 
| 122 DWORD TargetProcess::Create(const wchar_t* exe_path, | 122 ResultCode TargetProcess::Create( | 
| 123                             const wchar_t* command_line, | 123     const wchar_t* exe_path, | 
| 124                             bool inherit_handles, | 124     const wchar_t* command_line, | 
| 125                             const base::win::StartupInformation& startup_info, | 125     bool inherit_handles, | 
| 126                             base::win::ScopedProcessInformation* target_info) { | 126     const base::win::StartupInformation& startup_info, | 
|  | 127     base::win::ScopedProcessInformation* target_info, | 
|  | 128     DWORD* win_error) { | 
| 127   if (lowbox_token_.IsValid() && | 129   if (lowbox_token_.IsValid() && | 
| 128       base::win::GetVersion() < base::win::VERSION_WIN8) { | 130       base::win::GetVersion() < base::win::VERSION_WIN8) { | 
| 129     // We don't allow lowbox_token below Windows 8. | 131     // We don't allow lowbox_token below Windows 8. | 
| 130     return ERROR_INVALID_PARAMETER; | 132     return SBOX_ERROR_BAD_PARAMS; | 
| 131   } | 133   } | 
| 132 | 134 | 
| 133   exe_name_.reset(_wcsdup(exe_path)); | 135   exe_name_.reset(_wcsdup(exe_path)); | 
| 134 | 136 | 
| 135   // the command line needs to be writable by CreateProcess(). | 137   // the command line needs to be writable by CreateProcess(). | 
| 136   std::unique_ptr<wchar_t, base::FreeDeleter> cmd_line(_wcsdup(command_line)); | 138   std::unique_ptr<wchar_t, base::FreeDeleter> cmd_line(_wcsdup(command_line)); | 
| 137 | 139 | 
| 138   // Start the target process suspended. | 140   // Start the target process suspended. | 
| 139   DWORD flags = | 141   DWORD flags = | 
| 140       CREATE_SUSPENDED | CREATE_UNICODE_ENVIRONMENT | DETACHED_PROCESS; | 142       CREATE_SUSPENDED | CREATE_UNICODE_ENVIRONMENT | DETACHED_PROCESS; | 
| 141 | 143 | 
| 142   if (startup_info.has_extended_startup_info()) | 144   if (startup_info.has_extended_startup_info()) | 
| 143     flags |= EXTENDED_STARTUPINFO_PRESENT; | 145     flags |= EXTENDED_STARTUPINFO_PRESENT; | 
| 144 | 146 | 
| 145   if (job_ && base::win::GetVersion() < base::win::VERSION_WIN8) { | 147   if (job_ && base::win::GetVersion() < base::win::VERSION_WIN8) { | 
| 146     // Windows 8 implements nested jobs, but for older systems we need to | 148     // Windows 8 implements nested jobs, but for older systems we need to | 
| 147     // break out of any job we're in to enforce our restrictions. | 149     // break out of any job we're in to enforce our restrictions. | 
| 148     flags |= CREATE_BREAKAWAY_FROM_JOB; | 150     flags |= CREATE_BREAKAWAY_FROM_JOB; | 
| 149   } | 151   } | 
| 150 | 152 | 
| 151   PROCESS_INFORMATION temp_process_info = {}; | 153   PROCESS_INFORMATION temp_process_info = {}; | 
| 152   if (!::CreateProcessAsUserW(lockdown_token_.Get(), exe_path, cmd_line.get(), | 154   if (!::CreateProcessAsUserW(lockdown_token_.Get(), exe_path, cmd_line.get(), | 
| 153                               NULL,  // No security attribute. | 155                               NULL,  // No security attribute. | 
| 154                               NULL,  // No thread attribute. | 156                               NULL,  // No thread attribute. | 
| 155                               inherit_handles, flags, | 157                               inherit_handles, flags, | 
| 156                               NULL,  // Use the environment of the caller. | 158                               NULL,  // Use the environment of the caller. | 
| 157                               NULL,  // Use current directory of the caller. | 159                               NULL,  // Use current directory of the caller. | 
| 158                               startup_info.startup_info(), | 160                               startup_info.startup_info(), | 
| 159                               &temp_process_info)) { | 161                               &temp_process_info)) { | 
| 160     return ::GetLastError(); | 162     *win_error = ::GetLastError(); | 
|  | 163     return SBOX_ERROR_CREATE_PROCESS; | 
| 161   } | 164   } | 
| 162   base::win::ScopedProcessInformation process_info(temp_process_info); | 165   base::win::ScopedProcessInformation process_info(temp_process_info); | 
| 163 | 166 | 
| 164   DWORD win_result = ERROR_SUCCESS; |  | 
| 165 |  | 
| 166   if (job_) { | 167   if (job_) { | 
| 167     // Assign the suspended target to the windows job object. | 168     // Assign the suspended target to the windows job object. | 
| 168     if (!::AssignProcessToJobObject(job_, process_info.process_handle())) { | 169     if (!::AssignProcessToJobObject(job_, process_info.process_handle())) { | 
| 169       win_result = ::GetLastError(); | 170       *win_error = ::GetLastError(); | 
| 170       ::TerminateProcess(process_info.process_handle(), 0); | 171       ::TerminateProcess(process_info.process_handle(), 0); | 
| 171       return win_result; | 172       return SBOX_ERROR_ASSIGN_PROCESS_TO_JOB_OBJECT; | 
| 172     } | 173     } | 
| 173   } | 174   } | 
| 174 | 175 | 
| 175   if (initial_token_.IsValid()) { | 176   if (initial_token_.IsValid()) { | 
| 176     // Change the token of the main thread of the new process for the | 177     // Change the token of the main thread of the new process for the | 
| 177     // impersonation token with more rights. This allows the target to start; | 178     // impersonation token with more rights. This allows the target to start; | 
| 178     // otherwise it will crash too early for us to help. | 179     // otherwise it will crash too early for us to help. | 
| 179     HANDLE temp_thread = process_info.thread_handle(); | 180     HANDLE temp_thread = process_info.thread_handle(); | 
| 180     if (!::SetThreadToken(&temp_thread, initial_token_.Get())) { | 181     if (!::SetThreadToken(&temp_thread, initial_token_.Get())) { | 
| 181       win_result = ::GetLastError(); | 182       *win_error = ::GetLastError(); | 
| 182       // It might be a security breach if we let the target run outside the job | 183       // It might be a security breach if we let the target run outside the job | 
| 183       // so kill it before it causes damage. | 184       // so kill it before it causes damage. | 
| 184       ::TerminateProcess(process_info.process_handle(), 0); | 185       ::TerminateProcess(process_info.process_handle(), 0); | 
| 185       return win_result; | 186       return SBOX_ERROR_SET_THREAD_TOKEN; | 
| 186     } | 187     } | 
| 187     initial_token_.Close(); | 188     initial_token_.Close(); | 
| 188   } | 189   } | 
| 189 | 190 | 
| 190   CONTEXT context; | 191   CONTEXT context; | 
| 191   context.ContextFlags = CONTEXT_ALL; | 192   context.ContextFlags = CONTEXT_ALL; | 
| 192   if (!::GetThreadContext(process_info.thread_handle(), &context)) { | 193   if (!::GetThreadContext(process_info.thread_handle(), &context)) { | 
| 193     win_result = ::GetLastError(); | 194     *win_error = ::GetLastError(); | 
| 194     ::TerminateProcess(process_info.process_handle(), 0); | 195     ::TerminateProcess(process_info.process_handle(), 0); | 
| 195     return win_result; | 196     return SBOX_ERROR_GET_THREAD_CONTEXT; | 
| 196   } | 197   } | 
| 197 | 198 | 
| 198 #if defined(_WIN64) | 199 #if defined(_WIN64) | 
| 199   void* entry_point = reinterpret_cast<void*>(context.Rcx); | 200   void* entry_point = reinterpret_cast<void*>(context.Rcx); | 
| 200 #else | 201 #else | 
| 201 #pragma warning(push) | 202 #pragma warning(push) | 
| 202 #pragma warning(disable: 4312) | 203 #pragma warning(disable: 4312) | 
| 203   // This cast generates a warning because it is 32 bit specific. | 204   // This cast generates a warning because it is 32 bit specific. | 
| 204   void* entry_point = reinterpret_cast<void*>(context.Eax); | 205   void* entry_point = reinterpret_cast<void*>(context.Eax); | 
| 205 #pragma warning(pop) | 206 #pragma warning(pop) | 
| 206 #endif  // _WIN64 | 207 #endif  // _WIN64 | 
| 207 | 208 | 
| 208   if (!target_info->DuplicateFrom(process_info)) { | 209   if (!target_info->DuplicateFrom(process_info)) { | 
| 209     win_result = ::GetLastError();  // This may or may not be correct. | 210     *win_error = ::GetLastError();  // This may or may not be correct. | 
| 210     ::TerminateProcess(process_info.process_handle(), 0); | 211     ::TerminateProcess(process_info.process_handle(), 0); | 
| 211     return win_result; | 212     return SBOX_ERROR_DUPLICATE_TARGET_INFO; | 
| 212   } | 213   } | 
| 213 | 214 | 
| 214   if (lowbox_token_.IsValid()) { | 215   if (lowbox_token_.IsValid()) { | 
| 215     PROCESS_ACCESS_TOKEN process_access_token; | 216     PROCESS_ACCESS_TOKEN process_access_token; | 
| 216     process_access_token.thread = process_info.thread_handle(); | 217     process_access_token.thread = process_info.thread_handle(); | 
| 217     process_access_token.token = lowbox_token_.Get(); | 218     process_access_token.token = lowbox_token_.Get(); | 
| 218 | 219 | 
| 219     NtSetInformationProcess SetInformationProcess = NULL; | 220     NtSetInformationProcess SetInformationProcess = NULL; | 
| 220     ResolveNTFunctionPtr("NtSetInformationProcess", &SetInformationProcess); | 221     ResolveNTFunctionPtr("NtSetInformationProcess", &SetInformationProcess); | 
| 221 | 222 | 
| 222     NTSTATUS status = SetInformationProcess( | 223     NTSTATUS status = SetInformationProcess( | 
| 223         process_info.process_handle(), | 224         process_info.process_handle(), | 
| 224         static_cast<PROCESS_INFORMATION_CLASS>(NtProcessInformationAccessToken), | 225         static_cast<PROCESS_INFORMATION_CLASS>(NtProcessInformationAccessToken), | 
| 225         &process_access_token, sizeof(process_access_token)); | 226         &process_access_token, sizeof(process_access_token)); | 
| 226     if (!NT_SUCCESS(status)) { | 227     if (!NT_SUCCESS(status)) { | 
| 227       win_result = ERROR_INVALID_TOKEN; | 228       *win_error = ERROR_INVALID_TOKEN; | 
| 228       ::TerminateProcess(process_info.process_handle(), 0);  // exit code | 229       ::TerminateProcess(process_info.process_handle(), 0);  // exit code | 
| 229       return win_result; | 230       return SBOX_ERROR_SET_LOW_BOX_TOKEN; | 
| 230     } | 231     } | 
| 231   } | 232   } | 
| 232 | 233 | 
| 233   base_address_ = GetBaseAddress(exe_path, entry_point); | 234   base_address_ = GetBaseAddress(exe_path, entry_point); | 
| 234   sandbox_process_info_.Set(process_info.Take()); | 235   sandbox_process_info_.Set(process_info.Take()); | 
| 235   return win_result; | 236   return SBOX_ALL_OK; | 
| 236 } | 237 } | 
| 237 | 238 | 
| 238 ResultCode TargetProcess::TransferVariable(const char* name, void* address, | 239 ResultCode TargetProcess::TransferVariable(const char* name, void* address, | 
| 239                                            size_t size) { | 240                                            size_t size) { | 
| 240   if (!sandbox_process_info_.IsValid()) | 241   if (!sandbox_process_info_.IsValid()) | 
| 241     return SBOX_ERROR_UNEXPECTED_CALL; | 242     return SBOX_ERROR_UNEXPECTED_CALL; | 
| 242 | 243 | 
| 243   void* child_var = address; | 244   void* child_var = address; | 
| 244 | 245 | 
| 245 #if SANDBOX_EXPORTS | 246 #if SANDBOX_EXPORTS | 
| (...skipping 18 matching lines...) Expand all  Loading... | 
| 264     return SBOX_ERROR_GENERIC; | 265     return SBOX_ERROR_GENERIC; | 
| 265 | 266 | 
| 266   if (written != size) | 267   if (written != size) | 
| 267     return SBOX_ERROR_GENERIC; | 268     return SBOX_ERROR_GENERIC; | 
| 268 | 269 | 
| 269   return SBOX_ALL_OK; | 270   return SBOX_ALL_OK; | 
| 270 } | 271 } | 
| 271 | 272 | 
| 272 // Construct the IPC server and the IPC dispatcher. When the target does | 273 // Construct the IPC server and the IPC dispatcher. When the target does | 
| 273 // an IPC it will eventually call the dispatcher. | 274 // an IPC it will eventually call the dispatcher. | 
| 274 DWORD TargetProcess::Init(Dispatcher* ipc_dispatcher, | 275 ResultCode TargetProcess::Init(Dispatcher* ipc_dispatcher, | 
| 275                           void* policy, | 276                                void* policy, | 
| 276                           uint32_t shared_IPC_size, | 277                                uint32_t shared_IPC_size, | 
| 277                           uint32_t shared_policy_size) { | 278                                uint32_t shared_policy_size, | 
|  | 279                                DWORD* win_error) { | 
| 278   // We need to map the shared memory on the target. This is necessary for | 280   // We need to map the shared memory on the target. This is necessary for | 
| 279   // any IPC that needs to take place, even if the target has not yet hit | 281   // any IPC that needs to take place, even if the target has not yet hit | 
| 280   // the main( ) function or even has initialized the CRT. So here we set | 282   // the main( ) function or even has initialized the CRT. So here we set | 
| 281   // the handle to the shared section. The target on the first IPC must do | 283   // the handle to the shared section. The target on the first IPC must do | 
| 282   // the rest, which boils down to calling MapViewofFile() | 284   // the rest, which boils down to calling MapViewofFile() | 
| 283 | 285 | 
| 284   // We use this single memory pool for IPC and for policy. | 286   // We use this single memory pool for IPC and for policy. | 
| 285   DWORD shared_mem_size = static_cast<DWORD>(shared_IPC_size + | 287   DWORD shared_mem_size = static_cast<DWORD>(shared_IPC_size + | 
| 286                                              shared_policy_size); | 288                                              shared_policy_size); | 
| 287   shared_section_.Set(::CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, | 289   shared_section_.Set(::CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, | 
| 288                                            PAGE_READWRITE | SEC_COMMIT, | 290                                            PAGE_READWRITE | SEC_COMMIT, | 
| 289                                            0, shared_mem_size, NULL)); | 291                                            0, shared_mem_size, NULL)); | 
| 290   if (!shared_section_.IsValid()) { | 292   if (!shared_section_.IsValid()) { | 
| 291     return ::GetLastError(); | 293     *win_error = ::GetLastError(); | 
|  | 294     return SBOX_ERROR_CREATE_FILE_MAPPING; | 
| 292   } | 295   } | 
| 293 | 296 | 
| 294   DWORD access = FILE_MAP_READ | FILE_MAP_WRITE | SECTION_QUERY; | 297   DWORD access = FILE_MAP_READ | FILE_MAP_WRITE | SECTION_QUERY; | 
| 295   HANDLE target_shared_section; | 298   HANDLE target_shared_section; | 
| 296   if (!::DuplicateHandle(::GetCurrentProcess(), shared_section_.Get(), | 299   if (!::DuplicateHandle(::GetCurrentProcess(), shared_section_.Get(), | 
| 297                          sandbox_process_info_.process_handle(), | 300                          sandbox_process_info_.process_handle(), | 
| 298                          &target_shared_section, access, FALSE, 0)) { | 301                          &target_shared_section, access, FALSE, 0)) { | 
| 299     return ::GetLastError(); | 302     *win_error = ::GetLastError(); | 
|  | 303     return SBOX_ERROR_DUPLICATE_SHARED_SECTION; | 
| 300   } | 304   } | 
| 301 | 305 | 
| 302   void* shared_memory = ::MapViewOfFile(shared_section_.Get(), | 306   void* shared_memory = ::MapViewOfFile(shared_section_.Get(), | 
| 303                                         FILE_MAP_WRITE|FILE_MAP_READ, | 307                                         FILE_MAP_WRITE|FILE_MAP_READ, | 
| 304                                         0, 0, 0); | 308                                         0, 0, 0); | 
| 305   if (NULL == shared_memory) { | 309   if (NULL == shared_memory) { | 
| 306     return ::GetLastError(); | 310     *win_error = ::GetLastError(); | 
|  | 311     return SBOX_ERROR_MAP_VIEW_OF_SHARED_SECTION; | 
| 307   } | 312   } | 
| 308 | 313 | 
| 309   CopyPolicyToTarget(policy, shared_policy_size, | 314   CopyPolicyToTarget(policy, shared_policy_size, | 
| 310                      reinterpret_cast<char*>(shared_memory) + shared_IPC_size); | 315                      reinterpret_cast<char*>(shared_memory) + shared_IPC_size); | 
| 311 | 316 | 
| 312   ResultCode ret; | 317   ResultCode ret; | 
| 313   // Set the global variables in the target. These are not used on the broker. | 318   // Set the global variables in the target. These are not used on the broker. | 
| 314   g_shared_section = target_shared_section; | 319   g_shared_section = target_shared_section; | 
| 315   ret = TransferVariable("g_shared_section", &g_shared_section, | 320   ret = TransferVariable("g_shared_section", &g_shared_section, | 
| 316                          sizeof(g_shared_section)); | 321                          sizeof(g_shared_section)); | 
| 317   g_shared_section = NULL; | 322   g_shared_section = NULL; | 
| 318   if (SBOX_ALL_OK != ret) { | 323   if (SBOX_ALL_OK != ret) { | 
| 319     return (SBOX_ERROR_GENERIC == ret)? | 324     *win_error = ::GetLastError(); | 
| 320            ::GetLastError() : ERROR_INVALID_FUNCTION; | 325     return ret; | 
| 321   } | 326   } | 
| 322   g_shared_IPC_size = shared_IPC_size; | 327   g_shared_IPC_size = shared_IPC_size; | 
| 323   ret = TransferVariable("g_shared_IPC_size", &g_shared_IPC_size, | 328   ret = TransferVariable("g_shared_IPC_size", &g_shared_IPC_size, | 
| 324                          sizeof(g_shared_IPC_size)); | 329                          sizeof(g_shared_IPC_size)); | 
| 325   g_shared_IPC_size = 0; | 330   g_shared_IPC_size = 0; | 
| 326   if (SBOX_ALL_OK != ret) { | 331   if (SBOX_ALL_OK != ret) { | 
| 327     return (SBOX_ERROR_GENERIC == ret) ? | 332     *win_error = ::GetLastError(); | 
| 328            ::GetLastError() : ERROR_INVALID_FUNCTION; | 333     return ret; | 
| 329   } | 334   } | 
| 330   g_shared_policy_size = shared_policy_size; | 335   g_shared_policy_size = shared_policy_size; | 
| 331   ret = TransferVariable("g_shared_policy_size", &g_shared_policy_size, | 336   ret = TransferVariable("g_shared_policy_size", &g_shared_policy_size, | 
| 332                          sizeof(g_shared_policy_size)); | 337                          sizeof(g_shared_policy_size)); | 
| 333   g_shared_policy_size = 0; | 338   g_shared_policy_size = 0; | 
| 334   if (SBOX_ALL_OK != ret) { | 339   if (SBOX_ALL_OK != ret) { | 
| 335     return (SBOX_ERROR_GENERIC == ret) ? | 340     *win_error = ::GetLastError(); | 
| 336            ::GetLastError() : ERROR_INVALID_FUNCTION; | 341     return ret; | 
| 337   } | 342   } | 
| 338 | 343 | 
| 339   ipc_server_.reset( | 344   ipc_server_.reset( | 
| 340       new SharedMemIPCServer(sandbox_process_info_.process_handle(), | 345       new SharedMemIPCServer(sandbox_process_info_.process_handle(), | 
| 341                              sandbox_process_info_.process_id(), | 346                              sandbox_process_info_.process_id(), | 
| 342                              thread_pool_, ipc_dispatcher)); | 347                              thread_pool_, ipc_dispatcher)); | 
| 343 | 348 | 
| 344   if (!ipc_server_->Init(shared_memory, shared_IPC_size, kIPCChannelSize)) | 349   if (!ipc_server_->Init(shared_memory, shared_IPC_size, kIPCChannelSize)) | 
| 345     return ERROR_NOT_ENOUGH_MEMORY; | 350     return SBOX_ERROR_NO_SPACE; | 
| 346 | 351 | 
| 347   // After this point we cannot use this handle anymore. | 352   // After this point we cannot use this handle anymore. | 
| 348   ::CloseHandle(sandbox_process_info_.TakeThreadHandle()); | 353   ::CloseHandle(sandbox_process_info_.TakeThreadHandle()); | 
| 349 | 354 | 
| 350   return ERROR_SUCCESS; | 355   return SBOX_ALL_OK; | 
| 351 } | 356 } | 
| 352 | 357 | 
| 353 void TargetProcess::Terminate() { | 358 void TargetProcess::Terminate() { | 
| 354   if (!sandbox_process_info_.IsValid()) | 359   if (!sandbox_process_info_.IsValid()) | 
| 355     return; | 360     return; | 
| 356 | 361 | 
| 357   ::TerminateProcess(sandbox_process_info_.process_handle(), 0); | 362   ::TerminateProcess(sandbox_process_info_.process_handle(), 0); | 
| 358 } | 363 } | 
| 359 | 364 | 
| 360 TargetProcess* MakeTestTargetProcess(HANDLE process, HMODULE base_address) { | 365 TargetProcess* MakeTestTargetProcess(HANDLE process, HMODULE base_address) { | 
| 361   TargetProcess* target = | 366   TargetProcess* target = | 
| 362       new TargetProcess(base::win::ScopedHandle(), base::win::ScopedHandle(), | 367       new TargetProcess(base::win::ScopedHandle(), base::win::ScopedHandle(), | 
| 363                         base::win::ScopedHandle(), NULL, NULL); | 368                         base::win::ScopedHandle(), NULL, NULL); | 
| 364   PROCESS_INFORMATION process_info = {}; | 369   PROCESS_INFORMATION process_info = {}; | 
| 365   process_info.hProcess = process; | 370   process_info.hProcess = process; | 
| 366   target->sandbox_process_info_.Set(process_info); | 371   target->sandbox_process_info_.Set(process_info); | 
| 367   target->base_address_ = base_address; | 372   target->base_address_ = base_address; | 
| 368   return target; | 373   return target; | 
| 369 } | 374 } | 
| 370 | 375 | 
| 371 }  // namespace sandbox | 376 }  // namespace sandbox | 
| OLD | NEW | 
|---|