xref: /aosp_15_r20/external/sandboxed-api/sandboxed_api/sandbox2/comms.h (revision ec63e07ab9515d95e79c211197c445ef84cefa6a)
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