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/zygote/zygote_linux.h" 6 7 #include <fcntl.h> 8 #include <string.h> 9 #include <sys/socket.h> 10 #include <sys/types.h> 11 #include <sys/wait.h> 12 13 #include "base/command_line.h" 14 #include "base/debug/trace_event.h" 15 #include "base/file_util.h" 16 #include "base/linux_util.h" 17 #include "base/logging.h" 18 #include "base/pickle.h" 19 #include "base/posix/eintr_wrapper.h" 20 #include "base/posix/global_descriptors.h" 21 #include "base/posix/unix_domain_socket_linux.h" 22 #include "base/process/kill.h" 23 #include "content/common/child_process_sandbox_support_impl_linux.h" 24 #include "content/common/sandbox_linux/sandbox_linux.h" 25 #include "content/common/set_process_title.h" 26 #include "content/common/zygote_commands_linux.h" 27 #include "content/public/common/content_descriptors.h" 28 #include "content/public/common/result_codes.h" 29 #include "content/public/common/sandbox_linux.h" 30 #include "content/public/common/zygote_fork_delegate_linux.h" 31 #include "ipc/ipc_channel.h" 32 #include "ipc/ipc_switches.h" 33 34 // See http://code.google.com/p/chromium/wiki/LinuxZygote 35 36 namespace content { 37 38 namespace { 39 40 // NOP function. See below where this handler is installed. 41 void SIGCHLDHandler(int signal) { 42 } 43 44 int LookUpFd(const base::GlobalDescriptors::Mapping& fd_mapping, uint32_t key) { 45 for (size_t index = 0; index < fd_mapping.size(); ++index) { 46 if (fd_mapping[index].first == key) 47 return fd_mapping[index].second; 48 } 49 return -1; 50 } 51 52 } // namespace 53 54 Zygote::Zygote(int sandbox_flags, 55 ZygoteForkDelegate* helper) 56 : sandbox_flags_(sandbox_flags), 57 helper_(helper), 58 initial_uma_sample_(0), 59 initial_uma_boundary_value_(0) { 60 if (helper_) { 61 helper_->InitialUMA(&initial_uma_name_, 62 &initial_uma_sample_, 63 &initial_uma_boundary_value_); 64 } 65 } 66 67 Zygote::~Zygote() { 68 } 69 70 bool Zygote::ProcessRequests() { 71 // A SOCK_SEQPACKET socket is installed in fd 3. We get commands from the 72 // browser on it. 73 // A SOCK_DGRAM is installed in fd 5. This is the sandbox IPC channel. 74 // See http://code.google.com/p/chromium/wiki/LinuxSandboxIPC 75 76 // We need to accept SIGCHLD, even though our handler is a no-op because 77 // otherwise we cannot wait on children. (According to POSIX 2001.) 78 struct sigaction action; 79 memset(&action, 0, sizeof(action)); 80 action.sa_handler = &SIGCHLDHandler; 81 CHECK(sigaction(SIGCHLD, &action, NULL) == 0); 82 83 if (UsingSUIDSandbox()) { 84 // Let the ZygoteHost know we are ready to go. 85 // The receiving code is in content/browser/zygote_host_linux.cc. 86 std::vector<int> empty; 87 bool r = UnixDomainSocket::SendMsg(kZygoteSocketPairFd, 88 kZygoteHelloMessage, 89 sizeof(kZygoteHelloMessage), empty); 90 #if defined(OS_CHROMEOS) 91 LOG_IF(WARNING, !r) << "Sending zygote magic failed"; 92 // Exit normally on chromeos because session manager may send SIGTERM 93 // right after the process starts and it may fail to send zygote magic 94 // number to browser process. 95 if (!r) 96 _exit(RESULT_CODE_NORMAL_EXIT); 97 #else 98 CHECK(r) << "Sending zygote magic failed"; 99 #endif 100 } 101 102 for (;;) { 103 // This function call can return multiple times, once per fork(). 104 if (HandleRequestFromBrowser(kZygoteSocketPairFd)) 105 return true; 106 } 107 } 108 109 bool Zygote::GetProcessInfo(base::ProcessHandle pid, 110 ZygoteProcessInfo* process_info) { 111 DCHECK(process_info); 112 const ZygoteProcessMap::const_iterator it = process_info_map_.find(pid); 113 if (it == process_info_map_.end()) { 114 return false; 115 } 116 *process_info = it->second; 117 return true; 118 } 119 120 bool Zygote::UsingSUIDSandbox() const { 121 return sandbox_flags_ & kSandboxLinuxSUID; 122 } 123 124 bool Zygote::HandleRequestFromBrowser(int fd) { 125 std::vector<int> fds; 126 char buf[kZygoteMaxMessageLength]; 127 const ssize_t len = UnixDomainSocket::RecvMsg(fd, buf, sizeof(buf), &fds); 128 129 if (len == 0 || (len == -1 && errno == ECONNRESET)) { 130 // EOF from the browser. We should die. 131 _exit(0); 132 return false; 133 } 134 135 if (len == -1) { 136 PLOG(ERROR) << "Error reading message from browser"; 137 return false; 138 } 139 140 Pickle pickle(buf, len); 141 PickleIterator iter(pickle); 142 143 int kind; 144 if (pickle.ReadInt(&iter, &kind)) { 145 switch (kind) { 146 case kZygoteCommandFork: 147 // This function call can return multiple times, once per fork(). 148 return HandleForkRequest(fd, pickle, iter, fds); 149 150 case kZygoteCommandReap: 151 if (!fds.empty()) 152 break; 153 HandleReapRequest(fd, pickle, iter); 154 return false; 155 case kZygoteCommandGetTerminationStatus: 156 if (!fds.empty()) 157 break; 158 HandleGetTerminationStatus(fd, pickle, iter); 159 return false; 160 case kZygoteCommandGetSandboxStatus: 161 HandleGetSandboxStatus(fd, pickle, iter); 162 return false; 163 default: 164 NOTREACHED(); 165 break; 166 } 167 } 168 169 LOG(WARNING) << "Error parsing message from browser"; 170 for (std::vector<int>::const_iterator 171 i = fds.begin(); i != fds.end(); ++i) 172 close(*i); 173 return false; 174 } 175 176 // TODO(jln): remove callers to this broken API. See crbug.com/274855. 177 void Zygote::HandleReapRequest(int fd, 178 const Pickle& pickle, 179 PickleIterator iter) { 180 base::ProcessId child; 181 182 if (!pickle.ReadInt(&iter, &child)) { 183 LOG(WARNING) << "Error parsing reap request from browser"; 184 return; 185 } 186 187 ZygoteProcessInfo child_info; 188 if (!GetProcessInfo(child, &child_info)) { 189 LOG(ERROR) << "Child not found!"; 190 NOTREACHED(); 191 return; 192 } 193 194 if (!child_info.started_from_helper) { 195 // TODO(jln): this old code is completely broken. See crbug.com/274855. 196 base::EnsureProcessTerminated(child_info.internal_pid); 197 } else { 198 // For processes from the helper, send a GetTerminationStatus request 199 // with known_dead set to true. 200 // This is not perfect, as the process may be killed instantly, but is 201 // better than ignoring the request. 202 base::TerminationStatus status; 203 int exit_code; 204 bool got_termination_status = 205 GetTerminationStatus(child, true /* known_dead */, &status, &exit_code); 206 DCHECK(got_termination_status); 207 } 208 process_info_map_.erase(child); 209 } 210 211 bool Zygote::GetTerminationStatus(base::ProcessHandle real_pid, 212 bool known_dead, 213 base::TerminationStatus* status, 214 int* exit_code) { 215 216 ZygoteProcessInfo child_info; 217 if (!GetProcessInfo(real_pid, &child_info)) { 218 LOG(ERROR) << "Zygote::GetTerminationStatus for unknown PID " 219 << real_pid; 220 NOTREACHED(); 221 return false; 222 } 223 // We know about |real_pid|. 224 const base::ProcessHandle child = child_info.internal_pid; 225 if (child_info.started_from_helper) { 226 // Let the helper handle the request. 227 DCHECK(helper_); 228 if (!helper_->GetTerminationStatus(child, known_dead, status, exit_code)) { 229 return false; 230 } 231 } else { 232 // Handle the request directly. 233 if (known_dead) { 234 *status = base::GetKnownDeadTerminationStatus(child, exit_code); 235 } else { 236 // We don't know if the process is dying, so get its status but don't 237 // wait. 238 *status = base::GetTerminationStatus(child, exit_code); 239 } 240 } 241 // Successfully got a status for |real_pid|. 242 if (*status != base::TERMINATION_STATUS_STILL_RUNNING) { 243 // Time to forget about this process. 244 process_info_map_.erase(real_pid); 245 } 246 return true; 247 } 248 249 void Zygote::HandleGetTerminationStatus(int fd, 250 const Pickle& pickle, 251 PickleIterator iter) { 252 bool known_dead; 253 base::ProcessHandle child_requested; 254 255 if (!pickle.ReadBool(&iter, &known_dead) || 256 !pickle.ReadInt(&iter, &child_requested)) { 257 LOG(WARNING) << "Error parsing GetTerminationStatus request " 258 << "from browser"; 259 return; 260 } 261 262 base::TerminationStatus status; 263 int exit_code; 264 265 bool got_termination_status = 266 GetTerminationStatus(child_requested, known_dead, &status, &exit_code); 267 if (!got_termination_status) { 268 // Assume that if we can't find the child in the sandbox, then 269 // it terminated normally. 270 NOTREACHED(); 271 status = base::TERMINATION_STATUS_NORMAL_TERMINATION; 272 exit_code = RESULT_CODE_NORMAL_EXIT; 273 } 274 275 Pickle write_pickle; 276 write_pickle.WriteInt(static_cast<int>(status)); 277 write_pickle.WriteInt(exit_code); 278 ssize_t written = 279 HANDLE_EINTR(write(fd, write_pickle.data(), write_pickle.size())); 280 if (written != static_cast<ssize_t>(write_pickle.size())) 281 PLOG(ERROR) << "write"; 282 } 283 284 int Zygote::ForkWithRealPid(const std::string& process_type, 285 const base::GlobalDescriptors::Mapping& fd_mapping, 286 const std::string& channel_switch, 287 std::string* uma_name, 288 int* uma_sample, 289 int* uma_boundary_value) { 290 const bool use_helper = (helper_ && helper_->CanHelp(process_type, 291 uma_name, 292 uma_sample, 293 uma_boundary_value)); 294 int dummy_fd; 295 ino_t dummy_inode; 296 int pipe_fds[2] = { -1, -1 }; 297 base::ProcessId pid = 0; 298 299 dummy_fd = socket(PF_UNIX, SOCK_DGRAM, 0); 300 if (dummy_fd < 0) { 301 LOG(ERROR) << "Failed to create dummy FD"; 302 goto error; 303 } 304 if (!base::FileDescriptorGetInode(&dummy_inode, dummy_fd)) { 305 LOG(ERROR) << "Failed to get inode for dummy FD"; 306 goto error; 307 } 308 if (pipe(pipe_fds) != 0) { 309 LOG(ERROR) << "Failed to create pipe"; 310 goto error; 311 } 312 313 if (use_helper) { 314 std::vector<int> fds; 315 int ipc_channel_fd = LookUpFd(fd_mapping, kPrimaryIPCChannel); 316 if (ipc_channel_fd < 0) { 317 DLOG(ERROR) << "Failed to find kPrimaryIPCChannel in FD mapping"; 318 goto error; 319 } 320 fds.push_back(ipc_channel_fd); // kBrowserFDIndex 321 fds.push_back(dummy_fd); // kDummyFDIndex 322 fds.push_back(pipe_fds[0]); // kParentFDIndex 323 pid = helper_->Fork(fds); 324 } else { 325 pid = fork(); 326 } 327 if (pid < 0) { 328 goto error; 329 } else if (pid == 0) { 330 // In the child process. 331 close(pipe_fds[1]); 332 base::ProcessId real_pid; 333 // Wait until the parent process has discovered our PID. We 334 // should not fork any child processes (which the seccomp 335 // sandbox does) until then, because that can interfere with the 336 // parent's discovery of our PID. 337 if (!base::ReadFromFD(pipe_fds[0], reinterpret_cast<char*>(&real_pid), 338 sizeof(real_pid))) { 339 LOG(FATAL) << "Failed to synchronise with parent zygote process"; 340 } 341 if (real_pid <= 0) { 342 LOG(FATAL) << "Invalid pid from parent zygote"; 343 } 344 #if defined(OS_LINUX) 345 // Sandboxed processes need to send the global, non-namespaced PID when 346 // setting up an IPC channel to their parent. 347 IPC::Channel::SetGlobalPid(real_pid); 348 // Force the real PID so chrome event data have a PID that corresponds 349 // to system trace event data. 350 base::debug::TraceLog::GetInstance()->SetProcessID( 351 static_cast<int>(real_pid)); 352 #endif 353 close(pipe_fds[0]); 354 close(dummy_fd); 355 return 0; 356 } else { 357 // In the parent process. 358 close(dummy_fd); 359 dummy_fd = -1; 360 close(pipe_fds[0]); 361 pipe_fds[0] = -1; 362 base::ProcessId real_pid; 363 if (UsingSUIDSandbox()) { 364 uint8_t reply_buf[512]; 365 Pickle request; 366 request.WriteInt(LinuxSandbox::METHOD_GET_CHILD_WITH_INODE); 367 request.WriteUInt64(dummy_inode); 368 369 const ssize_t r = UnixDomainSocket::SendRecvMsg( 370 GetSandboxFD(), reply_buf, sizeof(reply_buf), NULL, 371 request); 372 if (r == -1) { 373 LOG(ERROR) << "Failed to get child process's real PID"; 374 goto error; 375 } 376 377 Pickle reply(reinterpret_cast<char*>(reply_buf), r); 378 PickleIterator iter(reply); 379 if (!reply.ReadInt(&iter, &real_pid)) 380 goto error; 381 if (real_pid <= 0) { 382 // METHOD_GET_CHILD_WITH_INODE failed. Did the child die already? 383 LOG(ERROR) << "METHOD_GET_CHILD_WITH_INODE failed"; 384 goto error; 385 } 386 } else { 387 // If no SUID sandbox is involved then no pid translation is 388 // necessary. 389 real_pid = pid; 390 } 391 392 // Now set-up this process to be tracked by the Zygote. 393 if (process_info_map_.find(real_pid) != process_info_map_.end()) { 394 LOG(ERROR) << "Already tracking PID " << real_pid; 395 NOTREACHED(); 396 } 397 process_info_map_[real_pid].internal_pid = pid; 398 process_info_map_[real_pid].started_from_helper = use_helper; 399 400 if (use_helper) { 401 if (!helper_->AckChild(pipe_fds[1], channel_switch)) { 402 LOG(ERROR) << "Failed to synchronise with zygote fork helper"; 403 goto error; 404 } 405 } else { 406 int written = 407 HANDLE_EINTR(write(pipe_fds[1], &real_pid, sizeof(real_pid))); 408 if (written != sizeof(real_pid)) { 409 LOG(ERROR) << "Failed to synchronise with child process"; 410 goto error; 411 } 412 } 413 close(pipe_fds[1]); 414 return real_pid; 415 } 416 417 error: 418 if (pid > 0) { 419 if (waitpid(pid, NULL, WNOHANG) == -1) 420 LOG(ERROR) << "Failed to wait for process"; 421 } 422 if (dummy_fd >= 0) 423 close(dummy_fd); 424 if (pipe_fds[0] >= 0) 425 close(pipe_fds[0]); 426 if (pipe_fds[1] >= 0) 427 close(pipe_fds[1]); 428 return -1; 429 } 430 431 base::ProcessId Zygote::ReadArgsAndFork(const Pickle& pickle, 432 PickleIterator iter, 433 std::vector<int>& fds, 434 std::string* uma_name, 435 int* uma_sample, 436 int* uma_boundary_value) { 437 std::vector<std::string> args; 438 int argc = 0; 439 int numfds = 0; 440 base::GlobalDescriptors::Mapping mapping; 441 std::string process_type; 442 std::string channel_id; 443 const std::string channel_id_prefix = std::string("--") 444 + switches::kProcessChannelID + std::string("="); 445 446 if (!pickle.ReadString(&iter, &process_type)) 447 return -1; 448 if (!pickle.ReadInt(&iter, &argc)) 449 return -1; 450 451 for (int i = 0; i < argc; ++i) { 452 std::string arg; 453 if (!pickle.ReadString(&iter, &arg)) 454 return -1; 455 args.push_back(arg); 456 if (arg.compare(0, channel_id_prefix.length(), channel_id_prefix) == 0) 457 channel_id = arg; 458 } 459 460 if (!pickle.ReadInt(&iter, &numfds)) 461 return -1; 462 if (numfds != static_cast<int>(fds.size())) 463 return -1; 464 465 for (int i = 0; i < numfds; ++i) { 466 base::GlobalDescriptors::Key key; 467 if (!pickle.ReadUInt32(&iter, &key)) 468 return -1; 469 mapping.push_back(std::make_pair(key, fds[i])); 470 } 471 472 mapping.push_back(std::make_pair( 473 static_cast<uint32_t>(kSandboxIPCChannel), GetSandboxFD())); 474 475 // Returns twice, once per process. 476 base::ProcessId child_pid = ForkWithRealPid(process_type, mapping, channel_id, 477 uma_name, uma_sample, 478 uma_boundary_value); 479 if (!child_pid) { 480 // This is the child process. 481 482 close(kZygoteSocketPairFd); // Our socket from the browser. 483 if (UsingSUIDSandbox()) 484 close(kZygoteIdFd); // Another socket from the browser. 485 base::GlobalDescriptors::GetInstance()->Reset(mapping); 486 487 // Reset the process-wide command line to our new command line. 488 CommandLine::Reset(); 489 CommandLine::Init(0, NULL); 490 CommandLine::ForCurrentProcess()->InitFromArgv(args); 491 492 // Update the process title. The argv was already cached by the call to 493 // SetProcessTitleFromCommandLine in ChromeMain, so we can pass NULL here 494 // (we don't have the original argv at this point). 495 SetProcessTitleFromCommandLine(NULL); 496 } else if (child_pid < 0) { 497 LOG(ERROR) << "Zygote could not fork: process_type " << process_type 498 << " numfds " << numfds << " child_pid " << child_pid; 499 } 500 return child_pid; 501 } 502 503 bool Zygote::HandleForkRequest(int fd, 504 const Pickle& pickle, 505 PickleIterator iter, 506 std::vector<int>& fds) { 507 std::string uma_name; 508 int uma_sample; 509 int uma_boundary_value; 510 base::ProcessId child_pid = ReadArgsAndFork(pickle, iter, fds, 511 &uma_name, &uma_sample, 512 &uma_boundary_value); 513 if (child_pid == 0) 514 return true; 515 for (std::vector<int>::const_iterator 516 i = fds.begin(); i != fds.end(); ++i) 517 close(*i); 518 if (uma_name.empty()) { 519 // There is no UMA report from this particular fork. 520 // Use the initial UMA report if any, and clear that record for next time. 521 // Note the swap method here is the efficient way to do this, since 522 // we know uma_name is empty. 523 uma_name.swap(initial_uma_name_); 524 uma_sample = initial_uma_sample_; 525 uma_boundary_value = initial_uma_boundary_value_; 526 } 527 // Must always send reply, as ZygoteHost blocks while waiting for it. 528 Pickle reply_pickle; 529 reply_pickle.WriteInt(child_pid); 530 reply_pickle.WriteString(uma_name); 531 if (!uma_name.empty()) { 532 reply_pickle.WriteInt(uma_sample); 533 reply_pickle.WriteInt(uma_boundary_value); 534 } 535 if (HANDLE_EINTR(write(fd, reply_pickle.data(), reply_pickle.size())) != 536 static_cast<ssize_t> (reply_pickle.size())) 537 PLOG(ERROR) << "write"; 538 return false; 539 } 540 541 bool Zygote::HandleGetSandboxStatus(int fd, 542 const Pickle& pickle, 543 PickleIterator iter) { 544 if (HANDLE_EINTR(write(fd, &sandbox_flags_, sizeof(sandbox_flags_))) != 545 sizeof(sandbox_flags_)) { 546 PLOG(ERROR) << "write"; 547 } 548 549 return false; 550 } 551 552 } // namespace content 553