• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 // TODO: We can't use std::shared_ptr on the older guests due to HALs.
18 
19 #ifndef CUTTLEFISH_COMMON_COMMON_LIBS_FS_SHARED_FD_H_
20 #define CUTTLEFISH_COMMON_COMMON_LIBS_FS_SHARED_FD_H_
21 
22 #ifdef __linux__
23 #include <sys/epoll.h>
24 #include <sys/eventfd.h>
25 #endif
26 #include <sys/inotify.h>
27 #include <sys/ioctl.h>
28 #include <sys/mman.h>
29 #include <sys/select.h>
30 #include <sys/socket.h>
31 #include <sys/stat.h>
32 #include <sys/time.h>
33 #include <sys/types.h>
34 #include <sys/uio.h>
35 #include <sys/un.h>
36 
37 #include <chrono>
38 #include <memory>
39 #include <sstream>
40 #include <string>
41 #include <utility>
42 #include <vector>
43 
44 #include <errno.h>
45 #include <fcntl.h>
46 #include <string.h>
47 #include <termios.h>
48 #include <unistd.h>
49 
50 #include <android-base/cmsg.h>
51 
52 #ifdef __linux__
53 #include <linux/vm_sockets.h>
54 #endif
55 
56 #include "common/libs/utils/result.h"
57 
58 /**
59  * Classes to to enable safe access to files.
60  * POSIX kernels have an unfortunate habit of recycling file descriptors.
61  * That can cause problems like http://b/26121457 in code that doesn't manage
62  * file lifetimes properly. These classes implement an alternate interface
63  * that has some advantages:
64  *
65  * o References to files are tightly controlled
66  * o Files are auto-closed if they go out of scope
67  * o Files are life-time aware. It is impossible to close the instance twice.
68  * o File descriptors are always initialized. By default the descriptor is
69  *   set to a closed instance.
70  *
71  * These classes are designed to mimic to POSIX interface as closely as
72  * possible. Specifically, they don't attempt to track the type of file
73  * descriptors and expose only the valid operations. This is by design, since
74  * it makes it easier to convert existing code to SharedFDs and avoids the
75  * possibility that new POSIX functionality will lead to large refactorings.
76  */
77 namespace cuttlefish {
78 
79 struct PollSharedFd;
80 class Epoll;
81 class FileInstance;
82 struct VhostUserVsockCid;
83 struct VsockCid;
84 
85 /**
86  * Counted reference to a FileInstance.
87  *
88  * This is also the place where most new FileInstances are created. The creation
89  * methods correspond to the underlying POSIX calls.
90  *
91  * SharedFDs can be compared and stored in STL containers. The semantics are
92  * slightly different from POSIX file descriptors:
93  *
94  * o The value of the SharedFD is the identity of its underlying FileInstance.
95  *
96  * o Each newly created SharedFD has a unique, closed FileInstance:
97  *    SharedFD a, b;
98  *    assert (a != b);
99  *    a = b;
100  *    assert(a == b);
101  *
102  * o The identity of the FileInstance is not affected by closing the file:
103  *   SharedFD a, b;
104  *   set<SharedFD> s;
105  *   s.insert(a);
106  *   assert(s.count(a) == 1);
107  *   assert(s.count(b) == 0);
108  *   a->Close();
109  *   assert(s.count(a) == 1);
110  *   assert(s.count(b) == 0);
111  *
112  * o FileInstances are never visibly recycled.
113  *
114  * o If all of the SharedFDs referring to a FileInstance go out of scope the
115  *   file is closed and the FileInstance is recycled.
116  *
117  * Creation methods must ensure that no references to the new file descriptor
118  * escape. The underlying FileInstance should have the only reference to the
119  * file descriptor. Any method that needs to know the fd must be in either
120  * SharedFD or FileInstance.
121  *
122  * SharedFDs always have an underlying FileInstance, so all of the method
123  * calls are safe in accordance with the null object pattern.
124  *
125  * Errors on system calls that create new FileInstances, such as Open, are
126  * reported with a new, closed FileInstance with the errno set.
127  */
128 class SharedFD {
129   // Give WeakFD access to the underlying shared_ptr.
130   friend class WeakFD;
131  public:
132   inline SharedFD();
SharedFD(const std::shared_ptr<FileInstance> & in)133   SharedFD(const std::shared_ptr<FileInstance>& in) : value_(in) {}
134   SharedFD(SharedFD const&) = default;
135   SharedFD(SharedFD&& other);
136   SharedFD& operator=(SharedFD const&) = default;
137   SharedFD& operator=(SharedFD&& other);
138   // Reference the listener as a FileInstance to make this FD type agnostic.
139   static SharedFD Accept(const FileInstance& listener, struct sockaddr* addr,
140                          socklen_t* addrlen);
141   static SharedFD Accept(const FileInstance& listener);
142   static SharedFD Dup(int unmanaged_fd);
143   // All SharedFDs have the O_CLOEXEC flag after creation. To remove use the
144   // Fcntl or Dup functions.
145   static SharedFD Open(const char* pathname, int flags, mode_t mode = 0);
146   static SharedFD Open(const std::string& pathname, int flags, mode_t mode = 0);
147   static SharedFD InotifyFd();
148   static SharedFD Creat(const std::string& pathname, mode_t mode);
149   static int Fchdir(SharedFD);
150   static Result<SharedFD> Fifo(const std::string& pathname, mode_t mode);
151   static bool Pipe(SharedFD* fd0, SharedFD* fd1);
152 #ifdef __linux__
153   static SharedFD Event(int initval = 0, int flags = 0);
154 #ifdef CUTTLEFISH_HOST
155   static SharedFD ShmOpen(const std::string& name, int oflag, int mode);
156 #endif
157 #endif
158   static SharedFD MemfdCreate(const std::string& name, unsigned int flags = 0);
159   static SharedFD MemfdCreateWithData(const std::string& name, const std::string& data, unsigned int flags = 0);
160   static SharedFD Mkstemp(std::string* path);
161   static int Poll(PollSharedFd* fds, size_t num_fds, int timeout);
162   static int Poll(std::vector<PollSharedFd>& fds, int timeout);
163   static bool SocketPair(int domain, int type, int protocol, SharedFD* fd0,
164                          SharedFD* fd1);
165   static Result<std::pair<SharedFD, SharedFD>> SocketPair(int domain, int type,
166                                                           int protocol);
167   static SharedFD Socket(int domain, int socket_type, int protocol);
168   static SharedFD SocketLocalClient(const std::string& name, bool is_abstract,
169                                     int in_type);
170   static SharedFD SocketLocalClient(const std::string& name, bool is_abstract,
171                                     int in_type, int timeout_seconds);
172   static SharedFD SocketLocalClient(int port, int type);
173   static SharedFD SocketClient(const std::string& host, int port,
174                                int type, std::chrono::seconds timeout = std::chrono::seconds(0));
175   static SharedFD Socket6Client(const std::string& host, const std::string& interface, int port,
176                                 int type, std::chrono::seconds timeout = std::chrono::seconds(0));
177   static SharedFD SocketLocalServer(const std::string& name, bool is_abstract,
178                                     int in_type, mode_t mode);
179   static SharedFD SocketLocalServer(int port, int type);
180 
181 #ifdef __linux__
182   // For binding in vsock, svm_cid from `cid` param would be either
183   // VMADDR_CID_ANY, VMADDR_CID_LOCAL, VMADDR_CID_HOST or their own CID, and it
184   // is used for indicating connections which it accepts from.
185   //  * VMADDR_CID_ANY: accept from any
186   //  * VMADDR_CID_LOCAL: accept from local
187   //  * VMADDR_CID_HOST: accept from child vm
188   //  * their own CID: accept from parent vm
189   // With vhost-user-vsock, it is basically similar to VMADDR_CID_HOST, but for
190   // now it has limitations that it should bind to a specific socket file which
191   // is for a certain cid. So for vhost-user-vsock, we need to specify the
192   // expected client's cid. That's why vhost_user_vsock_listening_cid is
193   // necessary.
194   // TODO: combining them when vhost-user-vsock impl supports a kind of
195   // VMADDR_CID_HOST
196   static SharedFD VsockServer(unsigned int port, int type,
197                               std::optional<int> vhost_user_vsock_listening_cid,
198                               unsigned int cid = VMADDR_CID_ANY);
199   static SharedFD VsockServer(
200       int type, std::optional<int> vhost_user_vsock_listening_cid);
201   static SharedFD VsockClient(unsigned int cid, unsigned int port, int type,
202                               bool vhost_user);
203   static std::string GetVhostUserVsockServerAddr(
204       unsigned int port, int vhost_user_vsock_listening_cid);
205   static std::string GetVhostUserVsockClientAddr(int cid);
206 #endif
207 
208   bool operator==(const SharedFD& rhs) const { return value_ == rhs.value_; }
209 
210   bool operator!=(const SharedFD& rhs) const { return value_ != rhs.value_; }
211 
212   bool operator<(const SharedFD& rhs) const { return value_ < rhs.value_; }
213 
214   bool operator<=(const SharedFD& rhs) const { return value_ <= rhs.value_; }
215 
216   bool operator>(const SharedFD& rhs) const { return value_ > rhs.value_; }
217 
218   bool operator>=(const SharedFD& rhs) const { return value_ >= rhs.value_; }
219 
220   std::shared_ptr<FileInstance> operator->() const { return value_; }
221 
222   const FileInstance& operator*() const { return *value_; }
223 
224   FileInstance& operator*() { return *value_; }
225 
226  private:
227   static SharedFD ErrorFD(int error);
228 
229   std::shared_ptr<FileInstance> value_;
230 };
231 
232 /**
233  * A non-owning reference to a FileInstance. The referenced FileInstance needs
234  * to be managed by a SharedFD. A WeakFD needs to be converted to a SharedFD to
235  * access the underlying FileInstance.
236  */
237 class WeakFD {
238  public:
WeakFD(SharedFD shared_fd)239   WeakFD(SharedFD shared_fd) : value_(shared_fd.value_) {}
240 
241   // Creates a new SharedFD object that shares ownership of the underlying fd.
242   // Callers need to check that the returned SharedFD is open before using it.
243   SharedFD lock() const;
244 
245  private:
246   std::weak_ptr<FileInstance> value_;
247 };
248 
249 // Provides RAII semantics for memory mappings, preventing memory leaks. It does
250 // not however prevent use-after-free errors since the underlying pointer can be
251 // extracted and could survive this object.
252 class ScopedMMap {
253  public:
254   ScopedMMap();
255   ScopedMMap(void* ptr, size_t size);
256   ScopedMMap(const ScopedMMap& other) = delete;
257   ScopedMMap& operator=(const ScopedMMap& other) = delete;
258   ScopedMMap(ScopedMMap&& other);
259 
260   ~ScopedMMap();
261 
get()262   void* get() { return ptr_; }
get()263   const void* get() const { return ptr_; }
len()264   size_t len() const { return len_; }
265 
266   operator bool() const { return ptr_ != MAP_FAILED; }
267 
268   // Checks whether the interval [offset, offset + length) is contained within
269   // [0, len_)
WithinBounds(size_t offset,size_t length)270   bool WithinBounds(size_t offset, size_t length) const {
271     // Don't add offset + len to avoid overflow
272     return offset < len_ && len_ - offset >= length;
273   }
274 
275  private:
276   void* ptr_ = MAP_FAILED;
277   size_t len_;
278 };
279 
280 /**
281  * Tracks the lifetime of a file descriptor and provides methods to allow
282  * callers to use the file without knowledge of the underlying descriptor
283  * number.
284  *
285  * FileInstances have two states: Open and Closed. They may start in either
286  * state. However, once a FileIntance enters the Closed state it cannot be
287  * reopened.
288  *
289  * Construction of FileInstances is limited to select classes to avoid
290  * escaping file descriptors. At this point SharedFD is the only class
291  * that has access. We may eventually have ScopedFD and WeakFD.
292  */
293 class FileInstance {
294   // Give SharedFD access to the aliasing constructor.
295   friend class SharedFD;
296   friend class Epoll;
297 
298  public:
~FileInstance()299   virtual ~FileInstance() { Close(); }
300 
301   // This can't be a singleton because our shared_ptr's aren't thread safe.
302   static std::shared_ptr<FileInstance> ClosedInstance();
303 
304   int Bind(const struct sockaddr* addr, socklen_t addrlen);
305   int Connect(const struct sockaddr* addr, socklen_t addrlen);
306   int ConnectWithTimeout(const struct sockaddr* addr, socklen_t addrlen,
307                          struct timeval* timeout);
308   void Close();
309 
310   bool Chmod(mode_t mode);
311 
312   // Returns true if the entire input was copied.
313   // Otherwise an error will be set either on this file or the input.
314   // The non-const reference is needed to avoid binding this to a particular
315   // reference type.
316   bool CopyFrom(FileInstance& in, size_t length, FileInstance* stop = nullptr);
317   // Same as CopyFrom, but reads from input until EOF is reached.
318   bool CopyAllFrom(FileInstance& in, FileInstance* stop = nullptr);
319 
320   int UNMANAGED_Dup();
321   int UNMANAGED_Dup2(int newfd);
322   int Fchdir();
323   int Fcntl(int command, int value);
324   int Fsync();
325 
326   Result<void> Flock(int operation);
327 
GetErrno()328   int GetErrno() const { return errno_; }
329   int GetSockName(struct sockaddr* addr, socklen_t* addrlen);
330 
331 #ifdef __linux__
332   unsigned int VsockServerPort();
333 #endif
334 
335   int Ioctl(int request, void* val = nullptr);
IsOpen()336   bool IsOpen() const { return fd_ != -1; }
337 
338   // in probably isn't modified, but the API spec doesn't have const.
339   bool IsSet(fd_set* in) const;
340 
341   // whether this is a regular file or not
IsRegular()342   bool IsRegular() const { return is_regular_file_; }
343 
344   /**
345    * Adds a hard link to a file descriptor, based on the current working
346    * directory of the process or to some absolute path.
347    *
348    * https://www.man7.org/linux/man-pages/man2/linkat.2.html
349    *
350    * Using this on a file opened with O_TMPFILE can link it into the filesystem.
351    */
352   // Used with O_TMPFILE files to attach them to the filesystem.
353   int LinkAtCwd(const std::string& path);
354   int Listen(int backlog);
355   static void Log(const char* message);
356   off_t LSeek(off_t offset, int whence);
357   ssize_t Recv(void* buf, size_t len, int flags);
358   ssize_t RecvMsg(struct msghdr* msg, int flags);
359   ssize_t Read(void* buf, size_t count);
360 #ifdef __linux__
361   int EventfdRead(eventfd_t* value);
362 #endif
363   ssize_t Send(const void* buf, size_t len, int flags);
364   ssize_t SendMsg(const struct msghdr* msg, int flags);
365 
366   template <typename... Args>
SendFileDescriptors(const void * buf,size_t len,Args &&...sent_fds)367   ssize_t SendFileDescriptors(const void* buf, size_t len, Args&&... sent_fds) {
368     std::vector<int> fds;
369     android::base::Append(fds, std::forward<int>(sent_fds->fd_)...);
370     errno = 0;
371     auto ret = android::base::SendFileDescriptorVector(fd_, buf, len, fds);
372     errno_ = errno;
373     return ret;
374   }
375 
376   int Shutdown(int how);
377   void Set(fd_set* dest, int* max_index) const;
378   int SetSockOpt(int level, int optname, const void* optval, socklen_t optlen);
379   int GetSockOpt(int level, int optname, void* optval, socklen_t* optlen);
380   int SetTerminalRaw();
381   std::string StrError() const;
382   ScopedMMap MMap(void* addr, size_t length, int prot, int flags, off_t offset);
383   ssize_t Truncate(off_t length);
384   /*
385    * If the file is a regular file and the count is 0, Write() may detect
386    * error(s) by calling write(fd, buf, 0) declared in <unistd.h>. If detected,
387    * it will return -1. If not, 0 will be returned. For non-regular files such
388    * as socket or pipe, write(fd, buf, 0) is not specified. Write(), however,
389    * will do nothing and just return 0.
390    *
391    */
392   ssize_t Write(const void* buf, size_t count);
393 #ifdef __linux__
394   int EventfdWrite(eventfd_t value);
395 #endif
396   bool IsATTY();
397 
398   int Futimens(const struct timespec times[2]);
399 
400   // Returns the target of "/proc/getpid()/fd/" + std::to_string(fd_)
401   // if appropriate
402   Result<std::string> ProcFdLinkTarget() const;
403 
404   // inotify related functions
405   int InotifyAddWatch(const std::string& pathname, uint32_t mask);
406   void InotifyRmWatch(int watch);
407 
408  private:
409   FileInstance(int fd, int in_errno);
410   FileInstance* Accept(struct sockaddr* addr, socklen_t* addrlen) const;
411 
412   int fd_;
413   int errno_;
414   std::string identity_;
415   bool is_regular_file_;
416 };
417 
418 struct PollSharedFd {
419   SharedFD fd;
420   short events;
421   short revents;
422 };
423 
424 /* Methods that need both a fully defined SharedFD and a fully defined
425    FileInstance. */
426 
SharedFD()427 SharedFD::SharedFD() : value_(FileInstance::ClosedInstance()) {}
428 
429 }  // namespace cuttlefish
430 
431 #endif  // CUTTLEFISH_COMMON_COMMON_LIBS_FS_SHARED_FD_H_
432