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 <sys/socket.h> | 7 #include <sys/socket.h> |
8 #include <sys/stat.h> | 8 #include <sys/stat.h> |
9 #include <sys/types.h> | 9 #include <sys/types.h> |
10 #include <unistd.h> | 10 #include <unistd.h> |
11 | 11 |
12 #include "base/base_switches.h" | 12 #include "base/base_switches.h" |
13 #include "base/command_line.h" | 13 #include "base/command_line.h" |
14 #include "base/eintr_wrapper.h" | 14 #include "base/eintr_wrapper.h" |
15 #include "base/environment.h" | 15 #include "base/environment.h" |
16 #include "base/file_util.h" | 16 #include "base/file_util.h" |
17 #include "base/linux_util.h" | 17 #include "base/linux_util.h" |
18 #include "base/logging.h" | 18 #include "base/logging.h" |
19 #include "base/memory/linked_ptr.h" | 19 #include "base/memory/linked_ptr.h" |
20 #include "base/memory/scoped_ptr.h" | 20 #include "base/memory/scoped_ptr.h" |
21 #include "base/metrics/histogram.h" | 21 #include "base/metrics/histogram.h" |
22 #include "base/path_service.h" | 22 #include "base/path_service.h" |
23 #include "base/pickle.h" | |
24 #include "base/posix/unix_domain_socket.h" | 23 #include "base/posix/unix_domain_socket.h" |
25 #include "base/process_util.h" | 24 #include "base/process_util.h" |
26 #include "base/string_number_conversions.h" | 25 #include "base/string_number_conversions.h" |
27 #include "base/string_util.h" | 26 #include "base/string_util.h" |
28 #include "base/time.h" | 27 #include "base/time.h" |
29 #include "base/utf_string_conversions.h" | 28 #include "base/utf_string_conversions.h" |
30 #include "content/browser/renderer_host/render_sandbox_host_linux.h" | 29 #include "content/browser/renderer_host/render_sandbox_host_linux.h" |
31 #include "content/common/zygote_commands_linux.h" | 30 #include "content/common/zygote_commands_linux.h" |
32 #include "content/public/browser/content_browser_client.h" | 31 #include "content/public/browser/content_browser_client.h" |
33 #include "content/public/common/content_switches.h" | 32 #include "content/public/common/content_switches.h" |
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
154 | 153 |
155 // Start up the sandbox host process and get the file descriptor for the | 154 // Start up the sandbox host process and get the file descriptor for the |
156 // renderers to talk to it. | 155 // renderers to talk to it. |
157 const int sfd = RenderSandboxHostLinux::GetInstance()->GetRendererSocket(); | 156 const int sfd = RenderSandboxHostLinux::GetInstance()->GetRendererSocket(); |
158 fds_to_map.push_back(std::make_pair(sfd, content::kZygoteRendererSocketFd)); | 157 fds_to_map.push_back(std::make_pair(sfd, content::kZygoteRendererSocketFd)); |
159 | 158 |
160 int dummy_fd = -1; | 159 int dummy_fd = -1; |
161 if (using_suid_sandbox_) { | 160 if (using_suid_sandbox_) { |
162 dummy_fd = socket(PF_UNIX, SOCK_DGRAM, 0); | 161 dummy_fd = socket(PF_UNIX, SOCK_DGRAM, 0); |
163 CHECK(dummy_fd >= 0); | 162 CHECK(dummy_fd >= 0); |
164 fds_to_map.push_back(std::make_pair(dummy_fd, | 163 fds_to_map.push_back(std::make_pair(dummy_fd, content::kZygoteIdFd)); |
165 content::kZygoteIdFd)); | |
166 } | 164 } |
167 | 165 |
168 base::ProcessHandle process = -1; | 166 base::ProcessHandle process = -1; |
169 base::LaunchOptions options; | 167 base::LaunchOptions options; |
170 options.fds_to_remap = &fds_to_map; | 168 options.fds_to_remap = &fds_to_map; |
171 base::LaunchProcess(cmd_line.argv(), options, &process); | 169 base::LaunchProcess(cmd_line.argv(), options, &process); |
172 CHECK(process != -1) << "Failed to launch zygote process"; | 170 CHECK(process != -1) << "Failed to launch zygote process"; |
173 | 171 |
174 if (using_suid_sandbox_) { | 172 if (using_suid_sandbox_) { |
175 // In the SUID sandbox, the real zygote is forked from the sandbox. | 173 // In the SUID sandbox, the real zygote is forked from the sandbox. |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
210 } else { | 208 } else { |
211 // Not using the SUID sandbox. | 209 // Not using the SUID sandbox. |
212 pid_ = process; | 210 pid_ = process; |
213 } | 211 } |
214 | 212 |
215 close(fds[1]); | 213 close(fds[1]); |
216 control_fd_ = fds[0]; | 214 control_fd_ = fds[0]; |
217 | 215 |
218 Pickle pickle; | 216 Pickle pickle; |
219 pickle.WriteInt(content::kZygoteCommandGetSandboxStatus); | 217 pickle.WriteInt(content::kZygoteCommandGetSandboxStatus); |
220 std::vector<int> empty_fds; | 218 if (!SendMessage(pickle, NULL)) |
221 if (!UnixDomainSocket::SendMsg(control_fd_, pickle.data(), pickle.size(), | |
222 empty_fds)) | |
223 LOG(FATAL) << "Cannot communicate with zygote"; | 219 LOG(FATAL) << "Cannot communicate with zygote"; |
224 // We don't wait for the reply. We'll read it in ReadReply. | 220 // We don't wait for the reply. We'll read it in ReadReply. |
225 } | 221 } |
226 | 222 |
| 223 bool ZygoteHostImpl::SendMessage(const Pickle& data, |
| 224 const std::vector<int>* fds) { |
| 225 CHECK(data.size() <= content::kZygoteMaxMessageLength) |
| 226 << "Trying to send too-large message to zygote (sending " << data.size() |
| 227 << " bytes, max is " << content::kZygoteMaxMessageLength << ")"; |
| 228 CHECK(!fds || fds->size() <= UnixDomainSocket::kMaxFileDescriptors) |
| 229 << "Trying to send message with too many file descriptors to zygote " |
| 230 << "(sending " << fds->size() << ", max is " |
| 231 << UnixDomainSocket::kMaxFileDescriptors << ")"; |
| 232 |
| 233 return UnixDomainSocket::SendMsg(control_fd_, |
| 234 data.data(), data.size(), |
| 235 fds ? *fds : std::vector<int>()); |
| 236 } |
| 237 |
227 ssize_t ZygoteHostImpl::ReadReply(void* buf, size_t buf_len) { | 238 ssize_t ZygoteHostImpl::ReadReply(void* buf, size_t buf_len) { |
228 // At startup we send a kZygoteCommandGetSandboxStatus request to the zygote, | 239 // At startup we send a kZygoteCommandGetSandboxStatus request to the zygote, |
229 // but don't wait for the reply. Thus, the first time that we read from the | 240 // but don't wait for the reply. Thus, the first time that we read from the |
230 // zygote, we get the reply to that request. | 241 // zygote, we get the reply to that request. |
231 if (!have_read_sandbox_status_word_) { | 242 if (!have_read_sandbox_status_word_) { |
232 if (HANDLE_EINTR(read(control_fd_, &sandbox_status_, | 243 if (HANDLE_EINTR(read(control_fd_, &sandbox_status_, |
233 sizeof(sandbox_status_))) != | 244 sizeof(sandbox_status_))) != |
234 sizeof(sandbox_status_)) { | 245 sizeof(sandbox_status_)) { |
235 return -1; | 246 return -1; |
236 } | 247 } |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
269 // to the other process. | 280 // to the other process. |
270 linked_ptr<file_util::ScopedFD> ptr( | 281 linked_ptr<file_util::ScopedFD> ptr( |
271 new file_util::ScopedFD(&(fds.back()))); | 282 new file_util::ScopedFD(&(fds.back()))); |
272 autodelete_fds.push_back(ptr); | 283 autodelete_fds.push_back(ptr); |
273 } | 284 } |
274 } | 285 } |
275 | 286 |
276 pid_t pid; | 287 pid_t pid; |
277 { | 288 { |
278 base::AutoLock lock(control_lock_); | 289 base::AutoLock lock(control_lock_); |
279 if (!UnixDomainSocket::SendMsg(control_fd_, pickle.data(), pickle.size(), | 290 if (!SendMessage(pickle, &fds)) |
280 fds)) | |
281 return base::kNullProcessHandle; | 291 return base::kNullProcessHandle; |
282 | 292 |
283 // Read the reply, which pickles the PID and an optional UMA enumeration. | 293 // Read the reply, which pickles the PID and an optional UMA enumeration. |
284 static const unsigned kMaxReplyLength = 2048; | 294 static const unsigned kMaxReplyLength = 2048; |
285 char buf[kMaxReplyLength]; | 295 char buf[kMaxReplyLength]; |
286 const ssize_t len = ReadReply(buf, sizeof(buf)); | 296 const ssize_t len = ReadReply(buf, sizeof(buf)); |
287 | 297 |
288 Pickle reply_pickle(buf, len); | 298 Pickle reply_pickle(buf, len); |
289 PickleIterator iter(reply_pickle); | 299 PickleIterator iter(reply_pickle); |
290 if (len <= 0 || !reply_pickle.ReadInt(&iter, &pid)) | 300 if (len <= 0 || !reply_pickle.ReadInt(&iter, &pid)) |
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
431 #endif // defined(OS_CHROMEOS) | 441 #endif // defined(OS_CHROMEOS) |
432 } | 442 } |
433 | 443 |
434 | 444 |
435 void ZygoteHostImpl::EnsureProcessTerminated(pid_t process) { | 445 void ZygoteHostImpl::EnsureProcessTerminated(pid_t process) { |
436 DCHECK(init_); | 446 DCHECK(init_); |
437 Pickle pickle; | 447 Pickle pickle; |
438 | 448 |
439 pickle.WriteInt(content::kZygoteCommandReap); | 449 pickle.WriteInt(content::kZygoteCommandReap); |
440 pickle.WriteInt(process); | 450 pickle.WriteInt(process); |
441 | 451 if (!SendMessage(pickle, NULL)) |
442 if (HANDLE_EINTR(write(control_fd_, pickle.data(), pickle.size())) < 0) | 452 LOG(ERROR) << "Failed to send Reap message to zygote"; |
443 PLOG(ERROR) << "write"; | |
444 } | 453 } |
445 | 454 |
446 base::TerminationStatus ZygoteHostImpl::GetTerminationStatus( | 455 base::TerminationStatus ZygoteHostImpl::GetTerminationStatus( |
447 base::ProcessHandle handle, | 456 base::ProcessHandle handle, |
448 int* exit_code) { | 457 int* exit_code) { |
449 DCHECK(init_); | 458 DCHECK(init_); |
450 Pickle pickle; | 459 Pickle pickle; |
451 pickle.WriteInt(content::kZygoteCommandGetTerminationStatus); | 460 pickle.WriteInt(content::kZygoteCommandGetTerminationStatus); |
452 pickle.WriteInt(handle); | 461 pickle.WriteInt(handle); |
453 | 462 |
454 // Set this now to handle the early termination cases. | 463 // Set this now to handle the early termination cases. |
455 if (exit_code) | 464 if (exit_code) |
456 *exit_code = content::RESULT_CODE_NORMAL_EXIT; | 465 *exit_code = content::RESULT_CODE_NORMAL_EXIT; |
457 | 466 |
458 static const unsigned kMaxMessageLength = 128; | 467 static const unsigned kMaxMessageLength = 128; |
459 char buf[kMaxMessageLength]; | 468 char buf[kMaxMessageLength]; |
460 ssize_t len; | 469 ssize_t len; |
461 { | 470 { |
462 base::AutoLock lock(control_lock_); | 471 base::AutoLock lock(control_lock_); |
463 if (HANDLE_EINTR(write(control_fd_, pickle.data(), pickle.size())) < 0) | 472 if (!SendMessage(pickle, NULL)) |
464 PLOG(ERROR) << "write"; | 473 LOG(ERROR) << "Failed to send GetTerminationStatus message to zygote"; |
465 | |
466 len = ReadReply(buf, sizeof(buf)); | 474 len = ReadReply(buf, sizeof(buf)); |
467 } | 475 } |
468 | 476 |
469 if (len == -1) { | 477 if (len == -1) { |
470 LOG(WARNING) << "Error reading message from zygote: " << errno; | 478 LOG(WARNING) << "Error reading message from zygote: " << errno; |
471 return base::TERMINATION_STATUS_NORMAL_TERMINATION; | 479 return base::TERMINATION_STATUS_NORMAL_TERMINATION; |
472 } else if (len == 0) { | 480 } else if (len == 0) { |
473 LOG(WARNING) << "Socket closed prematurely."; | 481 LOG(WARNING) << "Socket closed prematurely."; |
474 return base::TERMINATION_STATUS_NORMAL_TERMINATION; | 482 return base::TERMINATION_STATUS_NORMAL_TERMINATION; |
475 } | 483 } |
(...skipping 19 matching lines...) Expand all Loading... |
495 | 503 |
496 pid_t ZygoteHostImpl::GetSandboxHelperPid() const { | 504 pid_t ZygoteHostImpl::GetSandboxHelperPid() const { |
497 return RenderSandboxHostLinux::GetInstance()->pid(); | 505 return RenderSandboxHostLinux::GetInstance()->pid(); |
498 } | 506 } |
499 | 507 |
500 int ZygoteHostImpl::GetSandboxStatus() const { | 508 int ZygoteHostImpl::GetSandboxStatus() const { |
501 if (have_read_sandbox_status_word_) | 509 if (have_read_sandbox_status_word_) |
502 return sandbox_status_; | 510 return sandbox_status_; |
503 return 0; | 511 return 0; |
504 } | 512 } |
OLD | NEW |