Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(331)

Side by Side Diff: content/zygote/zygote_linux.cc

Issue 868233011: Start all children in their own PID namespace. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Only drop capabilities if we have any. Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 18 matching lines...) Expand all
29 #include "content/common/sandbox_linux/sandbox_linux.h" 29 #include "content/common/sandbox_linux/sandbox_linux.h"
30 #include "content/common/set_process_title.h" 30 #include "content/common/set_process_title.h"
31 #include "content/common/zygote_commands_linux.h" 31 #include "content/common/zygote_commands_linux.h"
32 #include "content/public/common/content_descriptors.h" 32 #include "content/public/common/content_descriptors.h"
33 #include "content/public/common/result_codes.h" 33 #include "content/public/common/result_codes.h"
34 #include "content/public/common/sandbox_linux.h" 34 #include "content/public/common/sandbox_linux.h"
35 #include "content/public/common/send_zygote_child_ping_linux.h" 35 #include "content/public/common/send_zygote_child_ping_linux.h"
36 #include "content/public/common/zygote_fork_delegate_linux.h" 36 #include "content/public/common/zygote_fork_delegate_linux.h"
37 #include "ipc/ipc_channel.h" 37 #include "ipc/ipc_channel.h"
38 #include "ipc/ipc_switches.h" 38 #include "ipc/ipc_switches.h"
39 #include "sandbox/linux/services/credentials.h"
39 40
40 // See http://code.google.com/p/chromium/wiki/LinuxZygote 41 // See http://code.google.com/p/chromium/wiki/LinuxZygote
41 42
42 namespace content { 43 namespace content {
43 44
44 namespace { 45 namespace {
45 46
46 // NOP function. See below where this handler is installed. 47 // NOP function. See below where this handler is installed.
47 void SIGCHLDHandler(int signal) { 48 void SIGCHLDHandler(int signal) {
48 } 49 }
49 50
51 // On Linux, when a process is the init process of a PID namespace, it cannot be
52 // terminated by signals like SIGTERM or SIGINT, since they are ignored unless
53 // we register a handler for them. In the handlers, we exit with this special
54 // exit code that GetTerminationStatus understands to mean that we were
55 // terminated by an external signal.
56 const int kKilledExitCode = 0x80;
57
58 void TerminationSignalHandler(int signal) {
59 // Return a special exit code so that the process is detected as terminated by
60 // a signal. We cannot terminate ourself with a signal since we may be the
61 // init process in a PID namespace.
62 _exit(kKilledExitCode);
63 }
64
50 int LookUpFd(const base::GlobalDescriptors::Mapping& fd_mapping, uint32_t key) { 65 int LookUpFd(const base::GlobalDescriptors::Mapping& fd_mapping, uint32_t key) {
51 for (size_t index = 0; index < fd_mapping.size(); ++index) { 66 for (size_t index = 0; index < fd_mapping.size(); ++index) {
52 if (fd_mapping[index].key == key) 67 if (fd_mapping[index].key == key)
53 return fd_mapping[index].fd; 68 return fd_mapping[index].fd;
54 } 69 }
55 return -1; 70 return -1;
56 } 71 }
57 72
58 void CreatePipe(base::ScopedFD* read_pipe, base::ScopedFD* write_pipe) { 73 void CreatePipe(base::ScopedFD* read_pipe, base::ScopedFD* write_pipe) {
59 int raw_pipe[2]; 74 int raw_pipe[2];
(...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after
268 GetTerminationStatus(child, true /* known_dead */, &status, &exit_code); 283 GetTerminationStatus(child, true /* known_dead */, &status, &exit_code);
269 DCHECK(got_termination_status); 284 DCHECK(got_termination_status);
270 } 285 }
271 process_info_map_.erase(child); 286 process_info_map_.erase(child);
272 } 287 }
273 288
274 bool Zygote::GetTerminationStatus(base::ProcessHandle real_pid, 289 bool Zygote::GetTerminationStatus(base::ProcessHandle real_pid,
275 bool known_dead, 290 bool known_dead,
276 base::TerminationStatus* status, 291 base::TerminationStatus* status,
277 int* exit_code) { 292 int* exit_code) {
278
279 ZygoteProcessInfo child_info; 293 ZygoteProcessInfo child_info;
280 if (!GetProcessInfo(real_pid, &child_info)) { 294 if (!GetProcessInfo(real_pid, &child_info)) {
281 LOG(ERROR) << "Zygote::GetTerminationStatus for unknown PID " 295 LOG(FATAL) << "Zygote::GetTerminationStatus for unknown PID "
282 << real_pid; 296 << real_pid;
283 NOTREACHED();
284 return false; 297 return false;
285 } 298 }
286 // We know about |real_pid|. 299 // We know about |real_pid|.
287 const base::ProcessHandle child = child_info.internal_pid; 300 const base::ProcessHandle child = child_info.internal_pid;
288 if (child_info.started_from_helper) { 301 if (child_info.started_from_helper) {
289 if (!child_info.started_from_helper->GetTerminationStatus( 302 if (!child_info.started_from_helper->GetTerminationStatus(
290 child, known_dead, status, exit_code)) { 303 child, known_dead, status, exit_code)) {
291 return false; 304 return false;
292 } 305 }
293 } else { 306 } else {
294 // Handle the request directly. 307 // Handle the request directly.
295 if (known_dead) { 308 if (known_dead) {
296 *status = base::GetKnownDeadTerminationStatus(child, exit_code); 309 *status = base::GetKnownDeadTerminationStatus(child, exit_code);
297 } else { 310 } else {
298 // We don't know if the process is dying, so get its status but don't 311 // We don't know if the process is dying, so get its status but don't
299 // wait. 312 // wait.
300 *status = base::GetTerminationStatus(child, exit_code); 313 *status = base::GetTerminationStatus(child, exit_code);
301 } 314 }
302 } 315 }
303 // Successfully got a status for |real_pid|. 316 // Successfully got a status for |real_pid|.
304 if (*status != base::TERMINATION_STATUS_STILL_RUNNING) { 317 if (*status != base::TERMINATION_STATUS_STILL_RUNNING) {
305 // Time to forget about this process. 318 // Time to forget about this process.
306 process_info_map_.erase(real_pid); 319 process_info_map_.erase(real_pid);
307 } 320 }
321
322 if (WIFEXITED(*exit_code) && WEXITSTATUS(*exit_code) == kKilledExitCode) {
323 *status = base::TERMINATION_STATUS_PROCESS_WAS_KILLED;
324 }
325
308 return true; 326 return true;
309 } 327 }
310 328
311 void Zygote::HandleGetTerminationStatus(int fd, 329 void Zygote::HandleGetTerminationStatus(int fd,
312 PickleIterator iter) { 330 PickleIterator iter) {
313 bool known_dead; 331 bool known_dead;
314 base::ProcessHandle child_requested; 332 base::ProcessHandle child_requested;
315 333
316 if (!iter.ReadBool(&known_dead) || !iter.ReadInt(&child_requested)) { 334 if (!iter.ReadBool(&known_dead) || !iter.ReadInt(&child_requested)) {
317 LOG(WARNING) << "Error parsing GetTerminationStatus request " 335 LOG(WARNING) << "Error parsing GetTerminationStatus request "
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
368 } 386 }
369 std::vector<int> fds; 387 std::vector<int> fds;
370 fds.push_back(ipc_channel_fd); // kBrowserFDIndex 388 fds.push_back(ipc_channel_fd); // kBrowserFDIndex
371 fds.push_back(pid_oracle.get()); // kPIDOracleFDIndex 389 fds.push_back(pid_oracle.get()); // kPIDOracleFDIndex
372 pid = helper->Fork(process_type, fds, channel_id); 390 pid = helper->Fork(process_type, fds, channel_id);
373 391
374 // Helpers should never return in the child process. 392 // Helpers should never return in the child process.
375 CHECK_NE(pid, 0); 393 CHECK_NE(pid, 0);
376 } else { 394 } else {
377 CreatePipe(&read_pipe, &write_pipe); 395 CreatePipe(&read_pipe, &write_pipe);
378 // This is roughly equivalent to a fork(). We are using ForkWithFlags mainly 396 int clone_flags = SIGCHLD;
379 // to give it some more diverse test coverage. 397 if (sandbox_flags_ & kSandboxLinuxPIDNS &&
380 pid = base::ForkWithFlags(SIGCHLD, nullptr, nullptr); 398 sandbox_flags_ & kSandboxLinuxUserNS) {
399 clone_flags |= CLONE_NEWPID;
jln (very slow on Chromium) 2015/02/25 21:32:48 I know there was some back and forth on this, but
rickyz (no longer on Chrome) 2015/03/21 01:35:31 I'm happy to not go out of my way to support peopl
400 }
401 pid = base::ForkWithFlags(clone_flags, nullptr, nullptr);
381 } 402 }
382 403
383 if (pid == 0) { 404 if (pid == 0) {
405 if (sandbox::Credentials::HasAnyCapability()) {
406 CHECK(sandbox::Credentials::DropAllCapabilities(
jln (very slow on Chromium) 2015/02/25 21:32:48 Why not always drop capabilities? Is it because p
rickyz (no longer on Chrome) 2015/03/21 01:35:31 Yeah, that's exactly the reason. I haven't address
407 LinuxSandbox::GetInstance()->proc_fd()));
408 }
409
410 // If the process is the init process inside a PID namespace, it must have
jln (very slow on Chromium) 2015/02/25 21:32:48 (I'm trying to figure out how we can re-factor the
rickyz (no longer on Chrome) 2015/03/21 01:35:31 Ugh, this signal handling stuff is so horrible. He
411 // explicit SIGTERM and SIGINT handlers.
412 if (getpid() == 1) {
413 struct sigaction action;
414 memset(&action, 0, sizeof(action));
415 action.sa_handler = &TerminationSignalHandler;
416 PCHECK(sigaction(SIGINT, &action, nullptr) == 0);
417 PCHECK(sigaction(SIGTERM, &action, nullptr) == 0);
418 }
419
384 // In the child process. 420 // In the child process.
385 write_pipe.reset(); 421 write_pipe.reset();
386 422
387 // Ping the PID oracle socket so the browser can find our PID. 423 // Ping the PID oracle socket so the browser can find our PID.
388 CHECK(SendZygoteChildPing(pid_oracle.get())); 424 CHECK(SendZygoteChildPing(pid_oracle.get()));
389 425
390 // Now read back our real PID from the zygote. 426 // Now read back our real PID from the zygote.
391 base::ProcessId real_pid; 427 base::ProcessId real_pid;
392 if (!base::ReadFromFD(read_pipe.get(), 428 if (!base::ReadFromFD(read_pipe.get(),
393 reinterpret_cast<char*>(&real_pid), 429 reinterpret_cast<char*>(&real_pid),
(...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after
585 PickleIterator iter) { 621 PickleIterator iter) {
586 if (HANDLE_EINTR(write(fd, &sandbox_flags_, sizeof(sandbox_flags_))) != 622 if (HANDLE_EINTR(write(fd, &sandbox_flags_, sizeof(sandbox_flags_))) !=
587 sizeof(sandbox_flags_)) { 623 sizeof(sandbox_flags_)) {
588 PLOG(ERROR) << "write"; 624 PLOG(ERROR) << "write";
589 } 625 }
590 626
591 return false; 627 return false;
592 } 628 }
593 629
594 } // namespace content 630 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698