| 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_linux.h" | 5 #include "content/zygote/zygote_linux.h" |
| 6 | 6 |
| 7 #include <fcntl.h> | 7 #include <fcntl.h> |
| 8 #include <string.h> | 8 #include <string.h> |
| 9 #include <sys/socket.h> | 9 #include <sys/socket.h> |
| 10 #include <sys/types.h> | 10 #include <sys/types.h> |
| (...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 178 | 178 |
| 179 if (len == -1) { | 179 if (len == -1) { |
| 180 PLOG(ERROR) << "Error reading message from browser"; | 180 PLOG(ERROR) << "Error reading message from browser"; |
| 181 return false; | 181 return false; |
| 182 } | 182 } |
| 183 | 183 |
| 184 Pickle pickle(buf, len); | 184 Pickle pickle(buf, len); |
| 185 PickleIterator iter(pickle); | 185 PickleIterator iter(pickle); |
| 186 | 186 |
| 187 int kind; | 187 int kind; |
| 188 if (iter.ReadInt(&kind)) { | 188 if (pickle.ReadInt(&iter, &kind)) { |
| 189 switch (kind) { | 189 switch (kind) { |
| 190 case kZygoteCommandFork: | 190 case kZygoteCommandFork: |
| 191 // This function call can return multiple times, once per fork(). | 191 // This function call can return multiple times, once per fork(). |
| 192 return HandleForkRequest(fd, iter, fds.Pass()); | 192 return HandleForkRequest(fd, pickle, iter, fds.Pass()); |
| 193 | 193 |
| 194 case kZygoteCommandReap: | 194 case kZygoteCommandReap: |
| 195 if (!fds.empty()) | 195 if (!fds.empty()) |
| 196 break; | 196 break; |
| 197 HandleReapRequest(fd, iter); | 197 HandleReapRequest(fd, pickle, iter); |
| 198 return false; | 198 return false; |
| 199 case kZygoteCommandGetTerminationStatus: | 199 case kZygoteCommandGetTerminationStatus: |
| 200 if (!fds.empty()) | 200 if (!fds.empty()) |
| 201 break; | 201 break; |
| 202 HandleGetTerminationStatus(fd, iter); | 202 HandleGetTerminationStatus(fd, pickle, iter); |
| 203 return false; | 203 return false; |
| 204 case kZygoteCommandGetSandboxStatus: | 204 case kZygoteCommandGetSandboxStatus: |
| 205 HandleGetSandboxStatus(fd, iter); | 205 HandleGetSandboxStatus(fd, pickle, iter); |
| 206 return false; | 206 return false; |
| 207 case kZygoteCommandForkRealPID: | 207 case kZygoteCommandForkRealPID: |
| 208 // This shouldn't happen in practice, but some failure paths in | 208 // This shouldn't happen in practice, but some failure paths in |
| 209 // HandleForkRequest (e.g., if ReadArgsAndFork fails during depickling) | 209 // HandleForkRequest (e.g., if ReadArgsAndFork fails during depickling) |
| 210 // could leave this command pending on the socket. | 210 // could leave this command pending on the socket. |
| 211 LOG(ERROR) << "Unexpected real PID message from browser"; | 211 LOG(ERROR) << "Unexpected real PID message from browser"; |
| 212 NOTREACHED(); | 212 NOTREACHED(); |
| 213 return false; | 213 return false; |
| 214 default: | 214 default: |
| 215 NOTREACHED(); | 215 NOTREACHED(); |
| 216 break; | 216 break; |
| 217 } | 217 } |
| 218 } | 218 } |
| 219 | 219 |
| 220 LOG(WARNING) << "Error parsing message from browser"; | 220 LOG(WARNING) << "Error parsing message from browser"; |
| 221 return false; | 221 return false; |
| 222 } | 222 } |
| 223 | 223 |
| 224 // TODO(jln): remove callers to this broken API. See crbug.com/274855. | 224 // TODO(jln): remove callers to this broken API. See crbug.com/274855. |
| 225 void Zygote::HandleReapRequest(int fd, | 225 void Zygote::HandleReapRequest(int fd, |
| 226 const Pickle& pickle, |
| 226 PickleIterator iter) { | 227 PickleIterator iter) { |
| 227 base::ProcessId child; | 228 base::ProcessId child; |
| 228 | 229 |
| 229 if (!iter.ReadInt(&child)) { | 230 if (!pickle.ReadInt(&iter, &child)) { |
| 230 LOG(WARNING) << "Error parsing reap request from browser"; | 231 LOG(WARNING) << "Error parsing reap request from browser"; |
| 231 return; | 232 return; |
| 232 } | 233 } |
| 233 | 234 |
| 234 ZygoteProcessInfo child_info; | 235 ZygoteProcessInfo child_info; |
| 235 if (!GetProcessInfo(child, &child_info)) { | 236 if (!GetProcessInfo(child, &child_info)) { |
| 236 LOG(ERROR) << "Child not found!"; | 237 LOG(ERROR) << "Child not found!"; |
| 237 NOTREACHED(); | 238 NOTREACHED(); |
| 238 return; | 239 return; |
| 239 } | 240 } |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 299 } | 300 } |
| 300 // Successfully got a status for |real_pid|. | 301 // Successfully got a status for |real_pid|. |
| 301 if (*status != base::TERMINATION_STATUS_STILL_RUNNING) { | 302 if (*status != base::TERMINATION_STATUS_STILL_RUNNING) { |
| 302 // Time to forget about this process. | 303 // Time to forget about this process. |
| 303 process_info_map_.erase(real_pid); | 304 process_info_map_.erase(real_pid); |
| 304 } | 305 } |
| 305 return true; | 306 return true; |
| 306 } | 307 } |
| 307 | 308 |
| 308 void Zygote::HandleGetTerminationStatus(int fd, | 309 void Zygote::HandleGetTerminationStatus(int fd, |
| 310 const Pickle& pickle, |
| 309 PickleIterator iter) { | 311 PickleIterator iter) { |
| 310 bool known_dead; | 312 bool known_dead; |
| 311 base::ProcessHandle child_requested; | 313 base::ProcessHandle child_requested; |
| 312 | 314 |
| 313 if (!iter.ReadBool(&known_dead) || !iter.ReadInt(&child_requested)) { | 315 if (!pickle.ReadBool(&iter, &known_dead) || |
| 316 !pickle.ReadInt(&iter, &child_requested)) { |
| 314 LOG(WARNING) << "Error parsing GetTerminationStatus request " | 317 LOG(WARNING) << "Error parsing GetTerminationStatus request " |
| 315 << "from browser"; | 318 << "from browser"; |
| 316 return; | 319 return; |
| 317 } | 320 } |
| 318 | 321 |
| 319 base::TerminationStatus status; | 322 base::TerminationStatus status; |
| 320 int exit_code; | 323 int exit_code; |
| 321 | 324 |
| 322 bool got_termination_status = | 325 bool got_termination_status = |
| 323 GetTerminationStatus(child_requested, known_dead, &status, &exit_code); | 326 GetTerminationStatus(child_requested, known_dead, &status, &exit_code); |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 418 char buf[kZygoteMaxMessageLength]; | 421 char buf[kZygoteMaxMessageLength]; |
| 419 const ssize_t len = UnixDomainSocket::RecvMsg( | 422 const ssize_t len = UnixDomainSocket::RecvMsg( |
| 420 kZygoteSocketPairFd, buf, sizeof(buf), &recv_fds); | 423 kZygoteSocketPairFd, buf, sizeof(buf), &recv_fds); |
| 421 CHECK_GT(len, 0); | 424 CHECK_GT(len, 0); |
| 422 CHECK(recv_fds.empty()); | 425 CHECK(recv_fds.empty()); |
| 423 | 426 |
| 424 Pickle pickle(buf, len); | 427 Pickle pickle(buf, len); |
| 425 PickleIterator iter(pickle); | 428 PickleIterator iter(pickle); |
| 426 | 429 |
| 427 int kind; | 430 int kind; |
| 428 CHECK(iter.ReadInt(&kind)); | 431 CHECK(pickle.ReadInt(&iter, &kind)); |
| 429 CHECK(kind == kZygoteCommandForkRealPID); | 432 CHECK(kind == kZygoteCommandForkRealPID); |
| 430 CHECK(iter.ReadInt(&real_pid)); | 433 CHECK(pickle.ReadInt(&iter, &real_pid)); |
| 431 } | 434 } |
| 432 | 435 |
| 433 // Fork failed. | 436 // Fork failed. |
| 434 if (pid < 0) { | 437 if (pid < 0) { |
| 435 return -1; | 438 return -1; |
| 436 } | 439 } |
| 437 | 440 |
| 438 // If we successfully forked a child, but it crashed without sending | 441 // If we successfully forked a child, but it crashed without sending |
| 439 // a message to the browser, the browser won't have found its PID. | 442 // a message to the browser, the browser won't have found its PID. |
| 440 if (real_pid < 0) { | 443 if (real_pid < 0) { |
| (...skipping 15 matching lines...) Expand all Loading... |
| 456 if (process_info_map_.find(real_pid) != process_info_map_.end()) { | 459 if (process_info_map_.find(real_pid) != process_info_map_.end()) { |
| 457 LOG(ERROR) << "Already tracking PID " << real_pid; | 460 LOG(ERROR) << "Already tracking PID " << real_pid; |
| 458 NOTREACHED(); | 461 NOTREACHED(); |
| 459 } | 462 } |
| 460 process_info_map_[real_pid].internal_pid = pid; | 463 process_info_map_[real_pid].internal_pid = pid; |
| 461 process_info_map_[real_pid].started_from_helper = helper; | 464 process_info_map_[real_pid].started_from_helper = helper; |
| 462 | 465 |
| 463 return real_pid; | 466 return real_pid; |
| 464 } | 467 } |
| 465 | 468 |
| 466 base::ProcessId Zygote::ReadArgsAndFork(PickleIterator iter, | 469 base::ProcessId Zygote::ReadArgsAndFork(const Pickle& pickle, |
| 470 PickleIterator iter, |
| 467 ScopedVector<base::ScopedFD> fds, | 471 ScopedVector<base::ScopedFD> fds, |
| 468 std::string* uma_name, | 472 std::string* uma_name, |
| 469 int* uma_sample, | 473 int* uma_sample, |
| 470 int* uma_boundary_value) { | 474 int* uma_boundary_value) { |
| 471 std::vector<std::string> args; | 475 std::vector<std::string> args; |
| 472 int argc = 0; | 476 int argc = 0; |
| 473 int numfds = 0; | 477 int numfds = 0; |
| 474 base::GlobalDescriptors::Mapping mapping; | 478 base::GlobalDescriptors::Mapping mapping; |
| 475 std::string process_type; | 479 std::string process_type; |
| 476 std::string channel_id; | 480 std::string channel_id; |
| 477 const std::string channel_id_prefix = std::string("--") | 481 const std::string channel_id_prefix = std::string("--") |
| 478 + switches::kProcessChannelID + std::string("="); | 482 + switches::kProcessChannelID + std::string("="); |
| 479 | 483 |
| 480 if (!iter.ReadString(&process_type)) | 484 if (!pickle.ReadString(&iter, &process_type)) |
| 481 return -1; | 485 return -1; |
| 482 if (!iter.ReadInt(&argc)) | 486 if (!pickle.ReadInt(&iter, &argc)) |
| 483 return -1; | 487 return -1; |
| 484 | 488 |
| 485 for (int i = 0; i < argc; ++i) { | 489 for (int i = 0; i < argc; ++i) { |
| 486 std::string arg; | 490 std::string arg; |
| 487 if (!iter.ReadString(&arg)) | 491 if (!pickle.ReadString(&iter, &arg)) |
| 488 return -1; | 492 return -1; |
| 489 args.push_back(arg); | 493 args.push_back(arg); |
| 490 if (arg.compare(0, channel_id_prefix.length(), channel_id_prefix) == 0) | 494 if (arg.compare(0, channel_id_prefix.length(), channel_id_prefix) == 0) |
| 491 channel_id = arg.substr(channel_id_prefix.length()); | 495 channel_id = arg.substr(channel_id_prefix.length()); |
| 492 } | 496 } |
| 493 | 497 |
| 494 if (!iter.ReadInt(&numfds)) | 498 if (!pickle.ReadInt(&iter, &numfds)) |
| 495 return -1; | 499 return -1; |
| 496 if (numfds != static_cast<int>(fds.size())) | 500 if (numfds != static_cast<int>(fds.size())) |
| 497 return -1; | 501 return -1; |
| 498 | 502 |
| 499 // First FD is the PID oracle socket. | 503 // First FD is the PID oracle socket. |
| 500 if (fds.size() < 1) | 504 if (fds.size() < 1) |
| 501 return -1; | 505 return -1; |
| 502 base::ScopedFD pid_oracle(fds[0]->Pass()); | 506 base::ScopedFD pid_oracle(fds[0]->Pass()); |
| 503 | 507 |
| 504 // Remaining FDs are for the global descriptor mapping. | 508 // Remaining FDs are for the global descriptor mapping. |
| 505 for (int i = 1; i < numfds; ++i) { | 509 for (int i = 1; i < numfds; ++i) { |
| 506 base::GlobalDescriptors::Key key; | 510 base::GlobalDescriptors::Key key; |
| 507 if (!iter.ReadUInt32(&key)) | 511 if (!pickle.ReadUInt32(&iter, &key)) |
| 508 return -1; | 512 return -1; |
| 509 mapping.push_back(std::make_pair(key, fds[i]->get())); | 513 mapping.push_back(std::make_pair(key, fds[i]->get())); |
| 510 } | 514 } |
| 511 | 515 |
| 512 mapping.push_back(std::make_pair( | 516 mapping.push_back(std::make_pair( |
| 513 static_cast<uint32_t>(kSandboxIPCChannel), GetSandboxFD())); | 517 static_cast<uint32_t>(kSandboxIPCChannel), GetSandboxFD())); |
| 514 | 518 |
| 515 // Returns twice, once per process. | 519 // Returns twice, once per process. |
| 516 base::ProcessId child_pid = ForkWithRealPid(process_type, | 520 base::ProcessId child_pid = ForkWithRealPid(process_type, |
| 517 mapping, | 521 mapping, |
| (...skipping 24 matching lines...) Expand all Loading... |
| 542 // (we don't have the original argv at this point). | 546 // (we don't have the original argv at this point). |
| 543 SetProcessTitleFromCommandLine(NULL); | 547 SetProcessTitleFromCommandLine(NULL); |
| 544 } else if (child_pid < 0) { | 548 } else if (child_pid < 0) { |
| 545 LOG(ERROR) << "Zygote could not fork: process_type " << process_type | 549 LOG(ERROR) << "Zygote could not fork: process_type " << process_type |
| 546 << " numfds " << numfds << " child_pid " << child_pid; | 550 << " numfds " << numfds << " child_pid " << child_pid; |
| 547 } | 551 } |
| 548 return child_pid; | 552 return child_pid; |
| 549 } | 553 } |
| 550 | 554 |
| 551 bool Zygote::HandleForkRequest(int fd, | 555 bool Zygote::HandleForkRequest(int fd, |
| 556 const Pickle& pickle, |
| 552 PickleIterator iter, | 557 PickleIterator iter, |
| 553 ScopedVector<base::ScopedFD> fds) { | 558 ScopedVector<base::ScopedFD> fds) { |
| 554 std::string uma_name; | 559 std::string uma_name; |
| 555 int uma_sample; | 560 int uma_sample; |
| 556 int uma_boundary_value; | 561 int uma_boundary_value; |
| 557 base::ProcessId child_pid = ReadArgsAndFork( | 562 base::ProcessId child_pid = ReadArgsAndFork( |
| 558 iter, fds.Pass(), &uma_name, &uma_sample, &uma_boundary_value); | 563 pickle, iter, fds.Pass(), &uma_name, &uma_sample, &uma_boundary_value); |
| 559 if (child_pid == 0) | 564 if (child_pid == 0) |
| 560 return true; | 565 return true; |
| 561 // If there's no UMA report for this particular fork, then check if any | 566 // If there's no UMA report for this particular fork, then check if any |
| 562 // helpers have an initial UMA report for us to send instead. | 567 // helpers have an initial UMA report for us to send instead. |
| 563 while (uma_name.empty() && initial_uma_index_ < helpers_.size()) { | 568 while (uma_name.empty() && initial_uma_index_ < helpers_.size()) { |
| 564 helpers_[initial_uma_index_++]->InitialUMA( | 569 helpers_[initial_uma_index_++]->InitialUMA( |
| 565 &uma_name, &uma_sample, &uma_boundary_value); | 570 &uma_name, &uma_sample, &uma_boundary_value); |
| 566 } | 571 } |
| 567 // Must always send reply, as ZygoteHost blocks while waiting for it. | 572 // Must always send reply, as ZygoteHost blocks while waiting for it. |
| 568 Pickle reply_pickle; | 573 Pickle reply_pickle; |
| 569 reply_pickle.WriteInt(child_pid); | 574 reply_pickle.WriteInt(child_pid); |
| 570 reply_pickle.WriteString(uma_name); | 575 reply_pickle.WriteString(uma_name); |
| 571 if (!uma_name.empty()) { | 576 if (!uma_name.empty()) { |
| 572 reply_pickle.WriteInt(uma_sample); | 577 reply_pickle.WriteInt(uma_sample); |
| 573 reply_pickle.WriteInt(uma_boundary_value); | 578 reply_pickle.WriteInt(uma_boundary_value); |
| 574 } | 579 } |
| 575 if (HANDLE_EINTR(write(fd, reply_pickle.data(), reply_pickle.size())) != | 580 if (HANDLE_EINTR(write(fd, reply_pickle.data(), reply_pickle.size())) != |
| 576 static_cast<ssize_t> (reply_pickle.size())) | 581 static_cast<ssize_t> (reply_pickle.size())) |
| 577 PLOG(ERROR) << "write"; | 582 PLOG(ERROR) << "write"; |
| 578 return false; | 583 return false; |
| 579 } | 584 } |
| 580 | 585 |
| 581 bool Zygote::HandleGetSandboxStatus(int fd, | 586 bool Zygote::HandleGetSandboxStatus(int fd, |
| 587 const Pickle& pickle, |
| 582 PickleIterator iter) { | 588 PickleIterator iter) { |
| 583 if (HANDLE_EINTR(write(fd, &sandbox_flags_, sizeof(sandbox_flags_))) != | 589 if (HANDLE_EINTR(write(fd, &sandbox_flags_, sizeof(sandbox_flags_))) != |
| 584 sizeof(sandbox_flags_)) { | 590 sizeof(sandbox_flags_)) { |
| 585 PLOG(ERROR) << "write"; | 591 PLOG(ERROR) << "write"; |
| 586 } | 592 } |
| 587 | 593 |
| 588 return false; | 594 return false; |
| 589 } | 595 } |
| 590 | 596 |
| 591 } // namespace content | 597 } // namespace content |
| OLD | NEW |