Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2)

Side by Side Diff: sandbox/win/src/target_process.cc

Issue 1923653002: Wire up process launch error codes. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fix debug and clang Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « sandbox/win/src/target_process.h ('k') | tools/metrics/histograms/histograms.xml » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
OLDNEW
« no previous file with comments | « sandbox/win/src/target_process.h ('k') | tools/metrics/histograms/histograms.xml » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698