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

Unified Diff: content/zygote/zygote_main_linux.cc

Issue 280303002: Add sandbox support for AsanCoverage. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: helper exits on 0 bytes received, zygote waits on it Created 6 years, 7 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 side-by-side diff with in-line comments
Download patch
« content/zygote/zygote_linux.cc ('K') | « content/zygote/zygote_linux.cc ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: content/zygote/zygote_main_linux.cc
diff --git a/content/zygote/zygote_main_linux.cc b/content/zygote/zygote_main_linux.cc
index b4da14eee8e726ba13cea0c3789e9a44d28b03e3..226cf78201db5de478e9291b61b9274399ad0eea 100644
--- a/content/zygote/zygote_main_linux.cc
+++ b/content/zygote/zygote_main_linux.cc
@@ -5,8 +5,10 @@
#include "content/zygote/zygote_main.h"
#include <dlfcn.h>
+#include <fcntl.h>
#include <pthread.h>
#include <string.h>
+#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
@@ -17,6 +19,7 @@
#include "base/memory/scoped_vector.h"
#include "base/native_library.h"
#include "base/pickle.h"
+#include "base/posix/eintr_wrapper.h"
#include "base/posix/unix_domain_socket_linux.h"
#include "base/rand_util.h"
#include "base/sys_info.h"
@@ -47,6 +50,10 @@
#include "third_party/libjingle/overrides/init_webrtc.h"
#endif
+#if defined(ADDRESS_SANITIZER)
+#include <sanitizer/asan_interface.h>
+#endif
+
namespace content {
// See http://code.google.com/p/chromium/wiki/LinuxZygote
@@ -323,10 +330,11 @@ static void ZygotePreSandboxInit() {
new FontConfigIPC(GetSandboxFD()))->unref();
}
-static bool CreateInitProcessReaper() {
+static bool CreateInitProcessReaper(base::Closure* post_fork_parent_callback) {
// The current process becomes init(1), this function returns from a
// newly created process.
- const bool init_created = sandbox::CreateInitProcessReaper(NULL);
+ const bool init_created =
+ sandbox::CreateInitProcessReaper(post_fork_parent_callback);
if (!init_created) {
LOG(ERROR) << "Error creating an init process to reap zombies";
return false;
@@ -336,7 +344,8 @@ static bool CreateInitProcessReaper() {
// Enter the setuid sandbox. This requires the current process to have been
// created through the setuid sandbox.
-static bool EnterSuidSandbox(sandbox::SetuidSandboxClient* setuid_sandbox) {
+static bool EnterSuidSandbox(sandbox::SetuidSandboxClient* setuid_sandbox,
+ base::Closure* post_fork_parent_callback) {
DCHECK(setuid_sandbox);
DCHECK(setuid_sandbox->IsSuidSandboxChild());
@@ -364,7 +373,7 @@ static bool EnterSuidSandbox(sandbox::SetuidSandboxClient* setuid_sandbox) {
if (getpid() == 1) {
// The setuid sandbox has created a new PID namespace and we need
// to assume the role of init.
- CHECK(CreateInitProcessReaper());
+ CHECK(CreateInitProcessReaper(post_fork_parent_callback));
}
#if !defined(OS_OPENBSD)
@@ -398,10 +407,67 @@ static bool EnterSuidSandbox(sandbox::SetuidSandboxClient* setuid_sandbox) {
return true;
}
+#if defined(ADDRESS_SANITIZER)
+const size_t kSanitizerMaxMessageLength = 1 * 1024 * 1024;
+
+// A helper process which collects code coverage data from the renderers over a
+// socket and dumps it to a file. See http://crbug.com/336212 for discussion.
+static void SanitizerCoverageHelper(int socket_fd, int file_fd) {
+ scoped_ptr<char[]> buffer(new char[kSanitizerMaxMessageLength]);
+ while (true) {
+ ssize_t received_size = HANDLE_EINTR(
+ recv(socket_fd, buffer.get(), kSanitizerMaxMessageLength, 0));
+ PCHECK(received_size >= 0);
+ if (received_size == 0)
+ // All clients have closed the socket. We should die.
+ _exit(0);
+ PCHECK(file_fd >= 0);
+ ssize_t written_size = 0;
+ while (written_size < received_size) {
+ ssize_t write_res =
+ HANDLE_EINTR(write(file_fd, buffer.get() + written_size,
+ received_size - written_size));
+ PCHECK(write_res >= 0);
+ written_size += write_res;
+ }
+ PCHECK(0 == HANDLE_EINTR(fsync(file_fd)));
+ }
+}
+
+// fds[0] is the read end, fds[1] is the write end.
+static void CreateSanitizerCoverageSocketPair(int fds[2]) {
+ PCHECK(0 == socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds));
+ PCHECK(0 == shutdown(fds[0], SHUT_WR));
+ PCHECK(0 == shutdown(fds[1], SHUT_RD));
+}
+
+static pid_t ForkSanitizerCoverageHelper(int child_fd, int parent_fd,
+ base::ScopedFD file_fd) {
+ pid_t pid = fork();
+ PCHECK(pid >= 0);
+ if (pid == 0) {
+ // In the child.
+ PCHECK(0 == IGNORE_EINTR(close(parent_fd)));
+ SanitizerCoverageHelper(child_fd, file_fd.get());
+ _exit(0);
+ } else {
+ // In the parent.
+ PCHECK(0 == IGNORE_EINTR(close(child_fd)));
+ return pid;
+ }
+}
+
+void CloseFdPair(const int fds[2]) {
+ PCHECK(0 == IGNORE_EINTR(close(fds[0])));
+ PCHECK(0 == IGNORE_EINTR(close(fds[1])));
+}
+#endif // defined(ADDRESS_SANITIZER)
+
// If |is_suid_sandbox_child|, then make sure that the setuid sandbox is
// engaged.
static void EnterLayerOneSandbox(LinuxSandbox* linux_sandbox,
- bool is_suid_sandbox_child) {
+ bool is_suid_sandbox_child,
+ base::Closure* post_fork_parent_callback) {
DCHECK(linux_sandbox);
ZygotePreSandboxInit();
@@ -415,7 +481,8 @@ static void EnterLayerOneSandbox(LinuxSandbox* linux_sandbox,
linux_sandbox->setuid_sandbox_client();
if (is_suid_sandbox_child) {
- CHECK(EnterSuidSandbox(setuid_sandbox)) << "Failed to enter setuid sandbox";
+ CHECK(EnterSuidSandbox(setuid_sandbox, post_fork_parent_callback))
+ << "Failed to enter setuid sandbox";
}
}
@@ -424,7 +491,26 @@ bool ZygoteMain(const MainFunctionParams& params,
g_am_zygote_or_renderer = true;
sandbox::InitLibcUrandomOverrides();
+ base::Closure *post_fork_parent_callback = NULL;
+
LinuxSandbox* linux_sandbox = LinuxSandbox::GetInstance();
+
+#if defined(ADDRESS_SANITIZER)
+ base::ScopedFD sancov_file_fd(__sanitizer_maybe_open_cov_file("zygote"));
+ int sancov_socket_fds[2] = {-1, -1};
+ CreateSanitizerCoverageSocketPair(sancov_socket_fds);
+ linux_sandbox->sanitizer_args()->coverage_sandboxed = 1;
+ linux_sandbox->sanitizer_args()->coverage_fd = sancov_socket_fds[1];
+ linux_sandbox->sanitizer_args()->coverage_max_block_size =
+ kSanitizerMaxMessageLength;
+ // Zygote termination will block until the helper process exits, which will
+ // not happen until the write end of the socket is closed everywhere. Make
+ // sure the init process does not hold on to it.
+ base::Closure close_sancov_socket_fds =
+ base::Bind(&CloseFdPair, sancov_socket_fds);
+ post_fork_parent_callback = &close_sancov_socket_fds;
+#endif
+
// This will pre-initialize the various sandboxes that need it.
linux_sandbox->PreinitializeSandbox();
@@ -449,13 +535,31 @@ bool ZygoteMain(const MainFunctionParams& params,
}
// Turn on the first layer of the sandbox if the configuration warrants it.
- EnterLayerOneSandbox(linux_sandbox, must_enable_setuid_sandbox);
+ EnterLayerOneSandbox(linux_sandbox, must_enable_setuid_sandbox,
+ post_fork_parent_callback);
+
+ std::vector<pid_t> extra_children;
+ std::vector<int> extra_fds;
+
+#if defined(ADDRESS_SANITIZER)
+ pid_t sancov_helper_pid = ForkSanitizerCoverageHelper(
+ sancov_socket_fds[0], sancov_socket_fds[1], sancov_file_fd.Pass());
+ // It's important that the zygote reaps the helper before dying. Otherwise,
+ // the destruction of the PID namespace could kill the helper before it
+ // completes its I/O tasks.
jln (very slow on Chromium) 2014/05/27 23:15:00 Let's add more information about the lifetime of s
earthdok 2014/05/28 16:44:51 Done.
+ extra_children.push_back(sancov_helper_pid);
+ // Sanitizer code in the renderers will inherit the write end of the socket
+ // from the zygote. We must keep it open until the very end of the zygote's
+ // lifetime, even though we don't explicitly use it.
+ extra_fds.push_back(sancov_socket_fds[1]);
+#endif
int sandbox_flags = linux_sandbox->GetStatus();
bool setuid_sandbox_engaged = sandbox_flags & kSandboxLinuxSUID;
CHECK_EQ(must_enable_setuid_sandbox, setuid_sandbox_engaged);
- Zygote zygote(sandbox_flags, fork_delegates.Pass());
+ Zygote zygote(sandbox_flags, fork_delegates.Pass(), extra_children,
+ extra_fds);
// This function call can return multiple times, once per fork().
return zygote.ProcessRequests();
}
« content/zygote/zygote_linux.cc ('K') | « content/zygote/zygote_linux.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698