| 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 <errno.h> | 8 #include <errno.h> |
| 9 #include <fcntl.h> | 9 #include <fcntl.h> |
| 10 #include <pthread.h> | 10 #include <pthread.h> |
| (...skipping 21 matching lines...) Expand all Loading... |
| 32 #include "content/common/pepper_plugin_list.h" | 32 #include "content/common/pepper_plugin_list.h" |
| 33 #include "content/common/sandbox_linux/sandbox_linux.h" | 33 #include "content/common/sandbox_linux/sandbox_linux.h" |
| 34 #include "content/common/zygote_commands_linux.h" | 34 #include "content/common/zygote_commands_linux.h" |
| 35 #include "content/public/common/content_switches.h" | 35 #include "content/public/common/content_switches.h" |
| 36 #include "content/public/common/main_function_params.h" | 36 #include "content/public/common/main_function_params.h" |
| 37 #include "content/public/common/pepper_plugin_info.h" | 37 #include "content/public/common/pepper_plugin_info.h" |
| 38 #include "content/public/common/sandbox_linux.h" | 38 #include "content/public/common/sandbox_linux.h" |
| 39 #include "content/public/common/zygote_fork_delegate_linux.h" | 39 #include "content/public/common/zygote_fork_delegate_linux.h" |
| 40 #include "content/zygote/zygote_linux.h" | 40 #include "content/zygote/zygote_linux.h" |
| 41 #include "crypto/nss_util.h" | 41 #include "crypto/nss_util.h" |
| 42 #include "sandbox/linux/services/init_process_reaper.h" |
| 42 #include "sandbox/linux/services/libc_urandom_override.h" | 43 #include "sandbox/linux/services/libc_urandom_override.h" |
| 43 #include "sandbox/linux/suid/client/setuid_sandbox_client.h" | 44 #include "sandbox/linux/suid/client/setuid_sandbox_client.h" |
| 44 #include "third_party/icu/source/i18n/unicode/timezone.h" | 45 #include "third_party/icu/source/i18n/unicode/timezone.h" |
| 45 #include "third_party/skia/include/ports/SkFontConfigInterface.h" | 46 #include "third_party/skia/include/ports/SkFontConfigInterface.h" |
| 46 | 47 |
| 47 #if defined(OS_LINUX) | 48 #if defined(OS_LINUX) |
| 48 #include <sys/epoll.h> | 49 #include <sys/epoll.h> |
| 49 #include <sys/prctl.h> | 50 #include <sys/prctl.h> |
| 50 #include <sys/signal.h> | 51 #include <sys/signal.h> |
| 51 #else | 52 #else |
| (...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 284 << error; | 285 << error; |
| 285 | 286 |
| 286 (void)library; // Prevent release-mode warning. | 287 (void)library; // Prevent release-mode warning. |
| 287 } | 288 } |
| 288 } | 289 } |
| 289 } | 290 } |
| 290 #endif | 291 #endif |
| 291 | 292 |
| 292 // This function triggers the static and lazy construction of objects that need | 293 // This function triggers the static and lazy construction of objects that need |
| 293 // to be created before imposing the sandbox. | 294 // to be created before imposing the sandbox. |
| 294 static void PreSandboxInit() { | 295 static void ZygotePreSandboxInit() { |
| 295 base::RandUint64(); | 296 base::RandUint64(); |
| 296 | 297 |
| 297 base::SysInfo::AmountOfPhysicalMemory(); | 298 base::SysInfo::AmountOfPhysicalMemory(); |
| 298 base::SysInfo::MaxSharedMemorySize(); | 299 base::SysInfo::MaxSharedMemorySize(); |
| 299 base::SysInfo::NumberOfProcessors(); | 300 base::SysInfo::NumberOfProcessors(); |
| 300 | 301 |
| 301 // ICU DateFormat class (used in base/time_format.cc) needs to get the | 302 // ICU DateFormat class (used in base/time_format.cc) needs to get the |
| 302 // Olson timezone ID by accessing the zoneinfo files on disk. After | 303 // Olson timezone ID by accessing the zoneinfo files on disk. After |
| 303 // TimeZone::createDefault is called once here, the timezone ID is | 304 // TimeZone::createDefault is called once here, the timezone ID is |
| 304 // cached and there's no more need to access the file system. | 305 // cached and there's no more need to access the file system. |
| (...skipping 20 matching lines...) Expand all Loading... |
| 325 InitializeWebRtcModule(); | 326 InitializeWebRtcModule(); |
| 326 #endif | 327 #endif |
| 327 SkFontConfigInterface::SetGlobal( | 328 SkFontConfigInterface::SetGlobal( |
| 328 new FontConfigIPC(GetSandboxFD()))->unref(); | 329 new FontConfigIPC(GetSandboxFD()))->unref(); |
| 329 } | 330 } |
| 330 | 331 |
| 331 static void CloseFdAndHandleEintr(int fd) { | 332 static void CloseFdAndHandleEintr(int fd) { |
| 332 close(fd); | 333 close(fd); |
| 333 } | 334 } |
| 334 | 335 |
| 335 // This will set the *using_suid_sandbox variable to true if the SUID sandbox | 336 static bool CreateInitProcessReaper() { |
| 336 // is enabled. This does not necessarily exclude other types of sandboxing. | 337 // This "magic" socket must only appear in one process, so make sure |
| 337 static bool EnterSuidSandbox(LinuxSandbox* linux_sandbox, | 338 // it gets closed in the parent after fork(). |
| 338 bool* using_suid_sandbox, | 339 base::Closure zygoteid_fd_closer = |
| 339 bool* has_started_new_init) { | 340 base::Bind(CloseFdAndHandleEintr, kZygoteIdFd); |
| 340 *using_suid_sandbox = false; | 341 // The current process becomes init(1), this function returns from a |
| 341 *has_started_new_init = false; | 342 // newly created process. |
| 343 const bool init_created = |
| 344 sandbox::CreateInitProcessReaper(&zygoteid_fd_closer); |
| 345 if (!init_created) { |
| 346 LOG(ERROR) << "Error creating an init process to reap zombies"; |
| 347 return false; |
| 348 } |
| 349 return true; |
| 350 } |
| 342 | 351 |
| 343 sandbox::SetuidSandboxClient* setuid_sandbox = | 352 // Enter the setuid sandbox. This requires the current process to have been |
| 344 linux_sandbox->setuid_sandbox_client(); | 353 // created through the setuid sandbox. |
| 354 static bool EnterSuidSandbox(sandbox::SetuidSandboxClient* setuid_sandbox) { |
| 355 DCHECK(setuid_sandbox); |
| 356 DCHECK(setuid_sandbox->IsSuidSandboxChild()); |
| 345 | 357 |
| 346 if (!setuid_sandbox) | 358 // Use the SUID sandbox. This still allows the seccomp sandbox to |
| 359 // be enabled by the process later. |
| 360 |
| 361 if (!setuid_sandbox->IsSuidSandboxUpToDate()) { |
| 362 LOG(WARNING) << |
| 363 "You are using a wrong version of the setuid binary!\n" |
| 364 "Please read " |
| 365 "https://code.google.com/p/chromium/wiki/LinuxSUIDSandboxDevelopment." |
| 366 "\n\n"; |
| 367 } |
| 368 |
| 369 if (!setuid_sandbox->ChrootMe()) |
| 347 return false; | 370 return false; |
| 348 | 371 |
| 349 PreSandboxInit(); | 372 if (setuid_sandbox->IsInNewPIDNamespace()) { |
| 373 CHECK_EQ(1, getpid()) |
| 374 << "The SUID sandbox created a new PID namespace but Zygote " |
| 375 "is not the init process. Please, make sure the SUID " |
| 376 "binary is up to date."; |
| 377 } |
| 378 |
| 379 if (getpid() == 1) { |
| 380 // The setuid sandbox has created a new PID namespace and we need |
| 381 // to assume the role of init. |
| 382 CHECK(CreateInitProcessReaper()); |
| 383 } |
| 384 |
| 385 #if !defined(OS_OPENBSD) |
| 386 // Previously, we required that the binary be non-readable. This causes the |
| 387 // kernel to mark the process as non-dumpable at startup. The thinking was |
| 388 // that, although we were putting the renderers into a PID namespace (with |
| 389 // the SUID sandbox), they would nonetheless be in the /same/ PID |
| 390 // namespace. So they could ptrace each other unless they were non-dumpable. |
| 391 // |
| 392 // If the binary was readable, then there would be a window between process |
| 393 // startup and the point where we set the non-dumpable flag in which a |
| 394 // compromised renderer could ptrace attach. |
| 395 // |
| 396 // However, now that we have a zygote model, only the (trusted) zygote |
| 397 // exists at this point and we can set the non-dumpable flag which is |
| 398 // inherited by all our renderer children. |
| 399 // |
| 400 // Note: a non-dumpable process can't be debugged. To debug sandbox-related |
| 401 // issues, one can specify --allow-sandbox-debugging to let the process be |
| 402 // dumpable. |
| 403 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); |
| 404 if (!command_line.HasSwitch(switches::kAllowSandboxDebugging)) { |
| 405 prctl(PR_SET_DUMPABLE, 0, 0, 0, 0); |
| 406 if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0)) { |
| 407 LOG(ERROR) << "Failed to set non-dumpable flag"; |
| 408 return false; |
| 409 } |
| 410 } |
| 411 #endif |
| 412 |
| 413 return true; |
| 414 } |
| 415 |
| 416 static void EnterLayerOneSandbox(LinuxSandbox* linux_sandbox) { |
| 417 DCHECK(linux_sandbox); |
| 418 |
| 419 ZygotePreSandboxInit(); |
| 350 | 420 |
| 351 // Check that the pre-sandbox initialization didn't spawn threads. | 421 // Check that the pre-sandbox initialization didn't spawn threads. |
| 352 #if !defined(THREAD_SANITIZER) | 422 #if !defined(THREAD_SANITIZER) |
| 353 DCHECK(linux_sandbox->IsSingleThreaded()); | 423 DCHECK(linux_sandbox->IsSingleThreaded()); |
| 354 #endif | 424 #endif |
| 355 | 425 |
| 426 sandbox::SetuidSandboxClient* setuid_sandbox = |
| 427 linux_sandbox->setuid_sandbox_client(); |
| 428 |
| 356 if (setuid_sandbox->IsSuidSandboxChild()) { | 429 if (setuid_sandbox->IsSuidSandboxChild()) { |
| 357 // Use the SUID sandbox. This still allows the seccomp sandbox to | 430 CHECK(EnterSuidSandbox(setuid_sandbox)) << "Failed to enter setuid sandbox"; |
| 358 // be enabled by the process later. | |
| 359 *using_suid_sandbox = true; | |
| 360 | |
| 361 if (!setuid_sandbox->IsSuidSandboxUpToDate()) { | |
| 362 LOG(WARNING) << "You are using a wrong version of the setuid binary!\n" | |
| 363 "Please read " | |
| 364 "https://code.google.com/p/chromium/wiki/LinuxSUIDSandboxDevelopment." | |
| 365 "\n\n"; | |
| 366 } | |
| 367 | |
| 368 if (!setuid_sandbox->ChrootMe()) | |
| 369 return false; | |
| 370 | |
| 371 if (getpid() == 1) { | |
| 372 // The setuid sandbox has created a new PID namespace and we need | |
| 373 // to assume the role of init. | |
| 374 // This "magic" socket must only appear in one process, so make sure | |
| 375 // it gets closed in the parent after fork(). | |
| 376 base::Closure zygoteid_fd_closer = | |
| 377 base::Bind(CloseFdAndHandleEintr, kZygoteIdFd); | |
| 378 const bool init_created = | |
| 379 setuid_sandbox->CreateInitProcessReaper(&zygoteid_fd_closer); | |
| 380 if (!init_created) { | |
| 381 LOG(ERROR) << "Error creating an init process to reap zombies"; | |
| 382 return false; | |
| 383 } | |
| 384 *has_started_new_init = true; | |
| 385 } | |
| 386 | |
| 387 #if !defined(OS_OPENBSD) | |
| 388 // Previously, we required that the binary be non-readable. This causes the | |
| 389 // kernel to mark the process as non-dumpable at startup. The thinking was | |
| 390 // that, although we were putting the renderers into a PID namespace (with | |
| 391 // the SUID sandbox), they would nonetheless be in the /same/ PID | |
| 392 // namespace. So they could ptrace each other unless they were non-dumpable. | |
| 393 // | |
| 394 // If the binary was readable, then there would be a window between process | |
| 395 // startup and the point where we set the non-dumpable flag in which a | |
| 396 // compromised renderer could ptrace attach. | |
| 397 // | |
| 398 // However, now that we have a zygote model, only the (trusted) zygote | |
| 399 // exists at this point and we can set the non-dumpable flag which is | |
| 400 // inherited by all our renderer children. | |
| 401 // | |
| 402 // Note: a non-dumpable process can't be debugged. To debug sandbox-related | |
| 403 // issues, one can specify --allow-sandbox-debugging to let the process be | |
| 404 // dumpable. | |
| 405 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); | |
| 406 if (!command_line.HasSwitch(switches::kAllowSandboxDebugging)) { | |
| 407 prctl(PR_SET_DUMPABLE, 0, 0, 0, 0); | |
| 408 if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0)) { | |
| 409 LOG(ERROR) << "Failed to set non-dumpable flag"; | |
| 410 return false; | |
| 411 } | |
| 412 } | |
| 413 #endif | |
| 414 } | 431 } |
| 415 | |
| 416 return true; | |
| 417 } | 432 } |
| 418 | 433 |
| 419 bool ZygoteMain(const MainFunctionParams& params, | 434 bool ZygoteMain(const MainFunctionParams& params, |
| 420 ZygoteForkDelegate* forkdelegate) { | 435 ZygoteForkDelegate* forkdelegate) { |
| 421 g_am_zygote_or_renderer = true; | 436 g_am_zygote_or_renderer = true; |
| 422 sandbox::InitLibcUrandomOverrides(); | 437 sandbox::InitLibcUrandomOverrides(); |
| 423 | 438 |
| 424 LinuxSandbox* linux_sandbox = LinuxSandbox::GetInstance(); | 439 LinuxSandbox* linux_sandbox = LinuxSandbox::GetInstance(); |
| 425 // This will pre-initialize the various sandboxes that need it. | 440 // This will pre-initialize the various sandboxes that need it. |
| 426 linux_sandbox->PreinitializeSandbox(); | 441 linux_sandbox->PreinitializeSandbox(); |
| 427 | 442 |
| 428 if (forkdelegate != NULL) { | 443 if (forkdelegate != NULL) { |
| 429 VLOG(1) << "ZygoteMain: initializing fork delegate"; | 444 VLOG(1) << "ZygoteMain: initializing fork delegate"; |
| 430 forkdelegate->Init(GetSandboxFD()); | 445 forkdelegate->Init(GetSandboxFD()); |
| 431 } else { | 446 } else { |
| 432 VLOG(1) << "ZygoteMain: fork delegate is NULL"; | 447 VLOG(1) << "ZygoteMain: fork delegate is NULL"; |
| 433 } | 448 } |
| 434 | 449 |
| 435 // Turn on the sandbox. | 450 // Turn on the first layer of the sandbox if the configuration warrants it. |
| 436 bool using_suid_sandbox = false; | 451 EnterLayerOneSandbox(linux_sandbox); |
| 437 bool has_started_new_init = false; | |
| 438 | |
| 439 if (!EnterSuidSandbox(linux_sandbox, | |
| 440 &using_suid_sandbox, | |
| 441 &has_started_new_init)) { | |
| 442 LOG(FATAL) << "Failed to enter sandbox. Fail safe abort. (errno: " | |
| 443 << errno << ")"; | |
| 444 return false; | |
| 445 } | |
| 446 | |
| 447 sandbox::SetuidSandboxClient* setuid_sandbox = | |
| 448 linux_sandbox->setuid_sandbox_client(); | |
| 449 | |
| 450 if (setuid_sandbox->IsInNewPIDNamespace() && !has_started_new_init) { | |
| 451 LOG(ERROR) << "The SUID sandbox created a new PID namespace but Zygote " | |
| 452 "is not the init process. Please, make sure the SUID " | |
| 453 "binary is up to date."; | |
| 454 } | |
| 455 | 452 |
| 456 int sandbox_flags = linux_sandbox->GetStatus(); | 453 int sandbox_flags = linux_sandbox->GetStatus(); |
| 457 | 454 |
| 458 Zygote zygote(sandbox_flags, forkdelegate); | 455 Zygote zygote(sandbox_flags, forkdelegate); |
| 459 // This function call can return multiple times, once per fork(). | 456 // This function call can return multiple times, once per fork(). |
| 460 return zygote.ProcessRequests(); | 457 return zygote.ProcessRequests(); |
| 461 } | 458 } |
| 462 | 459 |
| 463 } // namespace content | 460 } // namespace content |
| OLD | NEW |