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 "content/zygote/zygote_main.h" | 5 #include "content/zygote/zygote_main.h" |
6 | 6 |
7 #include <dlfcn.h> | 7 #include <dlfcn.h> |
8 #include <fcntl.h> | 8 #include <fcntl.h> |
9 #include <pthread.h> | 9 #include <pthread.h> |
10 #include <stdio.h> | 10 #include <stdio.h> |
11 #include <sys/socket.h> | 11 #include <sys/socket.h> |
12 #include <sys/stat.h> | 12 #include <sys/stat.h> |
13 #include <sys/types.h> | 13 #include <sys/types.h> |
14 #include <sys/wait.h> | 14 #include <sys/wait.h> |
15 #include <unistd.h> | 15 #include <unistd.h> |
16 | 16 |
17 #include "base/basictypes.h" | 17 #include "base/basictypes.h" |
| 18 #include "base/bind.h" |
| 19 #include "base/callback.h" |
18 #include "base/command_line.h" | 20 #include "base/command_line.h" |
19 #include "base/linux_util.h" | 21 #include "base/linux_util.h" |
20 #include "base/native_library.h" | 22 #include "base/native_library.h" |
21 #include "base/pickle.h" | 23 #include "base/pickle.h" |
22 #include "base/posix/eintr_wrapper.h" | 24 #include "base/posix/eintr_wrapper.h" |
23 #include "base/posix/unix_domain_socket_linux.h" | 25 #include "base/posix/unix_domain_socket_linux.h" |
24 #include "base/rand_util.h" | 26 #include "base/rand_util.h" |
25 #include "base/sys_info.h" | 27 #include "base/sys_info.h" |
26 #include "build/build_config.h" | 28 #include "build/build_config.h" |
27 #include "content/common/child_process_sandbox_support_impl_linux.h" | 29 #include "content/common/child_process_sandbox_support_impl_linux.h" |
(...skipping 273 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
301 // Ensure access to the Pepper plugins before the sandbox is turned on. | 303 // Ensure access to the Pepper plugins before the sandbox is turned on. |
302 PreloadPepperPlugins(); | 304 PreloadPepperPlugins(); |
303 #endif | 305 #endif |
304 #if defined(ENABLE_WEBRTC) | 306 #if defined(ENABLE_WEBRTC) |
305 InitializeWebRtcModule(); | 307 InitializeWebRtcModule(); |
306 #endif | 308 #endif |
307 SkFontConfigInterface::SetGlobal( | 309 SkFontConfigInterface::SetGlobal( |
308 new FontConfigIPC(GetSandboxFD()))->unref(); | 310 new FontConfigIPC(GetSandboxFD()))->unref(); |
309 } | 311 } |
310 | 312 |
311 // Do nothing here | 313 static void CloseFdAndHandleEintr(int fd) { |
312 static void SIGCHLDHandler(int signal) { | 314 (void) HANDLE_EINTR(close(fd)); |
313 } | |
314 | |
315 // The current process will become a process reaper like init. | |
316 // We fork a child that will continue normally, when it dies, we can safely | |
317 // exit. | |
318 // We need to be careful we close the magic kZygoteIdFd properly in the parent | |
319 // before this function returns. | |
320 static bool CreateInitProcessReaper() { | |
321 int sync_fds[2]; | |
322 // We want to use send, so we can't use a pipe | |
323 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sync_fds)) { | |
324 LOG(ERROR) << "Failed to create socketpair"; | |
325 return false; | |
326 } | |
327 | |
328 // We use normal fork, not the ForkDelegate in this case since we are not a | |
329 // true Zygote yet. | |
330 pid_t child_pid = fork(); | |
331 if (child_pid == -1) { | |
332 (void) HANDLE_EINTR(close(sync_fds[0])); | |
333 (void) HANDLE_EINTR(close(sync_fds[1])); | |
334 return false; | |
335 } | |
336 if (child_pid) { | |
337 // We are the parent, assuming the role of an init process. | |
338 // The disposition for SIGCHLD cannot be SIG_IGN or wait() will only return | |
339 // once all of our childs are dead. Since we're init we need to reap childs | |
340 // as they come. | |
341 struct sigaction action; | |
342 memset(&action, 0, sizeof(action)); | |
343 action.sa_handler = &SIGCHLDHandler; | |
344 CHECK(sigaction(SIGCHLD, &action, NULL) == 0); | |
345 | |
346 (void) HANDLE_EINTR(close(sync_fds[0])); | |
347 shutdown(sync_fds[1], SHUT_RD); | |
348 // This "magic" socket must only appear in one process. | |
349 (void) HANDLE_EINTR(close(kZygoteIdFd)); | |
350 // Tell the child to continue | |
351 CHECK(HANDLE_EINTR(send(sync_fds[1], "C", 1, MSG_NOSIGNAL)) == 1); | |
352 (void) HANDLE_EINTR(close(sync_fds[1])); | |
353 | |
354 for (;;) { | |
355 // Loop until we have reaped our one natural child | |
356 siginfo_t reaped_child_info; | |
357 int wait_ret = | |
358 HANDLE_EINTR(waitid(P_ALL, 0, &reaped_child_info, WEXITED)); | |
359 if (wait_ret) | |
360 _exit(1); | |
361 if (reaped_child_info.si_pid == child_pid) { | |
362 int exit_code = 0; | |
363 // We're done waiting | |
364 if (reaped_child_info.si_code == CLD_EXITED) { | |
365 exit_code = reaped_child_info.si_status; | |
366 } | |
367 // Exit with the same exit code as our parent. This is most likely | |
368 // useless. _exit with 0 if we got signaled. | |
369 _exit(exit_code); | |
370 } | |
371 } | |
372 } else { | |
373 // The child needs to wait for the parent to close kZygoteIdFd to avoid a | |
374 // race condition | |
375 (void) HANDLE_EINTR(close(sync_fds[1])); | |
376 shutdown(sync_fds[0], SHUT_WR); | |
377 char should_continue; | |
378 int read_ret = HANDLE_EINTR(read(sync_fds[0], &should_continue, 1)); | |
379 (void) HANDLE_EINTR(close(sync_fds[0])); | |
380 if (read_ret == 1) | |
381 return true; | |
382 else | |
383 return false; | |
384 } | |
385 } | 315 } |
386 | 316 |
387 // This will set the *using_suid_sandbox variable to true if the SUID sandbox | 317 // This will set the *using_suid_sandbox variable to true if the SUID sandbox |
388 // is enabled. This does not necessarily exclude other types of sandboxing. | 318 // is enabled. This does not necessarily exclude other types of sandboxing. |
389 static bool EnterSuidSandbox(LinuxSandbox* linux_sandbox, | 319 static bool EnterSuidSandbox(LinuxSandbox* linux_sandbox, |
390 bool* using_suid_sandbox, | 320 bool* using_suid_sandbox, |
391 bool* has_started_new_init) { | 321 bool* has_started_new_init) { |
392 *using_suid_sandbox = false; | 322 *using_suid_sandbox = false; |
393 *has_started_new_init = false; | 323 *has_started_new_init = false; |
394 | 324 |
(...skipping 19 matching lines...) Expand all Loading... |
414 "https://code.google.com/p/chromium/wiki/LinuxSUIDSandboxDevelopment." | 344 "https://code.google.com/p/chromium/wiki/LinuxSUIDSandboxDevelopment." |
415 "\n\n"; | 345 "\n\n"; |
416 } | 346 } |
417 | 347 |
418 if (!setuid_sandbox->ChrootMe()) | 348 if (!setuid_sandbox->ChrootMe()) |
419 return false; | 349 return false; |
420 | 350 |
421 if (getpid() == 1) { | 351 if (getpid() == 1) { |
422 // The setuid sandbox has created a new PID namespace and we need | 352 // The setuid sandbox has created a new PID namespace and we need |
423 // to assume the role of init. | 353 // to assume the role of init. |
424 if (!CreateInitProcessReaper()) { | 354 // This "magic" socket must only appear in one process, so make sure |
| 355 // it gets closed in the parent after fork(). |
| 356 base::Closure zygoteid_fd_closer = |
| 357 base::Bind(CloseFdAndHandleEintr, kZygoteIdFd); |
| 358 const bool init_created = |
| 359 setuid_sandbox->CreateInitProcessReaper(&zygoteid_fd_closer); |
| 360 if (!init_created) { |
425 LOG(ERROR) << "Error creating an init process to reap zombies"; | 361 LOG(ERROR) << "Error creating an init process to reap zombies"; |
426 return false; | 362 return false; |
427 } | 363 } |
428 *has_started_new_init = true; | 364 *has_started_new_init = true; |
429 } | 365 } |
430 | 366 |
431 #if !defined(OS_OPENBSD) | 367 #if !defined(OS_OPENBSD) |
432 // Previously, we required that the binary be non-readable. This causes the | 368 // Previously, we required that the binary be non-readable. This causes the |
433 // kernel to mark the process as non-dumpable at startup. The thinking was | 369 // kernel to mark the process as non-dumpable at startup. The thinking was |
434 // that, although we were putting the renderers into a PID namespace (with | 370 // that, although we were putting the renderers into a PID namespace (with |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
498 } | 434 } |
499 | 435 |
500 int sandbox_flags = linux_sandbox->GetStatus(); | 436 int sandbox_flags = linux_sandbox->GetStatus(); |
501 | 437 |
502 Zygote zygote(sandbox_flags, forkdelegate); | 438 Zygote zygote(sandbox_flags, forkdelegate); |
503 // This function call can return multiple times, once per fork(). | 439 // This function call can return multiple times, once per fork(). |
504 return zygote.ProcessRequests(); | 440 return zygote.ProcessRequests(); |
505 } | 441 } |
506 | 442 |
507 } // namespace content | 443 } // namespace content |
OLD | NEW |