1*ec63e07aSXin Li // Copyright 2019 Google LLC 2*ec63e07aSXin Li // 3*ec63e07aSXin Li // Licensed under the Apache License, Version 2.0 (the "License"); 4*ec63e07aSXin Li // you may not use this file except in compliance with the License. 5*ec63e07aSXin Li // You may obtain a copy of the License at 6*ec63e07aSXin Li // 7*ec63e07aSXin Li // https://www.apache.org/licenses/LICENSE-2.0 8*ec63e07aSXin Li // 9*ec63e07aSXin Li // Unless required by applicable law or agreed to in writing, software 10*ec63e07aSXin Li // distributed under the License is distributed on an "AS IS" BASIS, 11*ec63e07aSXin Li // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*ec63e07aSXin Li // See the License for the specific language governing permissions and 13*ec63e07aSXin Li // limitations under the License. 14*ec63e07aSXin Li 15*ec63e07aSXin Li // The sandbox2::Comms class uses AF_UNIX sockets (man 7 unix) to send pieces of 16*ec63e07aSXin Li // data between processes. It uses the TLV encoding and provides some useful 17*ec63e07aSXin Li // helpers. 18*ec63e07aSXin Li // 19*ec63e07aSXin Li // The endianess is platform-specific, but as it can be used over abstract 20*ec63e07aSXin Li // sockets only, that's not a problem. Is some poor soul decides to rewrite it 21*ec63e07aSXin Li // to work over AF_INET(6), the endianess will have to be dealt with (somehow). 22*ec63e07aSXin Li 23*ec63e07aSXin Li #ifndef SANDBOXED_API_SANDBOX2_COMMS_H_ 24*ec63e07aSXin Li #define SANDBOXED_API_SANDBOX2_COMMS_H_ 25*ec63e07aSXin Li 26*ec63e07aSXin Li #include <sys/un.h> 27*ec63e07aSXin Li #include <unistd.h> 28*ec63e07aSXin Li 29*ec63e07aSXin Li #include <cstddef> 30*ec63e07aSXin Li #include <cstdint> 31*ec63e07aSXin Li #include <functional> 32*ec63e07aSXin Li #include <limits> 33*ec63e07aSXin Li #include <memory> 34*ec63e07aSXin Li #include <string> 35*ec63e07aSXin Li #include <utility> 36*ec63e07aSXin Li #include <vector> 37*ec63e07aSXin Li 38*ec63e07aSXin Li #include "absl/base/attributes.h" 39*ec63e07aSXin Li #include "absl/log/die_if_null.h" 40*ec63e07aSXin Li #include "absl/status/status.h" 41*ec63e07aSXin Li #include "absl/status/statusor.h" 42*ec63e07aSXin Li #include "absl/strings/string_view.h" 43*ec63e07aSXin Li #include "google/protobuf/message_lite.h" 44*ec63e07aSXin Li #include "sandboxed_api/util/fileops.h" 45*ec63e07aSXin Li 46*ec63e07aSXin Li namespace proto2 { 47*ec63e07aSXin Li class Message; 48*ec63e07aSXin Li } // namespace proto2 49*ec63e07aSXin Li 50*ec63e07aSXin Li namespace sandbox2 { 51*ec63e07aSXin Li 52*ec63e07aSXin Li class Client; 53*ec63e07aSXin Li class ListeningComms; 54*ec63e07aSXin Li 55*ec63e07aSXin Li class Comms { 56*ec63e07aSXin Li public: 57*ec63e07aSXin Li struct DefaultConnectionTag {}; 58*ec63e07aSXin Li 59*ec63e07aSXin Li // Default tags, custom tags should be <0x80000000. 60*ec63e07aSXin Li static constexpr uint32_t kTagBool = 0x80000001; 61*ec63e07aSXin Li static constexpr uint32_t kTagInt8 = 0x80000002; 62*ec63e07aSXin Li static constexpr uint32_t kTagUint8 = 0x80000003; 63*ec63e07aSXin Li static constexpr uint32_t kTagInt16 = 0x80000004; 64*ec63e07aSXin Li static constexpr uint32_t kTagUint16 = 0x80000005; 65*ec63e07aSXin Li static constexpr uint32_t kTagInt32 = 0x80000006; 66*ec63e07aSXin Li static constexpr uint32_t kTagUint32 = 0x80000007; 67*ec63e07aSXin Li static constexpr uint32_t kTagInt64 = 0x80000008; 68*ec63e07aSXin Li static constexpr uint32_t kTagUint64 = 0x80000009; 69*ec63e07aSXin Li static constexpr uint32_t kTagString = 0x80000100; 70*ec63e07aSXin Li static constexpr uint32_t kTagBytes = 0x80000101; 71*ec63e07aSXin Li static constexpr uint32_t kTagProto2 = 0x80000102; 72*ec63e07aSXin Li static constexpr uint32_t kTagFd = 0X80000201; 73*ec63e07aSXin Li 74*ec63e07aSXin Li // Any payload size above this limit will LOG(WARNING). 75*ec63e07aSXin Li static constexpr size_t kWarnMsgSize = (256ULL << 20); 76*ec63e07aSXin Li 77*ec63e07aSXin Li // A high file descriptor number to be used with certain fork server request 78*ec63e07aSXin Li // modes to map the target executable. This is considered to be an 79*ec63e07aSXin Li // implementation detail. 80*ec63e07aSXin Li // This number is chosen so that low FD numbers are not interfered with. 81*ec63e07aSXin Li static constexpr int kSandbox2TargetExecFD = 1022; 82*ec63e07aSXin Li 83*ec63e07aSXin Li // Sandbox2-specific convention where FD=1023 is always passed to the 84*ec63e07aSXin Li // sandboxed process as a communication channel (encapsulated in the 85*ec63e07aSXin Li // sandbox2::Comms object at the server-side). 86*ec63e07aSXin Li static constexpr int kSandbox2ClientCommsFD = 1023; 87*ec63e07aSXin Li 88*ec63e07aSXin Li // Within SendTLV, a stack-allocated buffer is created to contiguously store 89*ec63e07aSXin Li // the TLV in order to perform one call to Send. 90*ec63e07aSXin Li // If the TLV is larger than the size below, two calls to Send are 91*ec63e07aSXin Li // used. 92*ec63e07aSXin Li static constexpr size_t kSendTLVTempBufferSize = 1024; 93*ec63e07aSXin Li 94*ec63e07aSXin Li static constexpr DefaultConnectionTag kDefaultConnection = {}; 95*ec63e07aSXin Li 96*ec63e07aSXin Li static constexpr const char* kSandbox2CommsFDEnvVar = "SANDBOX2_COMMS_FD"; 97*ec63e07aSXin Li 98*ec63e07aSXin Li static absl::StatusOr<Comms> Connect(const std::string& socket_name, 99*ec63e07aSXin Li bool abstract_uds = true); 100*ec63e07aSXin Li Comms(Comms && other)101*ec63e07aSXin Li Comms(Comms&& other) { *this = std::move(other); } 102*ec63e07aSXin Li Comms& operator=(Comms&& other) { 103*ec63e07aSXin Li if (this != &other) { 104*ec63e07aSXin Li using std::swap; 105*ec63e07aSXin Li swap(*this, other); 106*ec63e07aSXin Li other.Terminate(); 107*ec63e07aSXin Li } 108*ec63e07aSXin Li return *this; 109*ec63e07aSXin Li } 110*ec63e07aSXin Li 111*ec63e07aSXin Li Comms(const Comms&) = delete; 112*ec63e07aSXin Li Comms& operator=(const Comms&) = delete; 113*ec63e07aSXin Li 114*ec63e07aSXin Li // Instantiates a pre-connected object. 115*ec63e07aSXin Li // Takes ownership over fd, which will be closed on object's destruction. 116*ec63e07aSXin Li explicit Comms(int fd, absl::string_view name = ""); 117*ec63e07aSXin Li 118*ec63e07aSXin Li // Instantiates a pre-connected object using the default connection params. 119*ec63e07aSXin Li explicit Comms(DefaultConnectionTag); 120*ec63e07aSXin Li 121*ec63e07aSXin Li ~Comms(); 122*ec63e07aSXin Li 123*ec63e07aSXin Li // Terminates all underlying file descriptors, and sets the status of the 124*ec63e07aSXin Li // Comms object to TERMINATED. 125*ec63e07aSXin Li void Terminate(); 126*ec63e07aSXin Li 127*ec63e07aSXin Li // Returns the already connected FD. 128*ec63e07aSXin Li int GetConnectionFD() const; 129*ec63e07aSXin Li IsConnected()130*ec63e07aSXin Li bool IsConnected() const { return state_ == State::kConnected; } IsTerminated()131*ec63e07aSXin Li bool IsTerminated() const { return state_ == State::kTerminated; } 132*ec63e07aSXin Li 133*ec63e07aSXin Li // Returns the maximum size of a message that can be send over the comms 134*ec63e07aSXin Li // channel. 135*ec63e07aSXin Li // Note: The actual size is "unlimited", although the Buffer API is more 136*ec63e07aSXin Li // efficient for large transfers. There is an arbitrary limit to ~2GiB to 137*ec63e07aSXin Li // avoid protobuf serialization issues. GetMaxMsgSize()138*ec63e07aSXin Li size_t GetMaxMsgSize() const { return std::numeric_limits<int32_t>::max(); } 139*ec63e07aSXin Li 140*ec63e07aSXin Li bool SendTLV(uint32_t tag, size_t length, const void* value); 141*ec63e07aSXin Li // Receive a TLV structure, the memory for the value will be allocated 142*ec63e07aSXin Li // by std::vector. 143*ec63e07aSXin Li bool RecvTLV(uint32_t* tag, std::vector<uint8_t>* value); 144*ec63e07aSXin Li // Receive a TLV structure, the memory for the value will be allocated 145*ec63e07aSXin Li // by std::string. 146*ec63e07aSXin Li bool RecvTLV(uint32_t* tag, std::string* value); 147*ec63e07aSXin Li // Receives a TLV value into a specified buffer without allocating memory. 148*ec63e07aSXin Li bool RecvTLV(uint32_t* tag, size_t* length, void* buffer, size_t buffer_size); 149*ec63e07aSXin Li 150*ec63e07aSXin Li // Sends/receives various types of data. RecvUint8(uint8_t * v)151*ec63e07aSXin Li bool RecvUint8(uint8_t* v) { return RecvIntGeneric(v, kTagUint8); } SendUint8(uint8_t v)152*ec63e07aSXin Li bool SendUint8(uint8_t v) { return SendGeneric(v, kTagUint8); } RecvInt8(int8_t * v)153*ec63e07aSXin Li bool RecvInt8(int8_t* v) { return RecvIntGeneric(v, kTagInt8); } SendInt8(int8_t v)154*ec63e07aSXin Li bool SendInt8(int8_t v) { return SendGeneric(v, kTagInt8); } RecvUint16(uint16_t * v)155*ec63e07aSXin Li bool RecvUint16(uint16_t* v) { return RecvIntGeneric(v, kTagUint16); } SendUint16(uint16_t v)156*ec63e07aSXin Li bool SendUint16(uint16_t v) { return SendGeneric(v, kTagUint16); } RecvInt16(int16_t * v)157*ec63e07aSXin Li bool RecvInt16(int16_t* v) { return RecvIntGeneric(v, kTagInt16); } SendInt16(int16_t v)158*ec63e07aSXin Li bool SendInt16(int16_t v) { return SendGeneric(v, kTagInt16); } RecvUint32(uint32_t * v)159*ec63e07aSXin Li bool RecvUint32(uint32_t* v) { return RecvIntGeneric(v, kTagUint32); } SendUint32(uint32_t v)160*ec63e07aSXin Li bool SendUint32(uint32_t v) { return SendGeneric(v, kTagUint32); } RecvInt32(int32_t * v)161*ec63e07aSXin Li bool RecvInt32(int32_t* v) { return RecvIntGeneric(v, kTagInt32); } SendInt32(int32_t v)162*ec63e07aSXin Li bool SendInt32(int32_t v) { return SendGeneric(v, kTagInt32); } RecvUint64(uint64_t * v)163*ec63e07aSXin Li bool RecvUint64(uint64_t* v) { return RecvIntGeneric(v, kTagUint64); } SendUint64(uint64_t v)164*ec63e07aSXin Li bool SendUint64(uint64_t v) { return SendGeneric(v, kTagUint64); } RecvInt64(int64_t * v)165*ec63e07aSXin Li bool RecvInt64(int64_t* v) { return RecvIntGeneric(v, kTagInt64); } SendInt64(int64_t v)166*ec63e07aSXin Li bool SendInt64(int64_t v) { return SendGeneric(v, kTagInt64); } RecvBool(bool * v)167*ec63e07aSXin Li bool RecvBool(bool* v) { return RecvIntGeneric(v, kTagBool); } SendBool(bool v)168*ec63e07aSXin Li bool SendBool(bool v) { return SendGeneric(v, kTagBool); } 169*ec63e07aSXin Li bool RecvString(std::string* v); 170*ec63e07aSXin Li bool SendString(const std::string& v); 171*ec63e07aSXin Li 172*ec63e07aSXin Li bool RecvBytes(std::vector<uint8_t>* buffer); 173*ec63e07aSXin Li bool SendBytes(const uint8_t* v, size_t len); 174*ec63e07aSXin Li bool SendBytes(const std::vector<uint8_t>& buffer); 175*ec63e07aSXin Li 176*ec63e07aSXin Li // Receives remote process credentials. 177*ec63e07aSXin Li bool RecvCreds(pid_t* pid, uid_t* uid, gid_t* gid); 178*ec63e07aSXin Li 179*ec63e07aSXin Li // Receives/sends file descriptors. 180*ec63e07aSXin Li bool RecvFD(int* fd); 181*ec63e07aSXin Li bool SendFD(int fd); 182*ec63e07aSXin Li 183*ec63e07aSXin Li // Receives/sends protobufs. 184*ec63e07aSXin Li bool RecvProtoBuf(google::protobuf::MessageLite* message); 185*ec63e07aSXin Li bool SendProtoBuf(const google::protobuf::MessageLite& message); 186*ec63e07aSXin Li 187*ec63e07aSXin Li // Receives/sends Status objects. 188*ec63e07aSXin Li bool RecvStatus(absl::Status* status); 189*ec63e07aSXin Li bool SendStatus(const absl::Status& status); 190*ec63e07aSXin Li Swap(Comms & other)191*ec63e07aSXin Li void Swap(Comms& other) { 192*ec63e07aSXin Li if (this == &other) { 193*ec63e07aSXin Li return; 194*ec63e07aSXin Li } 195*ec63e07aSXin Li using std::swap; 196*ec63e07aSXin Li swap(name_, other.name_); 197*ec63e07aSXin Li swap(abstract_uds_, other.abstract_uds_); 198*ec63e07aSXin Li swap(connection_fd_, other.connection_fd_); 199*ec63e07aSXin Li swap(state_, other.state_); 200*ec63e07aSXin Li swap(listening_comms_, other.listening_comms_); 201*ec63e07aSXin Li } 202*ec63e07aSXin Li swap(Comms & x,Comms & y)203*ec63e07aSXin Li friend void swap(Comms& x, Comms& y) { return x.Swap(y); } 204*ec63e07aSXin Li 205*ec63e07aSXin Li private: 206*ec63e07aSXin Li friend class Client; 207*ec63e07aSXin Li 208*ec63e07aSXin Li // State of the channel 209*ec63e07aSXin Li enum class State { 210*ec63e07aSXin Li kUnconnected = 0, 211*ec63e07aSXin Li kConnected, 212*ec63e07aSXin Li kTerminated, 213*ec63e07aSXin Li }; 214*ec63e07aSXin Li 215*ec63e07aSXin Li // Connection parameters. 216*ec63e07aSXin Li std::string name_; 217*ec63e07aSXin Li bool abstract_uds_ = true; 218*ec63e07aSXin Li sapi::file_util::fileops::FDCloser connection_fd_; 219*ec63e07aSXin Li 220*ec63e07aSXin Li std::unique_ptr<ListeningComms> listening_comms_; 221*ec63e07aSXin Li 222*ec63e07aSXin Li // State of the channel (enum), socket will have to be connected later on. 223*ec63e07aSXin Li State state_ = State::kUnconnected; 224*ec63e07aSXin Li 225*ec63e07aSXin Li // Special struct for passing credentials or FDs. 226*ec63e07aSXin Li // When passing credentials or FDs, it inlines the value. This is important as 227*ec63e07aSXin Li // the data is transmitted using sendmsg/recvmsg instead of send/recv. 228*ec63e07aSXin Li // It is also used when sending/receiving through SendTLV/RecvTLV to reduce 229*ec63e07aSXin Li // writes/reads, although the value is written/read separately. 230*ec63e07aSXin Li struct ABSL_ATTRIBUTE_PACKED InternalTLV { 231*ec63e07aSXin Li uint32_t tag; 232*ec63e07aSXin Li size_t len; 233*ec63e07aSXin Li }; 234*ec63e07aSXin Li 235*ec63e07aSXin Li // Moves the comms fd to an other free file descriptor. 236*ec63e07aSXin Li void MoveToAnotherFd(); 237*ec63e07aSXin Li 238*ec63e07aSXin Li // Support for EINTR and size completion. 239*ec63e07aSXin Li bool Send(const void* data, size_t len); 240*ec63e07aSXin Li bool Recv(void* data, size_t len); 241*ec63e07aSXin Li 242*ec63e07aSXin Li // Receives tag and length. 243*ec63e07aSXin Li bool RecvTL(uint32_t* tag, size_t* length); 244*ec63e07aSXin Li 245*ec63e07aSXin Li // T has to be a ContiguousContainer 246*ec63e07aSXin Li template <typename T> 247*ec63e07aSXin Li bool RecvTLVGeneric(uint32_t* tag, T* value); 248*ec63e07aSXin Li 249*ec63e07aSXin Li // Receives arbitrary integers. 250*ec63e07aSXin Li bool RecvInt(void* buffer, size_t len, uint32_t tag); 251*ec63e07aSXin Li 252*ec63e07aSXin Li template <typename T> RecvIntGeneric(T * output,uint32_t tag)253*ec63e07aSXin Li bool RecvIntGeneric(T* output, uint32_t tag) { 254*ec63e07aSXin Li return RecvInt(output, sizeof(T), tag); 255*ec63e07aSXin Li } 256*ec63e07aSXin Li 257*ec63e07aSXin Li template <typename T> SendGeneric(T value,uint32_t tag)258*ec63e07aSXin Li bool SendGeneric(T value, uint32_t tag) { 259*ec63e07aSXin Li return SendTLV(tag, sizeof(T), &value); 260*ec63e07aSXin Li } 261*ec63e07aSXin Li }; 262*ec63e07aSXin Li 263*ec63e07aSXin Li class ListeningComms { 264*ec63e07aSXin Li public: 265*ec63e07aSXin Li static absl::StatusOr<ListeningComms> Create(absl::string_view socket_name, 266*ec63e07aSXin Li bool abstract_uds = true); 267*ec63e07aSXin Li 268*ec63e07aSXin Li ListeningComms(ListeningComms&& other) = default; 269*ec63e07aSXin Li ListeningComms& operator=(ListeningComms&& other) = default; 270*ec63e07aSXin Li ~ListeningComms() = default; 271*ec63e07aSXin Li absl::StatusOr<Comms> Accept(); 272*ec63e07aSXin Li 273*ec63e07aSXin Li private: ListeningComms(absl::string_view socket_name,bool abstract_uds)274*ec63e07aSXin Li ListeningComms(absl::string_view socket_name, bool abstract_uds) 275*ec63e07aSXin Li : socket_name_(socket_name), abstract_uds_(abstract_uds), bind_fd_(-1) {} 276*ec63e07aSXin Li absl::Status Listen(); 277*ec63e07aSXin Li 278*ec63e07aSXin Li std::string socket_name_; 279*ec63e07aSXin Li bool abstract_uds_; 280*ec63e07aSXin Li sapi::file_util::fileops::FDCloser bind_fd_; 281*ec63e07aSXin Li }; 282*ec63e07aSXin Li 283*ec63e07aSXin Li } // namespace sandbox2 284*ec63e07aSXin Li 285*ec63e07aSXin Li #endif // SANDBOXED_API_SANDBOX2_COMMS_H_ 286