Commit 84f5e5b9 authored by Matthew Denton's avatar Matthew Denton Committed by Commit Bot

Linux sandbox: BrokerSimpleMessage support for send/recv multiple fds

For USER_NOTIF support in the syscall broker, the broker will need to
send two fds to the CLONE_FILES process (temporary IPC socket for reply,
and the newly opened FD). The current BrokerSimpleMessage only supports
sending and receiving a single FD, so this CL adds support for
async-signal-safe sending/receiving of multiple FDs.

Bug: 1117351
Change-Id: I708f200b047857816a9c2958535a360811e25741
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2412761Reviewed-by: default avatarTom Sepez <tsepez@chromium.org>
Reviewed-by: default avatarRobert Sesek <rsesek@chromium.org>
Commit-Queue: Matthew Denton <mpdenton@chromium.org>
Cr-Commit-Position: refs/heads/master@{#812478}
parent e855807b
......@@ -93,7 +93,7 @@ int BrokerClient::Readlink(const char* path, char* buf, size_t bufsize) const {
RAW_CHECK(message.AddIntToMessage(COMMAND_READLINK));
RAW_CHECK(message.AddStringToMessage(path));
int returned_fd = -1;
base::ScopedFD returned_fd;
BrokerSimpleMessage reply;
ssize_t msg_len =
message.SendRecvMsgWithFlags(ipc_channel_.get(), 0, &returned_fd, &reply);
......@@ -137,7 +137,7 @@ int BrokerClient::Rename(const char* oldpath, const char* newpath) const {
RAW_CHECK(message.AddStringToMessage(oldpath));
RAW_CHECK(message.AddStringToMessage(newpath));
int returned_fd = -1;
base::ScopedFD returned_fd;
BrokerSimpleMessage reply;
ssize_t msg_len =
message.SendRecvMsgWithFlags(ipc_channel_.get(), 0, &returned_fd, &reply);
......@@ -212,7 +212,7 @@ int BrokerClient::PathOnlySyscall(BrokerCommand syscall_type,
RAW_CHECK(message.AddIntToMessage(syscall_type));
RAW_CHECK(message.AddStringToMessage(pathname));
int returned_fd = -1;
base::ScopedFD returned_fd;
BrokerSimpleMessage reply;
ssize_t msg_len =
message.SendRecvMsgWithFlags(ipc_channel_.get(), 0, &returned_fd, &reply);
......@@ -239,7 +239,7 @@ int BrokerClient::PathAndFlagsSyscall(BrokerCommand syscall_type,
RAW_CHECK(message.AddStringToMessage(pathname));
RAW_CHECK(message.AddIntToMessage(flags));
int returned_fd = -1;
base::ScopedFD returned_fd;
BrokerSimpleMessage reply;
ssize_t msg_len =
message.SendRecvMsgWithFlags(ipc_channel_.get(), 0, &returned_fd, &reply);
......@@ -280,7 +280,7 @@ int BrokerClient::PathAndFlagsSyscallReturningFD(BrokerCommand syscall_type,
RAW_CHECK(message.AddStringToMessage(pathname));
RAW_CHECK(message.AddIntToMessage(flags));
int returned_fd = -1;
base::ScopedFD returned_fd;
BrokerSimpleMessage reply;
ssize_t msg_len = message.SendRecvMsgWithFlags(
ipc_channel_.get(), recvmsg_flags, &returned_fd, &reply);
......@@ -295,8 +295,8 @@ int BrokerClient::PathAndFlagsSyscallReturningFD(BrokerCommand syscall_type,
return return_value;
// We have a real file descriptor to return.
RAW_CHECK(returned_fd >= 0);
return returned_fd;
RAW_CHECK(returned_fd.is_valid());
return returned_fd.release();
}
// Make a remote system call over IPC for syscalls that take a path
......@@ -313,7 +313,7 @@ int BrokerClient::StatFamilySyscall(BrokerCommand syscall_type,
RAW_CHECK(message.AddStringToMessage(pathname));
RAW_CHECK(message.AddIntToMessage(static_cast<int>(follow_links)));
int returned_fd = -1;
base::ScopedFD returned_fd;
BrokerSimpleMessage reply;
ssize_t msg_len =
message.SendRecvMsgWithFlags(ipc_channel_.get(), 0, &returned_fd, &reply);
......
......@@ -10,6 +10,7 @@
#include <unistd.h>
#include "base/check_op.h"
#include "base/containers/span.h"
#include "base/files/scoped_file.h"
#include "base/notreached.h"
#include "base/numerics/safe_math.h"
......@@ -22,19 +23,22 @@ namespace sandbox {
namespace syscall_broker {
BrokerSimpleMessage::BrokerSimpleMessage()
: read_only_(false),
write_only_(false),
broken_(false),
length_(0),
read_next_(message_),
write_next_(message_) {}
ssize_t BrokerSimpleMessage::SendRecvMsgWithFlags(int fd,
int recvmsg_flags,
int* result_fd,
base::ScopedFD* result_fd,
BrokerSimpleMessage* reply) {
return SendRecvMsgWithFlagsMultipleFds(fd, recvmsg_flags, {}, {result_fd, 1},
reply);
}
ssize_t BrokerSimpleMessage::SendRecvMsgWithFlagsMultipleFds(
int fd,
int recvmsg_flags,
base::span<const int> send_fds,
base::span<base::ScopedFD> result_fds,
BrokerSimpleMessage* reply) {
RAW_CHECK(reply);
RAW_CHECK(send_fds.size() + 1 <= base::UnixDomainSocket::kMaxFileDescriptors);
// This socketpair is only used for the IPC and is cleaned up before
// returning.
......@@ -43,48 +47,68 @@ ssize_t BrokerSimpleMessage::SendRecvMsgWithFlags(int fd,
if (!base::CreateSocketPair(&recv_sock, &send_sock))
return -1;
if (!SendMsg(fd, send_sock.get()))
int send_fds_with_reply_socket[base::UnixDomainSocket::kMaxFileDescriptors];
send_fds_with_reply_socket[0] = send_sock.get();
for (size_t i = 0; i < send_fds.size(); i++) {
send_fds_with_reply_socket[i + 1] = send_fds[i];
}
if (!SendMsgMultipleFds(fd,
{send_fds_with_reply_socket, send_fds.size() + 1})) {
return -1;
}
// Close the sending end of the socket right away so that if our peer closes
// it before sending a response (e.g., from exiting), RecvMsgWithFlags() will
// return EOF instead of hanging.
send_sock.reset();
base::ScopedFD recv_fd;
const ssize_t reply_len =
reply->RecvMsgWithFlags(recv_sock.get(), recvmsg_flags, &recv_fd);
const ssize_t reply_len = reply->RecvMsgWithFlagsMultipleFds(
recv_sock.get(), recvmsg_flags, result_fds);
recv_sock.reset();
if (reply_len == -1)
return -1;
if (result_fd)
*result_fd = (recv_fd == -1) ? -1 : recv_fd.release();
return reply_len;
}
bool BrokerSimpleMessage::SendMsg(int fd, int send_fd) {
return SendMsgMultipleFds(
fd, send_fd == -1 ? base::span<int>() : base::span<int>(&send_fd, 1));
}
bool BrokerSimpleMessage::SendMsgMultipleFds(int fd,
base::span<const int> send_fds) {
if (broken_)
return false;
RAW_CHECK(send_fds.size() <= base::UnixDomainSocket::kMaxFileDescriptors);
struct msghdr msg = {};
const void* buf = reinterpret_cast<const void*>(message_);
struct iovec iov = {const_cast<void*>(buf), length_};
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
const unsigned control_len = CMSG_SPACE(sizeof(send_fd));
const unsigned control_len = CMSG_SPACE(send_fds.size() * sizeof(int));
char control_buffer[control_len];
if (send_fd >= 0) {
if (send_fds.size() >= 1) {
struct cmsghdr* cmsg;
msg.msg_control = control_buffer;
msg.msg_controllen = control_len;
cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = CMSG_LEN(sizeof(send_fd));
memcpy(CMSG_DATA(cmsg), &send_fd, sizeof(send_fd));
int len = 0;
for (size_t i = 0; i < send_fds.size(); i++) {
if (send_fds[i] < 0)
return false;
// CMSG_DATA() not guaranteed to be aligned so this must use memcpy.
memcpy(CMSG_DATA(cmsg) + (sizeof(int) * i), &send_fds[i], sizeof(int));
len += sizeof(int);
}
cmsg->cmsg_len = CMSG_LEN(len);
msg.msg_controllen = cmsg->cmsg_len;
}
......@@ -100,8 +124,18 @@ bool BrokerSimpleMessage::SendMsg(int fd, int send_fd) {
ssize_t BrokerSimpleMessage::RecvMsgWithFlags(int fd,
int flags,
base::ScopedFD* return_fd) {
ssize_t ret = RecvMsgWithFlagsMultipleFds(
fd, flags, base::span<base::ScopedFD>(return_fd, 1));
return ret;
}
ssize_t BrokerSimpleMessage::RecvMsgWithFlagsMultipleFds(
int fd,
int flags,
base::span<base::ScopedFD> return_fds) {
// The message must be fresh and unused.
RAW_CHECK(!read_only_ && !write_only_);
RAW_CHECK(return_fds.size() <= base::UnixDomainSocket::kMaxFileDescriptors);
read_only_ = true; // The message should not be written to again.
struct msghdr msg = {};
struct iovec iov = {message_, kMaxMessageLength};
......@@ -126,7 +160,7 @@ ssize_t BrokerSimpleMessage::RecvMsgWithFlags(int fd,
if (r == -1)
return -1;
int* wire_fds = NULL;
int* wire_fds = nullptr;
size_t wire_fds_len = 0;
base::ProcessId pid = -1;
......@@ -136,7 +170,7 @@ ssize_t BrokerSimpleMessage::RecvMsgWithFlags(int fd,
const size_t payload_len = cmsg->cmsg_len - CMSG_LEN(0);
if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
DCHECK_EQ(payload_len % sizeof(fd), 0u);
DCHECK_EQ(wire_fds, static_cast<void*>(nullptr));
DCHECK_EQ(wire_fds, nullptr);
wire_fds = reinterpret_cast<int*>(CMSG_DATA(cmsg));
wire_fds_len = payload_len / sizeof(fd);
}
......@@ -162,9 +196,10 @@ ssize_t BrokerSimpleMessage::RecvMsgWithFlags(int fd,
}
if (wire_fds) {
if (wire_fds_len > 1) {
// Only one FD is accepted by this receive.
for (unsigned i = 0; i < wire_fds_len; ++i) {
if (wire_fds_len > return_fds.size()) {
// The number of fds received is limited to return_fds.size(). If there
// are more in the message than expected, close them and return an error.
for (size_t i = 0; i < wire_fds_len; ++i) {
close(wire_fds[i]);
}
errno = EMSGSIZE;
......@@ -172,7 +207,9 @@ ssize_t BrokerSimpleMessage::RecvMsgWithFlags(int fd,
return -1;
}
*return_fd = base::ScopedFD(wire_fds[0]);
for (size_t i = 0; i < wire_fds_len; ++i) {
return_fds[i] = base::ScopedFD(wire_fds[i]);
}
}
// At this point, |r| is guaranteed to be >= 0.
......
......@@ -8,6 +8,7 @@
#include <stdint.h>
#include <sys/types.h>
#include "base/containers/span.h"
#include "base/files/scoped_file.h"
#include "sandbox/sandbox_export.h"
......@@ -26,25 +27,46 @@ namespace syscall_broker {
// that reduces the code duplication.
class SANDBOX_EXPORT BrokerSimpleMessage {
public:
BrokerSimpleMessage();
BrokerSimpleMessage() = default;
// Signal-safe
// A synchronous version of SendMsg/RecvMsgWithFlags that creates and sends a
// temporary IPC socket over |fd|, then listens for a response on the IPC
// socket using reply->RecvMsgWithFlags(temporary_ipc_socket, recvmsg_flags,
// result_fd);
ssize_t SendRecvMsgWithFlags(int fd,
int recvmsg_flags,
int* send_fd,
base::ScopedFD* result_fd,
BrokerSimpleMessage* reply);
// Same as SendRecvMsgWithFlags(), but allows sending and receiving a variable
// number of fds. The temporary IPC return socket is always sent as the first
// fd in the cmsg.
ssize_t SendRecvMsgWithFlagsMultipleFds(int fd,
int recvmsg_flags,
base::span<const int> send_fds,
base::span<base::ScopedFD> result_fds,
BrokerSimpleMessage* reply);
// Use sendmsg to write the given msg and the file descriptor |send_fd|.
// Returns true if successful. Signal-safe.
bool SendMsg(int fd, int send_fd);
// Same as SendMsg() but allows sending more than one fd.
bool SendMsgMultipleFds(int fd, base::span<const int> send_fds);
// Similar to RecvMsg, but allows to specify |flags| for recvmsg(2).
// Guaranteed to return either 1 or 0 fds. Signal-safe.
ssize_t RecvMsgWithFlags(int fd, int flags, base::ScopedFD* return_fd);
// Same as RecvMsgWithFlags() but allows receiving more than one fd.
ssize_t RecvMsgWithFlagsMultipleFds(int fd,
int flags,
base::span<base::ScopedFD> return_fds);
// Adds a NUL-terminated C-style string to the message as a raw buffer.
// Returns true if the internal message buffer has room for the data, and the
// data is successfully appended.
// Returns true if the internal message buffer has room for the data, and
// the data is successfully appended.
bool AddStringToMessage(const char* string);
// Adds a raw data buffer to the message. If the raw data is actually a
......@@ -53,8 +75,8 @@ class SANDBOX_EXPORT BrokerSimpleMessage {
// data, and the data is successfully appended.
bool AddDataToMessage(const char* buffer, size_t length);
// Adds an int to the message. Returns true if the internal message buffer has
// room for the int and the int is successfully added.
// Adds an int to the message. Returns true if the internal message buffer
// has room for the int and the int is successfully added.
bool AddIntToMessage(int int_to_add);
// This returns a pointer to the next available data buffer in |data|. The
......@@ -63,8 +85,8 @@ class SANDBOX_EXPORT BrokerSimpleMessage {
bool ReadString(const char** string);
// This returns a pointer to the next available data buffer in the message
// in |data|, and the length of the buffer in |length|. The buffer is owned by
// |this| class.
// in |data|, and the length of the buffer in |length|. The buffer is owned
// by |this| class.
bool ReadData(const char** data, size_t* length);
// This reads the next available int from the message and stores it in
......@@ -79,25 +101,25 @@ class SANDBOX_EXPORT BrokerSimpleMessage {
enum class EntryType : uint32_t { DATA = 0xBDBDBD80, INT = 0xBDBDBD81 };
// Returns whether or not the next available entry matches the expected entry
// type.
// Returns whether or not the next available entry matches the expected
// entry type.
bool ValidateType(EntryType expected_type);
// Set to true once a message is read from, it may never be written to.
bool read_only_;
bool read_only_ = false;
// Set to true once a message is written to, it may never be read from.
bool write_only_;
bool write_only_ = false;
// Set when an operation fails, so that all subsequed operations fail,
// including any attempt to send the broken message.
bool broken_;
bool broken_ = false;
// The current length of the contents in the |message_| buffer.
size_t length_;
// The pointer to the next location in the |message_| buffer to read from.
uint8_t* read_next_;
// The pointer to the next location in the |message_| buffer to write from.
uint8_t* write_next_;
size_t length_ = 0;
// The statically allocated buffer of size |kMaxMessageLength|.
uint8_t message_[kMaxMessageLength];
// The pointer to the next location in the |message_| buffer to read from.
uint8_t* read_next_ = message_;
// The pointer to the next location in the |message_| buffer to write from.
uint8_t* write_next_ = message_;
};
} // namespace syscall_broker
......
......@@ -4,14 +4,25 @@
#include "sandbox/linux/syscall_broker/broker_simple_message.h"
#include <linux/kcmp.h>
#include <unistd.h>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/callback_forward.h"
#include "base/files/scoped_file.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/single_thread_task_runner.h"
#include "base/run_loop.h"
#include "base/synchronization/waitable_event.h"
#include "base/task/thread_pool.h"
#include "base/test/bind_test_util.h"
#include "base/test/task_environment.h"
#include "base/test/test_timeouts.h"
#include "base/threading/thread.h"
#include "sandbox/linux/syscall_broker/broker_channel.h"
#include "sandbox/linux/syscall_broker/broker_simple_message.h"
#include "sandbox/linux/system_headers/linux_syscalls.h"
#include "sandbox/linux/tests/test_utils.h"
#include "sandbox/linux/tests/unit_tests.h"
#include "testing/gtest/include/gtest/gtest.h"
......@@ -549,7 +560,7 @@ TEST(BrokerSimpleMessage, SendRecvMsgSynchronous) {
BrokerSimpleMessage send_message;
send_message.AddDataToMessage(data1, strlen(data1) + 1);
BrokerSimpleMessage reply_message;
int returned_fd;
base::ScopedFD returned_fd;
ssize_t len = send_message.SendRecvMsgWithFlags(
ipc_writer.get(), 0, &returned_fd, &reply_message);
......@@ -582,7 +593,7 @@ TEST(BrokerSimpleMessage, SendRecvMsgSynchronous) {
BrokerSimpleMessage send_message;
send_message.AddIntToMessage(int1);
BrokerSimpleMessage reply_message;
int returned_fd;
base::ScopedFD returned_fd;
ssize_t len = send_message.SendRecvMsgWithFlags(
ipc_writer.get(), 0, &returned_fd, &reply_message);
......@@ -617,7 +628,7 @@ TEST(BrokerSimpleMessage, SendRecvMsgSynchronous) {
send_message.AddDataToMessage(data1, strlen(data1) + 1);
send_message.AddIntToMessage(int1);
BrokerSimpleMessage reply_message;
int returned_fd;
base::ScopedFD returned_fd;
ssize_t len = send_message.SendRecvMsgWithFlags(
ipc_writer.get(), 0, &returned_fd, &reply_message);
......@@ -657,7 +668,7 @@ TEST(BrokerSimpleMessage, SendRecvMsgSynchronous) {
send_message.AddIntToMessage(int2);
send_message.AddDataToMessage(data2, strlen(data2) + 1);
BrokerSimpleMessage reply_message;
int returned_fd;
base::ScopedFD returned_fd;
ssize_t len = send_message.SendRecvMsgWithFlags(
ipc_writer.get(), 0, &returned_fd, &reply_message);
......@@ -688,7 +699,7 @@ TEST(BrokerSimpleMessage, SendRecvMsgSynchronous) {
EXPECT_TRUE(send_message.AddIntToMessage(5));
EXPECT_TRUE(send_message.AddStringToMessage("test"));
BrokerSimpleMessage reply_message;
int returned_fd;
base::ScopedFD returned_fd;
ssize_t len = send_message.SendRecvMsgWithFlags(
ipc_writer.get(), 0, &returned_fd, &reply_message);
......@@ -698,6 +709,182 @@ TEST(BrokerSimpleMessage, SendRecvMsgSynchronous) {
}
}
namespace {
// Adds a gtest failure and returns false iff any of the following conditions
// are true:
// 1. |fd1| or |fd2| are invalid fds
// 2. Kcmp fails
// 3. fd1 and fd2 do not compare equal under kcmp.
bool CheckKcmpResult(int fd1, int fd2) {
if (fd1 < 0) {
ADD_FAILURE() << "fd1 invalid";
return false;
}
if (fd2 < 0) {
ADD_FAILURE() << "fd2 invalid";
return false;
}
pid_t pid = getpid();
int ret = syscall(__NR_kcmp, pid, pid, KCMP_FILE, fd1, fd2);
if (ret < 0) {
ADD_FAILURE() << "Kcmp failed, errno = " << errno;
return false;
}
if (ret != 0) {
ADD_FAILURE() << "File description did not compare equal to stdout. Kcmp("
<< fd1 << ", " << fd2 << ") = " << ret;
return false;
}
return true;
}
// Receives an fd over |ipc_reader|, and if it does not point to the same
// description as stdout, prints a message and returns false.
// On any other error, also prints a message and returns false.
void ReceiveStdoutDupFd(BrokerChannel::EndPoint* ipc_reader) {
// Receive an fd from |ipc_reader|.
base::ScopedFD recv_fd;
BrokerSimpleMessage msg;
ssize_t len = msg.RecvMsgWithFlags(ipc_reader->get(), 0, &recv_fd);
ASSERT_GE(len, 0) << "Error on RecvMsgWithFlags, errno = " << errno;
CheckKcmpResult(STDOUT_FILENO, recv_fd.get());
}
void ReceiveTwoDupFds(BrokerChannel::EndPoint* ipc_reader) {
// Receive two fds from |ipc_reader|.
BrokerSimpleMessage msg;
base::ScopedFD recv_fds[2];
ssize_t len =
msg.RecvMsgWithFlagsMultipleFds(ipc_reader->get(), 0, {recv_fds});
ASSERT_GE(len, 0) << "Error on RecvMsgWithFlags, errno = " << errno;
CheckKcmpResult(STDOUT_FILENO, recv_fds[0].get());
CheckKcmpResult(STDIN_FILENO, recv_fds[1].get());
}
void ReceiveThreeFdsSendTwoBack(BrokerChannel::EndPoint* ipc_reader) {
// Receive two fds from |ipc_reader|.
BrokerSimpleMessage msg;
base::ScopedFD recv_fds[3];
ssize_t len =
msg.RecvMsgWithFlagsMultipleFds(ipc_reader->get(), 0, {recv_fds});
ASSERT_GE(len, 0) << "Error on RecvMsgWithFlags, errno = " << errno;
ASSERT_TRUE(recv_fds[0].is_valid());
if (!CheckKcmpResult(STDOUT_FILENO, recv_fds[1].get()) ||
!CheckKcmpResult(STDIN_FILENO, recv_fds[2].get())) {
return;
}
BrokerSimpleMessage resp;
int send_fds[2];
send_fds[0] = recv_fds[1].get();
send_fds[1] = recv_fds[2].get();
resp.AddIntToMessage(0); // Dummy int to send message
ASSERT_TRUE(resp.SendMsgMultipleFds(recv_fds[0].get(), {send_fds}));
}
} // namespace
class BrokerSimpleMessageFdTest : public testing::Test {
public:
void SetUp() override {
#if !defined(SANDBOX_USES_BASE_TEST_SUITE)
// TaskEnvironment requires initialized TestTimeouts, which are already
// enabled if using the base test suite.
TestTimeouts::Initialize();
#endif
task_environment_ = std::make_unique<base::test::TaskEnvironment>();
}
bool SkipIfKcmpNotSupported() {
pid_t pid = getpid();
if (syscall(__NR_kcmp, pid, pid, KCMP_FILE, STDOUT_FILENO, STDOUT_FILENO) <
0) {
LOG(INFO) << "Skipping test, kcmp not supported.";
return false;
}
return true;
}
private:
std::unique_ptr<base::test::TaskEnvironment> task_environment_;
};
// Passes one fd with RecvMsg, SendMsg.
TEST_F(BrokerSimpleMessageFdTest, PassOneFd) {
if (!SkipIfKcmpNotSupported())
return;
BrokerChannel::EndPoint ipc_reader;
BrokerChannel::EndPoint ipc_writer;
BrokerChannel::CreatePair(&ipc_reader, &ipc_writer);
base::RunLoop run_loop;
base::ThreadPool::PostTaskAndReply(
FROM_HERE, base::BindOnce(&ReceiveStdoutDupFd, &ipc_reader),
run_loop.QuitClosure());
BrokerSimpleMessage msg;
msg.AddIntToMessage(0); // Must add a dummy value to send the message.
ASSERT_TRUE(msg.SendMsg(ipc_writer.get(), STDOUT_FILENO));
run_loop.Run();
}
TEST_F(BrokerSimpleMessageFdTest, PassTwoFds) {
if (!SkipIfKcmpNotSupported())
return;
BrokerChannel::EndPoint ipc_reader;
BrokerChannel::EndPoint ipc_writer;
BrokerChannel::CreatePair(&ipc_reader, &ipc_writer);
base::RunLoop run_loop;
base::ThreadPool::PostTaskAndReply(
FROM_HERE, base::BindOnce(&ReceiveTwoDupFds, &ipc_reader),
run_loop.QuitClosure());
BrokerSimpleMessage msg;
msg.AddIntToMessage(0); // Must add a dummy value to send the message.
int send_fds[2];
send_fds[0] = STDOUT_FILENO;
send_fds[1] = STDIN_FILENO;
ASSERT_TRUE(msg.SendMsgMultipleFds(ipc_writer.get(), {send_fds}));
run_loop.Run();
}
TEST_F(BrokerSimpleMessageFdTest, SynchronousPassTwoFds) {
if (!SkipIfKcmpNotSupported())
return;
BrokerChannel::EndPoint ipc_reader;
BrokerChannel::EndPoint ipc_writer;
BrokerChannel::CreatePair(&ipc_reader, &ipc_writer);
base::RunLoop run_loop;
base::ThreadPool::PostTaskAndReply(
FROM_HERE, base::BindOnce(&ReceiveThreeFdsSendTwoBack, &ipc_reader),
run_loop.QuitClosure());
BrokerSimpleMessage msg, reply;
msg.AddIntToMessage(0); // Must add a dummy value to send the message.
int send_fds[2];
send_fds[0] = STDOUT_FILENO;
send_fds[1] = STDIN_FILENO;
base::ScopedFD result_fds[2];
msg.SendRecvMsgWithFlagsMultipleFds(ipc_writer.get(), 0, {send_fds},
{result_fds}, &reply);
run_loop.Run();
ASSERT_TRUE(CheckKcmpResult(STDOUT_FILENO, result_fds[0].get()));
ASSERT_TRUE(CheckKcmpResult(STDIN_FILENO, result_fds[1].get()));
}
} // namespace syscall_broker
} // namespace sandbox
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment