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