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

Unified Diff: chrome/browser/zygote_main_linux.cc

Issue 361002: Add support for getting the real process id from within the suid sandbox. The... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 11 years, 1 month 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/browser/zygote_host_linux.cc ('k') | chrome/chrome.gyp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/zygote_main_linux.cc
===================================================================
--- chrome/browser/zygote_main_linux.cc (revision 30939)
+++ chrome/browser/zygote_main_linux.cc (working copy)
@@ -3,18 +3,25 @@
// found in the LICENSE file.
#include <dlfcn.h>
-#include <unistd.h>
#include <sys/epoll.h>
+#include <sys/prctl.h>
+#include <sys/signal.h>
+#include <sys/socket.h>
#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/signal.h>
-#include <sys/prctl.h>
#include <sys/wait.h>
+#include <unistd.h>
+#if defined(CHROMIUM_SELINUX)
+#include <selinux/selinux.h>
+#include <selinux/context.h>
+#endif
+
#include "base/basictypes.h"
#include "base/command_line.h"
#include "base/eintr_wrapper.h"
#include "base/global_descriptors_posix.h"
+#include "base/hash_tables.h"
+#include "base/linux_util.h"
#include "base/path_service.h"
#include "base/pickle.h"
#include "base/rand_util.h"
@@ -33,16 +40,14 @@
#include "skia/ext/SkFontHost_fontconfig_control.h"
-#if defined(CHROMIUM_SELINUX)
-#include <selinux/selinux.h>
-#include <selinux/context.h>
-#endif
-
#include "unicode/timezone.h"
// http://code.google.com/p/chromium/wiki/LinuxZygote
+static const int kBrowserDescriptor = 3;
static const int kMagicSandboxIPCDescriptor = 5;
+static const int kZygoteIdDescriptor = 7;
+static bool g_suid_sandbox_active = false;
// This is the object which implements the zygote. The ZygoteMain function,
// which is called from ChromeMain, at the the bottom and simple constructs one
@@ -52,7 +57,7 @@
bool ProcessRequests() {
// A SOCK_SEQPACKET socket is installed in fd 3. We get commands from the
// browser on it.
- // A SOCK_DGRAM is installed in fd 4. This is the sandbox IPC channel.
+ // A SOCK_DGRAM is installed in fd 5. This is the sandbox IPC channel.
// See http://code.google.com/p/chromium/wiki/LinuxSandboxIPC
// We need to accept SIGCHLD, even though our handler is a no-op because
@@ -62,8 +67,17 @@
action.sa_handler = SIGCHLDHandler;
CHECK(sigaction(SIGCHLD, &action, NULL) == 0);
+ if (g_suid_sandbox_active) {
+ // Let the ZygoteHost know we are ready to go.
+ // The receiving code is in chrome/browser/zygote_host_linux.cc.
+ std::vector<int> empty;
+ bool r = base::SendMsg(kBrowserDescriptor, kZygoteMagic,
+ sizeof(kZygoteMagic), empty);
+ CHECK(r) << "Sending zygote magic failed";
+ }
+
for (;;) {
- if (HandleRequestFromBrowser(3))
+ if (HandleRequestFromBrowser(kBrowserDescriptor))
return true;
}
}
@@ -122,20 +136,30 @@
return false;
}
- bool HandleReapRequest(int fd, Pickle& pickle, void* iter) {
- pid_t child;
+ bool HandleReapRequest(int fd, const Pickle& pickle, void* iter) {
+ base::ProcessId child;
+ base::ProcessId actual_child;
if (!pickle.ReadInt(&iter, &child)) {
LOG(WARNING) << "Error parsing reap request from browser";
return false;
}
- ProcessWatcher::EnsureProcessTerminated(child);
+ if (g_suid_sandbox_active) {
+ actual_child = real_pids_to_sandbox_pids[child];
+ if (!actual_child)
+ return false;
+ real_pids_to_sandbox_pids.erase(child);
+ } else {
+ actual_child = child;
+ }
+ ProcessWatcher::EnsureProcessTerminated(actual_child);
+
return false;
}
- bool HandleDidProcessCrash(int fd, Pickle& pickle, void* iter) {
+ bool HandleDidProcessCrash(int fd, const Pickle& pickle, void* iter) {
base::ProcessHandle child;
if (!pickle.ReadInt(&iter, &child)) {
@@ -144,7 +168,13 @@
}
bool child_exited;
- bool did_crash = base::DidProcessCrash(&child_exited, child);
+ bool did_crash;
+ if (g_suid_sandbox_active)
+ child = real_pids_to_sandbox_pids[child];
+ if (child)
+ did_crash = base::DidProcessCrash(&child_exited, child);
+ else
+ did_crash = child_exited = false;
Pickle write_pickle;
write_pickle.WriteBool(did_crash);
@@ -156,12 +186,14 @@
// Handle a 'fork' request from the browser: this means that the browser
// wishes to start a new renderer.
- bool HandleForkRequest(int fd, Pickle& pickle, void* iter,
+ bool HandleForkRequest(int fd, const Pickle& pickle, void* iter,
std::vector<int>& fds) {
std::vector<std::string> args;
int argc, numfds;
base::GlobalDescriptors::Mapping mapping;
- pid_t child;
+ base::ProcessId child;
+ uint64_t dummy_inode = 0;
+ int dummy_fd = -1;
if (!pickle.ReadInt(&iter, &argc))
goto error;
@@ -186,12 +218,22 @@
}
mapping.push_back(std::make_pair(
- static_cast<uint32_t>(kSandboxIPCChannel), 5));
+ static_cast<uint32_t>(kSandboxIPCChannel), kMagicSandboxIPCDescriptor));
+ if (g_suid_sandbox_active) {
+ dummy_fd = socket(PF_UNIX, SOCK_DGRAM, 0);
+ if (dummy_fd < 0)
+ goto error;
+
+ if (!base::FileDescriptorGetInode(&dummy_inode, dummy_fd))
+ goto error;
+ }
+
child = fork();
if (!child) {
- close(3); // our socket from the browser is in fd 3
+ close(kBrowserDescriptor); // our socket from the browser
+ close(kZygoteIdDescriptor); // another socket from the browser
Singleton<base::GlobalDescriptors>()->Reset(mapping);
// Reset the process-wide command line to our new command line.
@@ -200,22 +242,59 @@
CommandLine::ForCurrentProcess()->InitFromArgv(args);
CommandLine::SetProcTitle();
return true;
+ } else if (child < 0) {
+ LOG(ERROR) << "Zygote could not fork";
+ goto error;
}
- for (std::vector<int>::const_iterator
- i = fds.begin(); i != fds.end(); ++i)
- close(*i);
+ {
+ base::ProcessId proc_id;
+ if (g_suid_sandbox_active) {
+ close(dummy_fd);
+ dummy_fd = -1;
+ uint8_t reply_buf[512];
+ Pickle request;
+ request.WriteInt(LinuxSandbox::METHOD_GET_CHILD_WITH_INODE);
+ request.WriteUInt64(dummy_inode);
- HANDLE_EINTR(write(fd, &child, sizeof(child)));
- return false;
+ const ssize_t r = base::SendRecvMsg(kMagicSandboxIPCDescriptor,
+ reply_buf, sizeof(reply_buf),
+ NULL, request);
+ if (r == -1)
+ goto error;
+ Pickle reply(reinterpret_cast<char*>(reply_buf), r);
+ void* iter2 = NULL;
+ if (!reply.ReadInt(&iter2, &proc_id))
+ goto error;
+ real_pids_to_sandbox_pids[proc_id] = child;
+ } else {
+ proc_id = child;
+ }
+
+ for (std::vector<int>::const_iterator
+ i = fds.begin(); i != fds.end(); ++i)
+ close(*i);
+
+ HANDLE_EINTR(write(fd, &proc_id, sizeof(proc_id)));
+ return false;
+ }
+
error:
- LOG(WARNING) << "Error parsing fork request from browser";
+ LOG(ERROR) << "Error parsing fork request from browser";
for (std::vector<int>::const_iterator
i = fds.begin(); i != fds.end(); ++i)
close(*i);
+ if (dummy_fd >= 0)
+ close(dummy_fd);
return false;
}
+
+ // In the SUID sandbox, we try to use a new PID namespace. Thus the PIDs
+ // fork() returns are not the real PIDs, so we need to map the Real PIDS
+ // into the sandbox PID namespace.
+ typedef base::hash_map<base::ProcessHandle, base::ProcessHandle> ProcessMap;
+ ProcessMap real_pids_to_sandbox_pids;
};
// With SELinux we can carve out a precise sandbox, so we don't have to play
@@ -402,6 +481,8 @@
// over which we can signal that we have completed our startup and can be
// chrooted.
+ g_suid_sandbox_active = true;
+
char* endptr;
const long fd_long = strtol(sandbox_fd_string, &endptr, 10);
if (!*sandbox_fd_string || *endptr || fd_long < 0 || fd_long > INT_MAX)
« no previous file with comments | « chrome/browser/zygote_host_linux.cc ('k') | chrome/chrome.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698