summaryrefslogtreecommitdiffstats
path: root/chromium/sandbox/linux/services/broker_process.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/sandbox/linux/services/broker_process.cc')
-rw-r--r--chromium/sandbox/linux/services/broker_process.cc59
1 files changed, 42 insertions, 17 deletions
diff --git a/chromium/sandbox/linux/services/broker_process.cc b/chromium/sandbox/linux/services/broker_process.cc
index 438e9726374..ef916f223a8 100644
--- a/chromium/sandbox/linux/services/broker_process.cc
+++ b/chromium/sandbox/linux/services/broker_process.cc
@@ -5,10 +5,12 @@
#include "sandbox/linux/services/broker_process.h"
#include <fcntl.h>
+#include <signal.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/types.h>
+#include <sys/wait.h>
#include <unistd.h>
#include <algorithm>
@@ -16,12 +18,16 @@
#include <vector>
#include "base/basictypes.h"
+#include "base/callback.h"
#include "base/compiler_specific.h"
+#include "base/files/scoped_file.h"
#include "base/logging.h"
+#include "base/memory/scoped_vector.h"
#include "base/pickle.h"
#include "base/posix/eintr_wrapper.h"
#include "base/posix/unix_domain_socket_linux.h"
#include "base/process/process_metrics.h"
+#include "base/third_party/valgrind/valgrind.h"
#include "build/build_config.h"
#include "sandbox/linux/services/linux_syscalls.h"
@@ -31,6 +37,22 @@
namespace {
+bool IsRunningOnValgrind() { return RUNNING_ON_VALGRIND; }
+
+// A little open(2) wrapper to handle some oddities for us. In the general case
+// make a direct system call since we want to keep in control of the broker
+// process' system calls profile to be able to loosely sandbox it.
+int sys_open(const char* pathname, int flags) {
+ // Always pass a defined |mode| in case flags mistakenly contains O_CREAT.
+ const int mode = 0;
+ if (IsRunningOnValgrind()) {
+ // Valgrind does not support AT_FDCWD, just use libc's open() in this case.
+ return open(pathname, flags, mode);
+ } else {
+ return syscall(__NR_openat, AT_FDCWD, pathname, flags, mode);
+ }
+}
+
static const size_t kMaxMessageLength = 4096;
// Some flags are local to the current process and cannot be sent over a Unix
@@ -132,11 +154,19 @@ BrokerProcess::BrokerProcess(int denied_errno,
BrokerProcess::~BrokerProcess() {
if (initialized_ && ipc_socketpair_ != -1) {
- close(ipc_socketpair_);
+ // Closing the socket should be enough to notify the child to die,
+ // unless it has been duplicated.
+ PCHECK(0 == IGNORE_EINTR(close(ipc_socketpair_)));
+ PCHECK(0 == kill(broker_pid_, SIGKILL));
+ siginfo_t process_info;
+ // Reap the child.
+ int ret = HANDLE_EINTR(waitid(P_PID, broker_pid_, &process_info, WEXITED));
+ PCHECK(0 == ret);
}
}
-bool BrokerProcess::Init(bool (*sandbox_callback)(void)) {
+bool BrokerProcess::Init(
+ const base::Callback<bool(void)>& broker_process_init_callback) {
CHECK(!initialized_);
int socket_pair[2];
// Use SOCK_SEQPACKET, because we need to preserve message boundaries
@@ -147,7 +177,9 @@ bool BrokerProcess::Init(bool (*sandbox_callback)(void)) {
return false;
}
+#if !defined(THREAD_SANITIZER)
DCHECK_EQ(1, base::GetNumberOfThreads(base::GetCurrentProcessHandle()));
+#endif
int child_pid = fork();
if (child_pid == -1) {
close(socket_pair[0]);
@@ -173,10 +205,7 @@ bool BrokerProcess::Init(bool (*sandbox_callback)(void)) {
shutdown(socket_pair[0], SHUT_WR);
ipc_socketpair_ = socket_pair[0];
is_child_ = true;
- // Enable the sandbox if provided.
- if (sandbox_callback) {
- CHECK(sandbox_callback());
- }
+ CHECK(broker_process_init_callback.Run());
initialized_ = true;
for (;;) {
HandleRequest();
@@ -292,8 +321,7 @@ int BrokerProcess::PathAndFlagsSyscall(enum IPCCommands syscall_type,
// that we will then close.
// A request should start with an int that will be used as the command type.
bool BrokerProcess::HandleRequest() const {
-
- std::vector<int> fds;
+ ScopedVector<base::ScopedFD> fds;
char buf[kMaxMessageLength];
errno = 0;
const ssize_t msg_len = UnixDomainSocket::RecvMsg(ipc_socketpair_, buf,
@@ -306,12 +334,13 @@ bool BrokerProcess::HandleRequest() const {
// The parent should send exactly one file descriptor, on which we
// will write the reply.
- if (msg_len < 0 || fds.size() != 1 || fds.at(0) < 0) {
+ // TODO(mdempsky): ScopedVector doesn't have 'at()', only 'operator[]'.
+ if (msg_len < 0 || fds.size() != 1 || fds[0]->get() < 0) {
PLOG(ERROR) << "Error reading message from the client";
return false;
}
- const int temporary_ipc = fds.at(0);
+ base::ScopedFD temporary_ipc(fds[0]->Pass());
Pickle pickle(buf, msg_len);
PickleIterator iter(pickle);
@@ -324,15 +353,13 @@ bool BrokerProcess::HandleRequest() const {
case kCommandOpen:
// We reply on the file descriptor sent to us via the IPC channel.
r = HandleRemoteCommand(static_cast<IPCCommands>(command_type),
- temporary_ipc, pickle, iter);
+ temporary_ipc.get(), pickle, iter);
break;
default:
NOTREACHED();
r = false;
break;
}
- int ret = IGNORE_EINTR(close(temporary_ipc));
- DCHECK(!ret) << "Could not close temporary IPC channel";
return r;
}
@@ -375,7 +402,7 @@ bool BrokerProcess::HandleRemoteCommand(IPCCommands command_type, int reply_ipc,
// Close anything we have opened in this process.
for (std::vector<int>::iterator it = opened_files.begin();
- it < opened_files.end(); ++it) {
+ it != opened_files.end(); ++it) {
int ret = IGNORE_EINTR(close(*it));
DCHECK(!ret) << "Could not close file descriptor";
}
@@ -423,9 +450,7 @@ void BrokerProcess::OpenFileForIPC(const std::string& requested_filename,
if (safe_to_open_file) {
CHECK(file_to_open);
- // We're doing a 2-parameter open, so we don't support O_CREAT. It doesn't
- // hurt to always pass a third argument though.
- int opened_fd = syscall(__NR_open, file_to_open, flags, 0);
+ int opened_fd = sys_open(file_to_open, flags);
if (opened_fd < 0) {
write_pickle->WriteInt(-errno);
} else {