| 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/browser/zygote_host/zygote_host_impl_linux.h" | 5 #include "content/browser/zygote_host/zygote_host_impl_linux.h" |
| 6 | 6 |
| 7 #include <string.h> | 7 #include <string.h> |
| 8 #include <sys/socket.h> | 8 #include <sys/socket.h> |
| 9 #include <sys/stat.h> | 9 #include <sys/stat.h> |
| 10 #include <sys/types.h> | 10 #include <sys/types.h> |
| (...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 214 } else { | 214 } else { |
| 215 // Not using the SUID sandbox. | 215 // Not using the SUID sandbox. |
| 216 // Note that ~base::Process() will reset the internal value, but there's no | 216 // Note that ~base::Process() will reset the internal value, but there's no |
| 217 // real "handle" on POSIX so that is safe. | 217 // real "handle" on POSIX so that is safe. |
| 218 pid_ = process.Pid(); | 218 pid_ = process.Pid(); |
| 219 } | 219 } |
| 220 | 220 |
| 221 close(fds[1]); | 221 close(fds[1]); |
| 222 control_fd_ = fds[0]; | 222 control_fd_ = fds[0]; |
| 223 | 223 |
| 224 Pickle pickle; | 224 base::Pickle pickle; |
| 225 pickle.WriteInt(kZygoteCommandGetSandboxStatus); | 225 pickle.WriteInt(kZygoteCommandGetSandboxStatus); |
| 226 if (!SendMessage(pickle, NULL)) | 226 if (!SendMessage(pickle, NULL)) |
| 227 LOG(FATAL) << "Cannot communicate with zygote"; | 227 LOG(FATAL) << "Cannot communicate with zygote"; |
| 228 // We don't wait for the reply. We'll read it in ReadReply. | 228 // We don't wait for the reply. We'll read it in ReadReply. |
| 229 } | 229 } |
| 230 | 230 |
| 231 void ZygoteHostImpl::TearDownAfterLastChild() { | 231 void ZygoteHostImpl::TearDownAfterLastChild() { |
| 232 bool do_teardown = false; | 232 bool do_teardown = false; |
| 233 { | 233 { |
| 234 base::AutoLock lock(child_tracking_lock_); | 234 base::AutoLock lock(child_tracking_lock_); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 268 size_t num_erased = list_of_running_zygote_children_.erase(process); | 268 size_t num_erased = list_of_running_zygote_children_.erase(process); |
| 269 DCHECK_EQ(1U, num_erased); | 269 DCHECK_EQ(1U, num_erased); |
| 270 do_teardown = should_teardown_after_last_child_exits_ && | 270 do_teardown = should_teardown_after_last_child_exits_ && |
| 271 list_of_running_zygote_children_.empty(); | 271 list_of_running_zygote_children_.empty(); |
| 272 } | 272 } |
| 273 if (do_teardown) { | 273 if (do_teardown) { |
| 274 TearDown(); | 274 TearDown(); |
| 275 } | 275 } |
| 276 } | 276 } |
| 277 | 277 |
| 278 bool ZygoteHostImpl::SendMessage(const Pickle& data, | 278 bool ZygoteHostImpl::SendMessage(const base::Pickle& data, |
| 279 const std::vector<int>* fds) { | 279 const std::vector<int>* fds) { |
| 280 DCHECK_NE(-1, control_fd_); | 280 DCHECK_NE(-1, control_fd_); |
| 281 CHECK(data.size() <= kZygoteMaxMessageLength) | 281 CHECK(data.size() <= kZygoteMaxMessageLength) |
| 282 << "Trying to send too-large message to zygote (sending " << data.size() | 282 << "Trying to send too-large message to zygote (sending " << data.size() |
| 283 << " bytes, max is " << kZygoteMaxMessageLength << ")"; | 283 << " bytes, max is " << kZygoteMaxMessageLength << ")"; |
| 284 CHECK(!fds || fds->size() <= UnixDomainSocket::kMaxFileDescriptors) | 284 CHECK(!fds || fds->size() <= UnixDomainSocket::kMaxFileDescriptors) |
| 285 << "Trying to send message with too many file descriptors to zygote " | 285 << "Trying to send message with too many file descriptors to zygote " |
| 286 << "(sending " << fds->size() << ", max is " | 286 << "(sending " << fds->size() << ", max is " |
| 287 << UnixDomainSocket::kMaxFileDescriptors << ")"; | 287 << UnixDomainSocket::kMaxFileDescriptors << ")"; |
| 288 | 288 |
| (...skipping 18 matching lines...) Expand all Loading... |
| 307 UMA_HISTOGRAM_SPARSE_SLOWLY("Linux.SandboxStatus", sandbox_status_); | 307 UMA_HISTOGRAM_SPARSE_SLOWLY("Linux.SandboxStatus", sandbox_status_); |
| 308 } | 308 } |
| 309 | 309 |
| 310 return HANDLE_EINTR(read(control_fd_, buf, buf_len)); | 310 return HANDLE_EINTR(read(control_fd_, buf, buf_len)); |
| 311 } | 311 } |
| 312 | 312 |
| 313 pid_t ZygoteHostImpl::ForkRequest(const std::vector<std::string>& argv, | 313 pid_t ZygoteHostImpl::ForkRequest(const std::vector<std::string>& argv, |
| 314 scoped_ptr<FileDescriptorInfo> mapping, | 314 scoped_ptr<FileDescriptorInfo> mapping, |
| 315 const std::string& process_type) { | 315 const std::string& process_type) { |
| 316 DCHECK(init_); | 316 DCHECK(init_); |
| 317 Pickle pickle; | 317 base::Pickle pickle; |
| 318 | 318 |
| 319 int raw_socks[2]; | 319 int raw_socks[2]; |
| 320 PCHECK(0 == socketpair(AF_UNIX, SOCK_SEQPACKET, 0, raw_socks)); | 320 PCHECK(0 == socketpair(AF_UNIX, SOCK_SEQPACKET, 0, raw_socks)); |
| 321 base::ScopedFD my_sock(raw_socks[0]); | 321 base::ScopedFD my_sock(raw_socks[0]); |
| 322 base::ScopedFD peer_sock(raw_socks[1]); | 322 base::ScopedFD peer_sock(raw_socks[1]); |
| 323 CHECK(UnixDomainSocket::EnableReceiveProcessId(my_sock.get())); | 323 CHECK(UnixDomainSocket::EnableReceiveProcessId(my_sock.get())); |
| 324 | 324 |
| 325 pickle.WriteInt(kZygoteCommandFork); | 325 pickle.WriteInt(kZygoteCommandFork); |
| 326 pickle.WriteString(process_type); | 326 pickle.WriteString(process_type); |
| 327 pickle.WriteInt(argv.size()); | 327 pickle.WriteInt(argv.size()); |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 371 sizeof(kZygoteChildPingMessage))) { | 371 sizeof(kZygoteChildPingMessage))) { |
| 372 // Zygote children should still be trustworthy when they're supposed to | 372 // Zygote children should still be trustworthy when they're supposed to |
| 373 // ping us, so something's broken if we don't receive a valid ping. | 373 // ping us, so something's broken if we don't receive a valid ping. |
| 374 LOG(ERROR) << "Did not receive ping from zygote child"; | 374 LOG(ERROR) << "Did not receive ping from zygote child"; |
| 375 NOTREACHED(); | 375 NOTREACHED(); |
| 376 real_pid = -1; | 376 real_pid = -1; |
| 377 } | 377 } |
| 378 my_sock.reset(); | 378 my_sock.reset(); |
| 379 | 379 |
| 380 // Always send PID back to zygote. | 380 // Always send PID back to zygote. |
| 381 Pickle pid_pickle; | 381 base::Pickle pid_pickle; |
| 382 pid_pickle.WriteInt(kZygoteCommandForkRealPID); | 382 pid_pickle.WriteInt(kZygoteCommandForkRealPID); |
| 383 pid_pickle.WriteInt(real_pid); | 383 pid_pickle.WriteInt(real_pid); |
| 384 if (!SendMessage(pid_pickle, NULL)) | 384 if (!SendMessage(pid_pickle, NULL)) |
| 385 return base::kNullProcessHandle; | 385 return base::kNullProcessHandle; |
| 386 } | 386 } |
| 387 | 387 |
| 388 // Read the reply, which pickles the PID and an optional UMA enumeration. | 388 // Read the reply, which pickles the PID and an optional UMA enumeration. |
| 389 static const unsigned kMaxReplyLength = 2048; | 389 static const unsigned kMaxReplyLength = 2048; |
| 390 char buf[kMaxReplyLength]; | 390 char buf[kMaxReplyLength]; |
| 391 const ssize_t len = ReadReply(buf, sizeof(buf)); | 391 const ssize_t len = ReadReply(buf, sizeof(buf)); |
| 392 | 392 |
| 393 Pickle reply_pickle(buf, len); | 393 base::Pickle reply_pickle(buf, len); |
| 394 PickleIterator iter(reply_pickle); | 394 base::PickleIterator iter(reply_pickle); |
| 395 if (len <= 0 || !iter.ReadInt(&pid)) | 395 if (len <= 0 || !iter.ReadInt(&pid)) |
| 396 return base::kNullProcessHandle; | 396 return base::kNullProcessHandle; |
| 397 | 397 |
| 398 // If there is a nonempty UMA name string, then there is a UMA | 398 // If there is a nonempty UMA name string, then there is a UMA |
| 399 // enumeration to record. | 399 // enumeration to record. |
| 400 std::string uma_name; | 400 std::string uma_name; |
| 401 int uma_sample; | 401 int uma_sample; |
| 402 int uma_boundary_value; | 402 int uma_boundary_value; |
| 403 if (iter.ReadString(&uma_name) && | 403 if (iter.ReadString(&uma_name) && |
| 404 !uma_name.empty() && | 404 !uma_name.empty() && |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 506 base::EnsureProcessGetsReaped(sandbox_helper_process.Pid()); | 506 base::EnsureProcessGetsReaped(sandbox_helper_process.Pid()); |
| 507 } else if (!use_suid_sandbox_for_adj_oom_score_) { | 507 } else if (!use_suid_sandbox_for_adj_oom_score_) { |
| 508 if (!base::AdjustOOMScore(pid, score)) | 508 if (!base::AdjustOOMScore(pid, score)) |
| 509 PLOG(ERROR) << "Failed to adjust OOM score of renderer with pid " << pid; | 509 PLOG(ERROR) << "Failed to adjust OOM score of renderer with pid " << pid; |
| 510 } | 510 } |
| 511 } | 511 } |
| 512 #endif | 512 #endif |
| 513 | 513 |
| 514 void ZygoteHostImpl::EnsureProcessTerminated(pid_t process) { | 514 void ZygoteHostImpl::EnsureProcessTerminated(pid_t process) { |
| 515 DCHECK(init_); | 515 DCHECK(init_); |
| 516 Pickle pickle; | 516 base::Pickle pickle; |
| 517 | 517 |
| 518 pickle.WriteInt(kZygoteCommandReap); | 518 pickle.WriteInt(kZygoteCommandReap); |
| 519 pickle.WriteInt(process); | 519 pickle.WriteInt(process); |
| 520 if (!SendMessage(pickle, NULL)) | 520 if (!SendMessage(pickle, NULL)) |
| 521 LOG(ERROR) << "Failed to send Reap message to zygote"; | 521 LOG(ERROR) << "Failed to send Reap message to zygote"; |
| 522 ZygoteChildDied(process); | 522 ZygoteChildDied(process); |
| 523 } | 523 } |
| 524 | 524 |
| 525 base::TerminationStatus ZygoteHostImpl::GetTerminationStatus( | 525 base::TerminationStatus ZygoteHostImpl::GetTerminationStatus( |
| 526 base::ProcessHandle handle, | 526 base::ProcessHandle handle, |
| 527 bool known_dead, | 527 bool known_dead, |
| 528 int* exit_code) { | 528 int* exit_code) { |
| 529 DCHECK(init_); | 529 DCHECK(init_); |
| 530 Pickle pickle; | 530 base::Pickle pickle; |
| 531 pickle.WriteInt(kZygoteCommandGetTerminationStatus); | 531 pickle.WriteInt(kZygoteCommandGetTerminationStatus); |
| 532 pickle.WriteBool(known_dead); | 532 pickle.WriteBool(known_dead); |
| 533 pickle.WriteInt(handle); | 533 pickle.WriteInt(handle); |
| 534 | 534 |
| 535 static const unsigned kMaxMessageLength = 128; | 535 static const unsigned kMaxMessageLength = 128; |
| 536 char buf[kMaxMessageLength]; | 536 char buf[kMaxMessageLength]; |
| 537 ssize_t len; | 537 ssize_t len; |
| 538 { | 538 { |
| 539 base::AutoLock lock(control_lock_); | 539 base::AutoLock lock(control_lock_); |
| 540 if (!SendMessage(pickle, NULL)) | 540 if (!SendMessage(pickle, NULL)) |
| 541 LOG(ERROR) << "Failed to send GetTerminationStatus message to zygote"; | 541 LOG(ERROR) << "Failed to send GetTerminationStatus message to zygote"; |
| 542 len = ReadReply(buf, sizeof(buf)); | 542 len = ReadReply(buf, sizeof(buf)); |
| 543 } | 543 } |
| 544 | 544 |
| 545 // Set this now to handle the error cases. | 545 // Set this now to handle the error cases. |
| 546 if (exit_code) | 546 if (exit_code) |
| 547 *exit_code = RESULT_CODE_NORMAL_EXIT; | 547 *exit_code = RESULT_CODE_NORMAL_EXIT; |
| 548 int status = base::TERMINATION_STATUS_NORMAL_TERMINATION; | 548 int status = base::TERMINATION_STATUS_NORMAL_TERMINATION; |
| 549 | 549 |
| 550 if (len == -1) { | 550 if (len == -1) { |
| 551 LOG(WARNING) << "Error reading message from zygote: " << errno; | 551 LOG(WARNING) << "Error reading message from zygote: " << errno; |
| 552 } else if (len == 0) { | 552 } else if (len == 0) { |
| 553 LOG(WARNING) << "Socket closed prematurely."; | 553 LOG(WARNING) << "Socket closed prematurely."; |
| 554 } else { | 554 } else { |
| 555 Pickle read_pickle(buf, len); | 555 base::Pickle read_pickle(buf, len); |
| 556 int tmp_status, tmp_exit_code; | 556 int tmp_status, tmp_exit_code; |
| 557 PickleIterator iter(read_pickle); | 557 base::PickleIterator iter(read_pickle); |
| 558 if (!iter.ReadInt(&tmp_status) || !iter.ReadInt(&tmp_exit_code)) { | 558 if (!iter.ReadInt(&tmp_status) || !iter.ReadInt(&tmp_exit_code)) { |
| 559 LOG(WARNING) | 559 LOG(WARNING) |
| 560 << "Error parsing GetTerminationStatus response from zygote."; | 560 << "Error parsing GetTerminationStatus response from zygote."; |
| 561 } else { | 561 } else { |
| 562 if (exit_code) | 562 if (exit_code) |
| 563 *exit_code = tmp_exit_code; | 563 *exit_code = tmp_exit_code; |
| 564 status = tmp_status; | 564 status = tmp_status; |
| 565 } | 565 } |
| 566 } | 566 } |
| 567 | 567 |
| (...skipping 25 matching lines...) Expand all Loading... |
| 593 } | 593 } |
| 594 | 594 |
| 595 if (!sandbox::Credentials::CanCreateProcessInNewUserNS()) { | 595 if (!sandbox::Credentials::CanCreateProcessInNewUserNS()) { |
| 596 return false; | 596 return false; |
| 597 } | 597 } |
| 598 | 598 |
| 599 return true; | 599 return true; |
| 600 } | 600 } |
| 601 | 601 |
| 602 } // namespace content | 602 } // namespace content |
| OLD | NEW |