blob: 6203c999591657b8b54968acd3bb70b3a988f4ef [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SANDBOX_LINUX_SYSCALL_BROKER_BROKER_SIMPLE_MESSAGE_H_
#define SANDBOX_LINUX_SYSCALL_BROKER_BROKER_SIMPLE_MESSAGE_H_
#include <stdint.h>
#include <sys/types.h>
#include "base/containers/span.h"
#include "base/files/scoped_file.h"
#include "sandbox/sandbox_export.h"
namespace sandbox {
namespace syscall_broker {
// This class is meant to provide a very simple messaging mechanism that is
// signal-safe for the broker to utilize. This addresses many of the issues
// outlined in https://crbug.com/255063. In short, the use of the standard
// base::UnixDomainSockets is not possible because it uses base::Pickle and
// std::vector, which are not signal-safe.
//
// In implementation, much of the code for sending and receiving is taken from
// base::UnixDomainSockets and re-used below. Thus, ultimately, it might be
// worthwhile making a first-class base-supported signal-safe set of mechanisms
// that reduces the code duplication.
class SANDBOX_EXPORT BrokerSimpleMessage {
public:
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,
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.
bool AddStringToMessage(const char* string);
// Adds a raw data buffer to the message. If the raw data is actually a
// string, be sure to have length explicitly include the '\0' terminating
// character. Returns true if the internal message buffer has room for the
// 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.
bool AddIntToMessage(int int_to_add);
// This returns a pointer to the next available data buffer in |data|. The
// pointer is owned by |this| class. The resulting buffer is a string and
// terminated with a '\0' character.
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.
bool ReadData(const char** data, size_t* length);
// This reads the next available int from the message and stores it in
// |result|.
bool ReadInt(int* result);
// The maximum length of a message in the fixed size buffer.
static constexpr size_t kMaxMessageLength = 4096;
private:
friend class BrokerSimpleMessageTestHelper;
enum class EntryType : uint32_t { DATA = 0xBDBDBD80, INT = 0xBDBDBD81 };
// 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_ = false;
// Set to true once a message is written to, it may never be read from.
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_ = false;
// The current length of the contents in the |message_| buffer.
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
} // namespace sandbox
#endif // SANDBOX_LINUX_SYSCALL_BROKER_BROKER_SIMPLE_MESSAGE_H_