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 3 // found in the LICENSE file. 4 5 #include "content/browser/zygote_host/zygote_host_impl_linux.h" 6 7 #include <string.h> 8 #include <sys/socket.h> 9 #include <sys/stat.h> 10 #include <sys/types.h> 11 #include <unistd.h> 12 13 #include "base/base_switches.h" 14 #include "base/command_line.h" 15 #include "base/environment.h" 16 #include "base/files/file_enumerator.h" 17 #include "base/files/file_util.h" 18 #include "base/files/scoped_file.h" 19 #include "base/linux_util.h" 20 #include "base/logging.h" 21 #include "base/memory/linked_ptr.h" 22 #include "base/memory/scoped_ptr.h" 23 #include "base/memory/scoped_vector.h" 24 #include "base/metrics/histogram.h" 25 #include "base/path_service.h" 26 #include "base/posix/eintr_wrapper.h" 27 #include "base/posix/unix_domain_socket_linux.h" 28 #include "base/process/launch.h" 29 #include "base/process/memory.h" 30 #include "base/process/process_handle.h" 31 #include "base/strings/string_number_conversions.h" 32 #include "base/strings/string_util.h" 33 #include "base/strings/utf_string_conversions.h" 34 #include "base/time/time.h" 35 #include "content/browser/renderer_host/render_sandbox_host_linux.h" 36 #include "content/common/child_process_sandbox_support_impl_linux.h" 37 #include "content/common/zygote_commands_linux.h" 38 #include "content/public/browser/content_browser_client.h" 39 #include "content/public/common/content_switches.h" 40 #include "content/public/common/result_codes.h" 41 #include "sandbox/linux/suid/client/setuid_sandbox_client.h" 42 #include "sandbox/linux/suid/common/sandbox.h" 43 #include "ui/base/ui_base_switches.h" 44 #include "ui/gfx/switches.h" 45 46 #if defined(USE_TCMALLOC) 47 #include "third_party/tcmalloc/chromium/src/gperftools/heap-profiler.h" 48 #endif 49 50 namespace content { 51 52 // Receive a fixed message on fd and return the sender's PID. 53 // Returns true if the message received matches the expected message. 54 static bool ReceiveFixedMessage(int fd, 55 const char* expect_msg, 56 size_t expect_len, 57 base::ProcessId* sender_pid) { 58 char buf[expect_len + 1]; 59 ScopedVector<base::ScopedFD> fds_vec; 60 61 const ssize_t len = UnixDomainSocket::RecvMsgWithPid( 62 fd, buf, sizeof(buf), &fds_vec, sender_pid); 63 if (static_cast<size_t>(len) != expect_len) 64 return false; 65 if (memcmp(buf, expect_msg, expect_len) != 0) 66 return false; 67 if (!fds_vec.empty()) 68 return false; 69 return true; 70 } 71 72 // static 73 ZygoteHost* ZygoteHost::GetInstance() { 74 return ZygoteHostImpl::GetInstance(); 75 } 76 77 ZygoteHostImpl::ZygoteHostImpl() 78 : control_fd_(-1), 79 control_lock_(), 80 pid_(-1), 81 init_(false), 82 using_suid_sandbox_(false), 83 sandbox_binary_(), 84 have_read_sandbox_status_word_(false), 85 sandbox_status_(0), 86 child_tracking_lock_(), 87 list_of_running_zygote_children_(), 88 should_teardown_after_last_child_exits_(false) {} 89 90 ZygoteHostImpl::~ZygoteHostImpl() { TearDown(); } 91 92 // static 93 ZygoteHostImpl* ZygoteHostImpl::GetInstance() { 94 return Singleton<ZygoteHostImpl>::get(); 95 } 96 97 void ZygoteHostImpl::Init(const std::string& sandbox_cmd) { 98 DCHECK(!init_); 99 init_ = true; 100 101 base::FilePath chrome_path; 102 CHECK(PathService::Get(base::FILE_EXE, &chrome_path)); 103 base::CommandLine cmd_line(chrome_path); 104 105 cmd_line.AppendSwitchASCII(switches::kProcessType, switches::kZygoteProcess); 106 107 int fds[2]; 108 CHECK(socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds) == 0); 109 CHECK(UnixDomainSocket::EnableReceiveProcessId(fds[0])); 110 base::FileHandleMappingVector fds_to_map; 111 fds_to_map.push_back(std::make_pair(fds[1], kZygoteSocketPairFd)); 112 113 base::LaunchOptions options; 114 const base::CommandLine& browser_command_line = 115 *base::CommandLine::ForCurrentProcess(); 116 if (browser_command_line.HasSwitch(switches::kZygoteCmdPrefix)) { 117 cmd_line.PrependWrapper( 118 browser_command_line.GetSwitchValueNative(switches::kZygoteCmdPrefix)); 119 } 120 // Append any switches from the browser process that need to be forwarded on 121 // to the zygote/renderers. 122 // Should this list be obtained from browser_render_process_host.cc? 123 static const char* kForwardSwitches[] = { 124 switches::kAllowSandboxDebugging, 125 switches::kDisableSeccompFilterSandbox, 126 switches::kEnableLogging, // Support, e.g., --enable-logging=stderr. 127 // Zygote process needs to know what resources to have loaded when it 128 // becomes a renderer process. 129 switches::kForceDeviceScaleFactor, 130 switches::kLoggingLevel, 131 switches::kNoSandbox, 132 switches::kPpapiInProcess, 133 switches::kRegisterPepperPlugins, 134 switches::kV, 135 switches::kVModule, 136 }; 137 cmd_line.CopySwitchesFrom(browser_command_line, kForwardSwitches, 138 arraysize(kForwardSwitches)); 139 140 GetContentClient()->browser()->AppendExtraCommandLineSwitches(&cmd_line, -1); 141 142 sandbox_binary_ = sandbox_cmd.c_str(); 143 144 // A non empty sandbox_cmd means we want a SUID sandbox. 145 using_suid_sandbox_ = !sandbox_cmd.empty(); 146 147 // Start up the sandbox host process and get the file descriptor for the 148 // renderers to talk to it. 149 const int sfd = RenderSandboxHostLinux::GetInstance()->GetRendererSocket(); 150 fds_to_map.push_back(std::make_pair(sfd, GetSandboxFD())); 151 152 base::ScopedFD dummy_fd; 153 if (using_suid_sandbox_) { 154 scoped_ptr<sandbox::SetuidSandboxClient> 155 sandbox_client(sandbox::SetuidSandboxClient::Create()); 156 sandbox_client->PrependWrapper(&cmd_line); 157 sandbox_client->SetupLaunchOptions(&options, &fds_to_map, &dummy_fd); 158 sandbox_client->SetupLaunchEnvironment(); 159 } 160 161 base::ProcessHandle process = -1; 162 options.fds_to_remap = &fds_to_map; 163 base::LaunchProcess(cmd_line.argv(), options, &process); 164 CHECK(process != -1) << "Failed to launch zygote process"; 165 dummy_fd.reset(); 166 167 if (using_suid_sandbox_) { 168 // The SUID sandbox will execute the zygote in a new PID namespace, and 169 // the main zygote process will then fork from there. Watch now our 170 // elaborate dance to find and validate the zygote's PID. 171 172 // First we receive a message from the zygote boot process. 173 base::ProcessId boot_pid; 174 CHECK(ReceiveFixedMessage( 175 fds[0], kZygoteBootMessage, sizeof(kZygoteBootMessage), &boot_pid)); 176 177 // Within the PID namespace, the zygote boot process thinks it's PID 1, 178 // but its real PID can never be 1. This gives us a reliable test that 179 // the kernel is translating the sender's PID to our namespace. 180 CHECK_GT(boot_pid, 1) 181 << "Received invalid process ID for zygote; kernel might be too old? " 182 "See crbug.com/357670 or try using --" 183 << switches::kDisableSetuidSandbox << " to workaround."; 184 185 // Now receive the message that the zygote's ready to go, along with the 186 // main zygote process's ID. 187 CHECK(ReceiveFixedMessage( 188 fds[0], kZygoteHelloMessage, sizeof(kZygoteHelloMessage), &pid_)); 189 CHECK_GT(pid_, 1); 190 191 if (process != pid_) { 192 // Reap the sandbox. 193 base::EnsureProcessGetsReaped(process); 194 } 195 } else { 196 // Not using the SUID sandbox. 197 pid_ = process; 198 } 199 200 close(fds[1]); 201 control_fd_ = fds[0]; 202 203 Pickle pickle; 204 pickle.WriteInt(kZygoteCommandGetSandboxStatus); 205 if (!SendMessage(pickle, NULL)) 206 LOG(FATAL) << "Cannot communicate with zygote"; 207 // We don't wait for the reply. We'll read it in ReadReply. 208 } 209 210 void ZygoteHostImpl::TearDownAfterLastChild() { 211 bool do_teardown = false; 212 { 213 base::AutoLock lock(child_tracking_lock_); 214 should_teardown_after_last_child_exits_ = true; 215 do_teardown = list_of_running_zygote_children_.empty(); 216 } 217 if (do_teardown) { 218 TearDown(); 219 } 220 } 221 222 // Note: this is also called from the destructor. 223 void ZygoteHostImpl::TearDown() { 224 base::AutoLock lock(control_lock_); 225 if (control_fd_ > -1) { 226 // Closing the IPC channel will act as a notification to exit 227 // to the Zygote. 228 if (IGNORE_EINTR(close(control_fd_))) { 229 PLOG(ERROR) << "Could not close Zygote control channel."; 230 NOTREACHED(); 231 } 232 control_fd_ = -1; 233 } 234 } 235 236 void ZygoteHostImpl::ZygoteChildBorn(pid_t process) { 237 base::AutoLock lock(child_tracking_lock_); 238 bool new_element_inserted = 239 list_of_running_zygote_children_.insert(process).second; 240 DCHECK(new_element_inserted); 241 } 242 243 void ZygoteHostImpl::ZygoteChildDied(pid_t process) { 244 bool do_teardown = false; 245 { 246 base::AutoLock lock(child_tracking_lock_); 247 size_t num_erased = list_of_running_zygote_children_.erase(process); 248 DCHECK_EQ(1U, num_erased); 249 do_teardown = should_teardown_after_last_child_exits_ && 250 list_of_running_zygote_children_.empty(); 251 } 252 if (do_teardown) { 253 TearDown(); 254 } 255 } 256 257 bool ZygoteHostImpl::SendMessage(const Pickle& data, 258 const std::vector<int>* fds) { 259 DCHECK_NE(-1, control_fd_); 260 CHECK(data.size() <= kZygoteMaxMessageLength) 261 << "Trying to send too-large message to zygote (sending " << data.size() 262 << " bytes, max is " << kZygoteMaxMessageLength << ")"; 263 CHECK(!fds || fds->size() <= UnixDomainSocket::kMaxFileDescriptors) 264 << "Trying to send message with too many file descriptors to zygote " 265 << "(sending " << fds->size() << ", max is " 266 << UnixDomainSocket::kMaxFileDescriptors << ")"; 267 268 return UnixDomainSocket::SendMsg(control_fd_, 269 data.data(), data.size(), 270 fds ? *fds : std::vector<int>()); 271 } 272 273 ssize_t ZygoteHostImpl::ReadReply(void* buf, size_t buf_len) { 274 DCHECK_NE(-1, control_fd_); 275 // At startup we send a kZygoteCommandGetSandboxStatus request to the zygote, 276 // but don't wait for the reply. Thus, the first time that we read from the 277 // zygote, we get the reply to that request. 278 if (!have_read_sandbox_status_word_) { 279 if (HANDLE_EINTR(read(control_fd_, &sandbox_status_, 280 sizeof(sandbox_status_))) != 281 sizeof(sandbox_status_)) { 282 return -1; 283 } 284 have_read_sandbox_status_word_ = true; 285 } 286 287 return HANDLE_EINTR(read(control_fd_, buf, buf_len)); 288 } 289 290 pid_t ZygoteHostImpl::ForkRequest( 291 const std::vector<std::string>& argv, 292 const std::vector<FileDescriptorInfo>& mapping, 293 const std::string& process_type) { 294 DCHECK(init_); 295 Pickle pickle; 296 297 int raw_socks[2]; 298 PCHECK(0 == socketpair(AF_UNIX, SOCK_SEQPACKET, 0, raw_socks)); 299 base::ScopedFD my_sock(raw_socks[0]); 300 base::ScopedFD peer_sock(raw_socks[1]); 301 CHECK(UnixDomainSocket::EnableReceiveProcessId(my_sock.get())); 302 303 pickle.WriteInt(kZygoteCommandFork); 304 pickle.WriteString(process_type); 305 pickle.WriteInt(argv.size()); 306 for (std::vector<std::string>::const_iterator 307 i = argv.begin(); i != argv.end(); ++i) 308 pickle.WriteString(*i); 309 310 // Fork requests contain one file descriptor for the PID oracle, and one 311 // more for each file descriptor mapping for the child process. 312 const size_t num_fds_to_send = 1 + mapping.size(); 313 pickle.WriteInt(num_fds_to_send); 314 315 std::vector<int> fds; 316 ScopedVector<base::ScopedFD> autoclose_fds; 317 318 // First FD to send is peer_sock. 319 fds.push_back(peer_sock.get()); 320 autoclose_fds.push_back(new base::ScopedFD(peer_sock.Pass())); 321 322 // The rest come from mapping. 323 for (std::vector<FileDescriptorInfo>::const_iterator 324 i = mapping.begin(); i != mapping.end(); ++i) { 325 pickle.WriteUInt32(i->id); 326 fds.push_back(i->fd.fd); 327 if (i->fd.auto_close) { 328 // Auto-close means we need to close the FDs after they have been passed 329 // to the other process. 330 autoclose_fds.push_back(new base::ScopedFD(i->fd.fd)); 331 } 332 } 333 334 // Sanity check that we've populated |fds| correctly. 335 DCHECK_EQ(num_fds_to_send, fds.size()); 336 337 pid_t pid; 338 { 339 base::AutoLock lock(control_lock_); 340 if (!SendMessage(pickle, &fds)) 341 return base::kNullProcessHandle; 342 autoclose_fds.clear(); 343 344 { 345 char buf[sizeof(kZygoteChildPingMessage) + 1]; 346 ScopedVector<base::ScopedFD> recv_fds; 347 base::ProcessId real_pid; 348 349 ssize_t n = UnixDomainSocket::RecvMsgWithPid( 350 my_sock.get(), buf, sizeof(buf), &recv_fds, &real_pid); 351 if (n != sizeof(kZygoteChildPingMessage) || 352 0 != memcmp(buf, 353 kZygoteChildPingMessage, 354 sizeof(kZygoteChildPingMessage))) { 355 // Zygote children should still be trustworthy when they're supposed to 356 // ping us, so something's broken if we don't receive a valid ping. 357 LOG(ERROR) << "Did not receive ping from zygote child"; 358 NOTREACHED(); 359 real_pid = -1; 360 } 361 my_sock.reset(); 362 363 // Always send PID back to zygote. 364 Pickle pid_pickle; 365 pid_pickle.WriteInt(kZygoteCommandForkRealPID); 366 pid_pickle.WriteInt(real_pid); 367 if (!SendMessage(pid_pickle, NULL)) 368 return base::kNullProcessHandle; 369 } 370 371 // Read the reply, which pickles the PID and an optional UMA enumeration. 372 static const unsigned kMaxReplyLength = 2048; 373 char buf[kMaxReplyLength]; 374 const ssize_t len = ReadReply(buf, sizeof(buf)); 375 376 Pickle reply_pickle(buf, len); 377 PickleIterator iter(reply_pickle); 378 if (len <= 0 || !reply_pickle.ReadInt(&iter, &pid)) 379 return base::kNullProcessHandle; 380 381 // If there is a nonempty UMA name string, then there is a UMA 382 // enumeration to record. 383 std::string uma_name; 384 int uma_sample; 385 int uma_boundary_value; 386 if (reply_pickle.ReadString(&iter, &uma_name) && 387 !uma_name.empty() && 388 reply_pickle.ReadInt(&iter, &uma_sample) && 389 reply_pickle.ReadInt(&iter, &uma_boundary_value)) { 390 // We cannot use the UMA_HISTOGRAM_ENUMERATION macro here, 391 // because that's only for when the name is the same every time. 392 // Here we're using whatever name we got from the other side. 393 // But since it's likely that the same one will be used repeatedly 394 // (even though it's not guaranteed), we cache it here. 395 static base::HistogramBase* uma_histogram; 396 if (!uma_histogram || uma_histogram->histogram_name() != uma_name) { 397 uma_histogram = base::LinearHistogram::FactoryGet( 398 uma_name, 1, 399 uma_boundary_value, 400 uma_boundary_value + 1, 401 base::HistogramBase::kUmaTargetedHistogramFlag); 402 } 403 uma_histogram->Add(uma_sample); 404 } 405 406 if (pid <= 0) 407 return base::kNullProcessHandle; 408 } 409 410 #if !defined(OS_OPENBSD) 411 // This is just a starting score for a renderer or extension (the 412 // only types of processes that will be started this way). It will 413 // get adjusted as time goes on. (This is the same value as 414 // chrome::kLowestRendererOomScore in chrome/chrome_constants.h, but 415 // that's not something we can include here.) 416 const int kLowestRendererOomScore = 300; 417 AdjustRendererOOMScore(pid, kLowestRendererOomScore); 418 #endif 419 420 ZygoteChildBorn(pid); 421 return pid; 422 } 423 424 #if !defined(OS_OPENBSD) 425 void ZygoteHostImpl::AdjustRendererOOMScore(base::ProcessHandle pid, 426 int score) { 427 // 1) You can't change the oom_score_adj of a non-dumpable process 428 // (EPERM) unless you're root. Because of this, we can't set the 429 // oom_adj from the browser process. 430 // 431 // 2) We can't set the oom_score_adj before entering the sandbox 432 // because the zygote is in the sandbox and the zygote is as 433 // critical as the browser process. Its oom_adj value shouldn't 434 // be changed. 435 // 436 // 3) A non-dumpable process can't even change its own oom_score_adj 437 // because it's root owned 0644. The sandboxed processes don't 438 // even have /proc, but one could imagine passing in a descriptor 439 // from outside. 440 // 441 // So, in the normal case, we use the SUID binary to change it for us. 442 // However, Fedora (and other SELinux systems) don't like us touching other 443 // process's oom_score_adj (or oom_adj) values 444 // (https://bugzilla.redhat.com/show_bug.cgi?id=581256). 445 // 446 // The offical way to get the SELinux mode is selinux_getenforcemode, but I 447 // don't want to add another library to the build as it's sure to cause 448 // problems with other, non-SELinux distros. 449 // 450 // So we just check for files in /selinux. This isn't foolproof, but it's not 451 // bad and it's easy. 452 453 static bool selinux; 454 static bool selinux_valid = false; 455 456 if (!selinux_valid) { 457 const base::FilePath kSelinuxPath("/selinux"); 458 base::FileEnumerator en(kSelinuxPath, false, base::FileEnumerator::FILES); 459 bool has_selinux_files = !en.Next().empty(); 460 461 selinux = access(kSelinuxPath.value().c_str(), X_OK) == 0 && 462 has_selinux_files; 463 selinux_valid = true; 464 } 465 466 if (using_suid_sandbox_ && !selinux) { 467 #if defined(USE_TCMALLOC) 468 // If heap profiling is running, these processes are not exiting, at least 469 // on ChromeOS. The easiest thing to do is not launch them when profiling. 470 // TODO(stevenjb): Investigate further and fix. 471 if (IsHeapProfilerRunning()) 472 return; 473 #endif 474 std::vector<std::string> adj_oom_score_cmdline; 475 adj_oom_score_cmdline.push_back(sandbox_binary_); 476 adj_oom_score_cmdline.push_back(sandbox::kAdjustOOMScoreSwitch); 477 adj_oom_score_cmdline.push_back(base::Int64ToString(pid)); 478 adj_oom_score_cmdline.push_back(base::IntToString(score)); 479 480 base::ProcessHandle sandbox_helper_process; 481 base::LaunchOptions options; 482 483 // sandbox_helper_process is a setuid binary. 484 options.allow_new_privs = true; 485 486 if (base::LaunchProcess(adj_oom_score_cmdline, options, 487 &sandbox_helper_process)) { 488 base::EnsureProcessGetsReaped(sandbox_helper_process); 489 } 490 } else if (!using_suid_sandbox_) { 491 if (!base::AdjustOOMScore(pid, score)) 492 PLOG(ERROR) << "Failed to adjust OOM score of renderer with pid " << pid; 493 } 494 } 495 #endif 496 497 void ZygoteHostImpl::EnsureProcessTerminated(pid_t process) { 498 DCHECK(init_); 499 Pickle pickle; 500 501 pickle.WriteInt(kZygoteCommandReap); 502 pickle.WriteInt(process); 503 if (!SendMessage(pickle, NULL)) 504 LOG(ERROR) << "Failed to send Reap message to zygote"; 505 ZygoteChildDied(process); 506 } 507 508 base::TerminationStatus ZygoteHostImpl::GetTerminationStatus( 509 base::ProcessHandle handle, 510 bool known_dead, 511 int* exit_code) { 512 DCHECK(init_); 513 Pickle pickle; 514 pickle.WriteInt(kZygoteCommandGetTerminationStatus); 515 pickle.WriteBool(known_dead); 516 pickle.WriteInt(handle); 517 518 static const unsigned kMaxMessageLength = 128; 519 char buf[kMaxMessageLength]; 520 ssize_t len; 521 { 522 base::AutoLock lock(control_lock_); 523 if (!SendMessage(pickle, NULL)) 524 LOG(ERROR) << "Failed to send GetTerminationStatus message to zygote"; 525 len = ReadReply(buf, sizeof(buf)); 526 } 527 528 // Set this now to handle the error cases. 529 if (exit_code) 530 *exit_code = RESULT_CODE_NORMAL_EXIT; 531 int status = base::TERMINATION_STATUS_NORMAL_TERMINATION; 532 533 if (len == -1) { 534 LOG(WARNING) << "Error reading message from zygote: " << errno; 535 } else if (len == 0) { 536 LOG(WARNING) << "Socket closed prematurely."; 537 } else { 538 Pickle read_pickle(buf, len); 539 int tmp_status, tmp_exit_code; 540 PickleIterator iter(read_pickle); 541 if (!read_pickle.ReadInt(&iter, &tmp_status) || 542 !read_pickle.ReadInt(&iter, &tmp_exit_code)) { 543 LOG(WARNING) 544 << "Error parsing GetTerminationStatus response from zygote."; 545 } else { 546 if (exit_code) 547 *exit_code = tmp_exit_code; 548 status = tmp_status; 549 } 550 } 551 552 if (status != base::TERMINATION_STATUS_STILL_RUNNING) { 553 ZygoteChildDied(handle); 554 } 555 return static_cast<base::TerminationStatus>(status); 556 } 557 558 pid_t ZygoteHostImpl::GetPid() const { 559 return pid_; 560 } 561 562 int ZygoteHostImpl::GetSandboxStatus() const { 563 if (have_read_sandbox_status_word_) 564 return sandbox_status_; 565 return 0; 566 } 567 568 } // namespace content 569