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> |
11 #include <sys/wait.h> | 11 #include <sys/wait.h> |
12 | 12 |
13 #include "base/command_line.h" | 13 #include "base/command_line.h" |
14 #include "base/debug/trace_event.h" | 14 #include "base/debug/trace_event.h" |
15 #include "base/file_util.h" | 15 #include "base/file_util.h" |
16 #include "base/linux_util.h" | 16 #include "base/linux_util.h" |
17 #include "base/logging.h" | 17 #include "base/logging.h" |
18 #include "base/macros.h" | |
18 #include "base/pickle.h" | 19 #include "base/pickle.h" |
19 #include "base/posix/eintr_wrapper.h" | 20 #include "base/posix/eintr_wrapper.h" |
20 #include "base/posix/global_descriptors.h" | 21 #include "base/posix/global_descriptors.h" |
21 #include "base/posix/unix_domain_socket_linux.h" | 22 #include "base/posix/unix_domain_socket_linux.h" |
22 #include "base/process/kill.h" | 23 #include "base/process/kill.h" |
23 #include "content/common/child_process_sandbox_support_impl_linux.h" | 24 #include "content/common/child_process_sandbox_support_impl_linux.h" |
24 #include "content/common/sandbox_linux/sandbox_linux.h" | 25 #include "content/common/sandbox_linux/sandbox_linux.h" |
25 #include "content/common/set_process_title.h" | 26 #include "content/common/set_process_title.h" |
26 #include "content/common/zygote_commands_linux.h" | 27 #include "content/common/zygote_commands_linux.h" |
27 #include "content/public/common/content_descriptors.h" | 28 #include "content/public/common/content_descriptors.h" |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
115 } | 116 } |
116 *process_info = it->second; | 117 *process_info = it->second; |
117 return true; | 118 return true; |
118 } | 119 } |
119 | 120 |
120 bool Zygote::UsingSUIDSandbox() const { | 121 bool Zygote::UsingSUIDSandbox() const { |
121 return sandbox_flags_ & kSandboxLinuxSUID; | 122 return sandbox_flags_ & kSandboxLinuxSUID; |
122 } | 123 } |
123 | 124 |
124 bool Zygote::HandleRequestFromBrowser(int fd) { | 125 bool Zygote::HandleRequestFromBrowser(int fd) { |
125 std::vector<int> fds; | 126 ScopedVector<base::ScopedFD> fds; |
126 char buf[kZygoteMaxMessageLength]; | 127 char buf[kZygoteMaxMessageLength]; |
127 const ssize_t len = UnixDomainSocket::RecvMsg(fd, buf, sizeof(buf), &fds); | 128 const ssize_t len = UnixDomainSocket::RecvMsg(fd, buf, sizeof(buf), &fds); |
128 | 129 |
129 if (len == 0 || (len == -1 && errno == ECONNRESET)) { | 130 if (len == 0 || (len == -1 && errno == ECONNRESET)) { |
130 // EOF from the browser. We should die. | 131 // EOF from the browser. We should die. |
131 _exit(0); | 132 _exit(0); |
132 return false; | 133 return false; |
133 } | 134 } |
134 | 135 |
135 if (len == -1) { | 136 if (len == -1) { |
136 PLOG(ERROR) << "Error reading message from browser"; | 137 PLOG(ERROR) << "Error reading message from browser"; |
137 return false; | 138 return false; |
138 } | 139 } |
139 | 140 |
140 Pickle pickle(buf, len); | 141 Pickle pickle(buf, len); |
141 PickleIterator iter(pickle); | 142 PickleIterator iter(pickle); |
142 | 143 |
143 int kind; | 144 int kind; |
144 if (pickle.ReadInt(&iter, &kind)) { | 145 if (pickle.ReadInt(&iter, &kind)) { |
145 switch (kind) { | 146 switch (kind) { |
146 case kZygoteCommandFork: | 147 case kZygoteCommandFork: |
147 // This function call can return multiple times, once per fork(). | 148 // This function call can return multiple times, once per fork(). |
148 return HandleForkRequest(fd, pickle, iter, fds); | 149 return HandleForkRequest(fd, pickle, iter, fds.Pass()); |
149 | 150 |
150 case kZygoteCommandReap: | 151 case kZygoteCommandReap: |
151 if (!fds.empty()) | 152 if (!fds.empty()) |
152 break; | 153 break; |
153 HandleReapRequest(fd, pickle, iter); | 154 HandleReapRequest(fd, pickle, iter); |
154 return false; | 155 return false; |
155 case kZygoteCommandGetTerminationStatus: | 156 case kZygoteCommandGetTerminationStatus: |
156 if (!fds.empty()) | 157 if (!fds.empty()) |
157 break; | 158 break; |
158 HandleGetTerminationStatus(fd, pickle, iter); | 159 HandleGetTerminationStatus(fd, pickle, iter); |
159 return false; | 160 return false; |
160 case kZygoteCommandGetSandboxStatus: | 161 case kZygoteCommandGetSandboxStatus: |
161 HandleGetSandboxStatus(fd, pickle, iter); | 162 HandleGetSandboxStatus(fd, pickle, iter); |
162 return false; | 163 return false; |
163 default: | 164 default: |
164 NOTREACHED(); | 165 NOTREACHED(); |
165 break; | 166 break; |
166 } | 167 } |
167 } | 168 } |
168 | 169 |
169 LOG(WARNING) << "Error parsing message from browser"; | 170 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; | 171 return false; |
174 } | 172 } |
175 | 173 |
176 // TODO(jln): remove callers to this broken API. See crbug.com/274855. | 174 // TODO(jln): remove callers to this broken API. See crbug.com/274855. |
177 void Zygote::HandleReapRequest(int fd, | 175 void Zygote::HandleReapRequest(int fd, |
178 const Pickle& pickle, | 176 const Pickle& pickle, |
179 PickleIterator iter) { | 177 PickleIterator iter) { |
180 base::ProcessId child; | 178 base::ProcessId child; |
181 | 179 |
182 if (!pickle.ReadInt(&iter, &child)) { | 180 if (!pickle.ReadInt(&iter, &child)) { |
(...skipping 249 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
432 close(dummy_fd); | 430 close(dummy_fd); |
433 if (pipe_fds[0] >= 0) | 431 if (pipe_fds[0] >= 0) |
434 close(pipe_fds[0]); | 432 close(pipe_fds[0]); |
435 if (pipe_fds[1] >= 0) | 433 if (pipe_fds[1] >= 0) |
436 close(pipe_fds[1]); | 434 close(pipe_fds[1]); |
437 return -1; | 435 return -1; |
438 } | 436 } |
439 | 437 |
440 base::ProcessId Zygote::ReadArgsAndFork(const Pickle& pickle, | 438 base::ProcessId Zygote::ReadArgsAndFork(const Pickle& pickle, |
441 PickleIterator iter, | 439 PickleIterator iter, |
442 std::vector<int>& fds, | 440 ScopedVector<base::ScopedFD> fds, |
443 std::string* uma_name, | 441 std::string* uma_name, |
444 int* uma_sample, | 442 int* uma_sample, |
445 int* uma_boundary_value) { | 443 int* uma_boundary_value) { |
446 std::vector<std::string> args; | 444 std::vector<std::string> args; |
447 int argc = 0; | 445 int argc = 0; |
448 int numfds = 0; | 446 int numfds = 0; |
449 base::GlobalDescriptors::Mapping mapping; | 447 base::GlobalDescriptors::Mapping mapping; |
450 std::string process_type; | 448 std::string process_type; |
451 std::string channel_id; | 449 std::string channel_id; |
452 const std::string channel_id_prefix = std::string("--") | 450 const std::string channel_id_prefix = std::string("--") |
(...skipping 15 matching lines...) Expand all Loading... | |
468 | 466 |
469 if (!pickle.ReadInt(&iter, &numfds)) | 467 if (!pickle.ReadInt(&iter, &numfds)) |
470 return -1; | 468 return -1; |
471 if (numfds != static_cast<int>(fds.size())) | 469 if (numfds != static_cast<int>(fds.size())) |
472 return -1; | 470 return -1; |
473 | 471 |
474 for (int i = 0; i < numfds; ++i) { | 472 for (int i = 0; i < numfds; ++i) { |
475 base::GlobalDescriptors::Key key; | 473 base::GlobalDescriptors::Key key; |
476 if (!pickle.ReadUInt32(&iter, &key)) | 474 if (!pickle.ReadUInt32(&iter, &key)) |
477 return -1; | 475 return -1; |
478 mapping.push_back(std::make_pair(key, fds[i])); | 476 mapping.push_back(std::make_pair(key, fds[i]->get())); |
479 } | 477 } |
480 | 478 |
481 mapping.push_back(std::make_pair( | 479 mapping.push_back(std::make_pair( |
482 static_cast<uint32_t>(kSandboxIPCChannel), GetSandboxFD())); | 480 static_cast<uint32_t>(kSandboxIPCChannel), GetSandboxFD())); |
483 | 481 |
484 // Returns twice, once per process. | 482 // Returns twice, once per process. |
485 base::ProcessId child_pid = ForkWithRealPid(process_type, mapping, channel_id, | 483 base::ProcessId child_pid = ForkWithRealPid(process_type, mapping, channel_id, |
486 uma_name, uma_sample, | 484 uma_name, uma_sample, |
487 uma_boundary_value); | 485 uma_boundary_value); |
488 if (!child_pid) { | 486 if (!child_pid) { |
489 // This is the child process. | 487 // This is the child process. |
490 | 488 |
491 close(kZygoteSocketPairFd); // Our socket from the browser. | 489 close(kZygoteSocketPairFd); // Our socket from the browser. |
jln (very slow on Chromium)
2014/04/28 23:48:55
This is not passed in fds I suppose? Do you mind a
mdempsky
2014/04/29 00:10:33
Correct. There's no ScopedFD that owns this socke
| |
490 | |
491 // Pass ownership of file descriptors from fds to GlobalDescriptors. | |
492 for (ScopedVector<base::ScopedFD>::iterator i = fds.begin(); i != fds.end(); | |
jln (very slow on Chromium)
2014/04/28 23:48:55
Wouldn't it be cleaner to iterate on "mapping" ins
mdempsky
2014/04/29 00:10:33
Probably, but as discussed, |mapping| just has the
| |
493 ++i) | |
494 ignore_result((*i)->release()); | |
492 base::GlobalDescriptors::GetInstance()->Reset(mapping); | 495 base::GlobalDescriptors::GetInstance()->Reset(mapping); |
493 | 496 |
494 // Reset the process-wide command line to our new command line. | 497 // Reset the process-wide command line to our new command line. |
495 CommandLine::Reset(); | 498 CommandLine::Reset(); |
496 CommandLine::Init(0, NULL); | 499 CommandLine::Init(0, NULL); |
497 CommandLine::ForCurrentProcess()->InitFromArgv(args); | 500 CommandLine::ForCurrentProcess()->InitFromArgv(args); |
498 | 501 |
499 // Update the process title. The argv was already cached by the call to | 502 // Update the process title. The argv was already cached by the call to |
500 // SetProcessTitleFromCommandLine in ChromeMain, so we can pass NULL here | 503 // SetProcessTitleFromCommandLine in ChromeMain, so we can pass NULL here |
501 // (we don't have the original argv at this point). | 504 // (we don't have the original argv at this point). |
502 SetProcessTitleFromCommandLine(NULL); | 505 SetProcessTitleFromCommandLine(NULL); |
503 } else if (child_pid < 0) { | 506 } else if (child_pid < 0) { |
504 LOG(ERROR) << "Zygote could not fork: process_type " << process_type | 507 LOG(ERROR) << "Zygote could not fork: process_type " << process_type |
505 << " numfds " << numfds << " child_pid " << child_pid; | 508 << " numfds " << numfds << " child_pid " << child_pid; |
506 } | 509 } |
507 return child_pid; | 510 return child_pid; |
508 } | 511 } |
509 | 512 |
510 bool Zygote::HandleForkRequest(int fd, | 513 bool Zygote::HandleForkRequest(int fd, |
511 const Pickle& pickle, | 514 const Pickle& pickle, |
512 PickleIterator iter, | 515 PickleIterator iter, |
513 std::vector<int>& fds) { | 516 ScopedVector<base::ScopedFD> fds) { |
514 std::string uma_name; | 517 std::string uma_name; |
515 int uma_sample; | 518 int uma_sample; |
516 int uma_boundary_value; | 519 int uma_boundary_value; |
517 base::ProcessId child_pid = ReadArgsAndFork(pickle, iter, fds, | 520 base::ProcessId child_pid = ReadArgsAndFork( |
518 &uma_name, &uma_sample, | 521 pickle, iter, fds.Pass(), &uma_name, &uma_sample, &uma_boundary_value); |
519 &uma_boundary_value); | |
520 if (child_pid == 0) | 522 if (child_pid == 0) |
521 return true; | 523 return true; |
522 for (std::vector<int>::const_iterator | |
523 i = fds.begin(); i != fds.end(); ++i) | |
524 close(*i); | |
525 if (uma_name.empty()) { | 524 if (uma_name.empty()) { |
526 // There is no UMA report from this particular fork. | 525 // There is no UMA report from this particular fork. |
527 // Use the initial UMA report if any, and clear that record for next time. | 526 // Use the initial UMA report if any, and clear that record for next time. |
528 // Note the swap method here is the efficient way to do this, since | 527 // Note the swap method here is the efficient way to do this, since |
529 // we know uma_name is empty. | 528 // we know uma_name is empty. |
530 uma_name.swap(initial_uma_name_); | 529 uma_name.swap(initial_uma_name_); |
531 uma_sample = initial_uma_sample_; | 530 uma_sample = initial_uma_sample_; |
532 uma_boundary_value = initial_uma_boundary_value_; | 531 uma_boundary_value = initial_uma_boundary_value_; |
533 } | 532 } |
534 // Must always send reply, as ZygoteHost blocks while waiting for it. | 533 // Must always send reply, as ZygoteHost blocks while waiting for it. |
(...skipping 15 matching lines...) Expand all Loading... | |
550 PickleIterator iter) { | 549 PickleIterator iter) { |
551 if (HANDLE_EINTR(write(fd, &sandbox_flags_, sizeof(sandbox_flags_))) != | 550 if (HANDLE_EINTR(write(fd, &sandbox_flags_, sizeof(sandbox_flags_))) != |
552 sizeof(sandbox_flags_)) { | 551 sizeof(sandbox_flags_)) { |
553 PLOG(ERROR) << "write"; | 552 PLOG(ERROR) << "write"; |
554 } | 553 } |
555 | 554 |
556 return false; | 555 return false; |
557 } | 556 } |
558 | 557 |
559 } // namespace content | 558 } // namespace content |
OLD | NEW |