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 
38 #include <errno.h>
39 #include <fcntl.h>
40 #include <string.h>
41 #include <unistd.h>
42 
43 #include "vm_sockets.h"
44 
45 /**
46  * Classes to to enable safe access to files.
47  * POSIX kernels have an unfortunate habit of recycling file descriptors.
48  * That can cause problems like http://b/26121457 in code that doesn't manage
49  * file lifetimes properly. These classes implement an alternate interface
50  * that has some advantages:
51  *
52  * o References to files are tightly controlled
53  * o Files are auto-closed if they go out of scope
54  * o Files are life-time aware. It is impossible to close the instance twice.
55  * o File descriptors are always initialized. By default the descriptor is
56  *   set to a closed instance.
57  *
58  * These classes are designed to mimic to POSIX interface as closely as
59  * possible. Specifically, they don't attempt to track the type of file
60  * descriptors and expose only the valid operations. This is by design, since
61  * it makes it easier to convert existing code to SharedFDs and avoids the
62  * possibility that new POSIX functionality will lead to large refactorings.
63  */
64 namespace cuttlefish {
65 
66 class FileInstance;
67 
68 /**
69  * Counted reference to a FileInstance.
70  *
71  * This is also the place where most new FileInstances are created. The creation
72  * mehtods correspond to the underlying POSIX calls.
73  *
74  * SharedFDs can be compared and stored in STL containers. The semantics are
75  * slightly different from POSIX file descriptors:
76  *
77  * o The value of the SharedFD is the identity of its underlying FileInstance.
78  *
79  * o Each newly created SharedFD has a unique, closed FileInstance:
80  *    SharedFD a, b;
81  *    assert (a != b);
82  *    a = b;
83  *    asssert(a == b);
84  *
85  * o The identity of the FileInstance is not affected by closing the file:
86  *   SharedFD a, b;
87  *   set<SharedFD> s;
88  *   s.insert(a);
89  *   assert(s.count(a) == 1);
90  *   assert(s.count(b) == 0);
91  *   a->Close();
92  *   assert(s.count(a) == 1);
93  *   assert(s.count(b) == 0);
94  *
95  * o FileInstances are never visibly recycled.
96  *
97  * o If all of the SharedFDs referring to a FileInstance go out of scope the
98  *   file is closed and the FileInstance is recycled.
99  *
100  * Creation methods must ensure that no references to the new file descriptor
101  * escape. The underlying FileInstance should have the only reference to the
102  * file descriptor. Any method that needs to know the fd must be in either
103  * SharedFD or FileInstance.
104  *
105  * SharedFDs always have an underlying FileInstance, so all of the method
106  * calls are safe in accordance with the null object pattern.
107  *
108  * Errors on system calls that create new FileInstances, such as Open, are
109  * reported with a new, closed FileInstance with the errno set.
110  */
111 class SharedFD {
112  public:
113   inline SharedFD();
SharedFD(const std::shared_ptr<FileInstance> & in)114   SharedFD(const std::shared_ptr<FileInstance>& in) : value_(in) {}
115   // Reference the listener as a FileInstance to make this FD type agnostic.
116   static SharedFD Accept(const FileInstance& listener, struct sockaddr* addr,
117                          socklen_t* addrlen);
118   static SharedFD Accept(const FileInstance& listener);
119   static SharedFD Dup(int unmanaged_fd);
120   // All SharedFDs have the O_CLOEXEC flag after creation. To remove use the
121   // Fcntl or Dup functions.
122   static SharedFD Open(const std::string& pathname, int flags, mode_t mode = 0);
123   static SharedFD Creat(const std::string& pathname, mode_t mode);
124   static bool Pipe(SharedFD* fd0, SharedFD* fd1);
125   static SharedFD Event(int initval = 0, int flags = 0);
126   static SharedFD MemfdCreate(const std::string& name, unsigned int flags = 0);
127   static bool SocketPair(int domain, int type, int protocol, SharedFD* fd0,
128                          SharedFD* fd1);
129   static SharedFD Socket(int domain, int socket_type, int protocol);
130   static SharedFD SocketLocalClient(const std::string& name, bool is_abstract,
131                                     int in_type);
132   static SharedFD SocketLocalClient(int port, int type);
133   static SharedFD SocketLocalServer(const std::string& name, bool is_abstract,
134                                     int in_type, mode_t mode);
135   static SharedFD SocketLocalServer(int port, int type);
136   static SharedFD VsockServer(unsigned int port, int type);
137   static SharedFD VsockServer(int type);
138   static SharedFD VsockClient(unsigned int cid, unsigned int port, int type);
139 
140   bool operator==(const SharedFD& rhs) const { return value_ == rhs.value_; }
141 
142   bool operator!=(const SharedFD& rhs) const { return value_ != rhs.value_; }
143 
144   bool operator<(const SharedFD& rhs) const { return value_ < rhs.value_; }
145 
146   bool operator<=(const SharedFD& rhs) const { return value_ <= rhs.value_; }
147 
148   bool operator>(const SharedFD& rhs) const { return value_ > rhs.value_; }
149 
150   bool operator>=(const SharedFD& rhs) const { return value_ >= rhs.value_; }
151 
152   std::shared_ptr<FileInstance> operator->() const { return value_; }
153 
154   const FileInstance& operator*() const { return *value_; }
155 
156   FileInstance& operator*() { return *value_; }
157 
158  private:
159   static SharedFD ErrorFD(int error);
160 
161   std::shared_ptr<FileInstance> value_;
162 };
163 
164 /**
165  * Tracks the lifetime of a file descriptor and provides methods to allow
166  * callers to use the file without knowledge of the underlying descriptor
167  * number.
168  *
169  * FileInstances have two states: Open and Closed. They may start in either
170  * state. However, once a FileIntance enters the Closed state it cannot be
171  * reopened.
172  *
173  * Construction of FileInstances is limited to select classes to avoid
174  * escaping file descriptors. At this point SharedFD is the only class
175  * that has access. We may eventually have ScopedFD and WeakFD.
176  */
177 class FileInstance {
178   // Give SharedFD access to the aliasing constructor.
179   friend class SharedFD;
180 
181  public:
~FileInstance()182   virtual ~FileInstance() { Close(); }
183 
184   // This can't be a singleton because our shared_ptr's aren't thread safe.
ClosedInstance()185   static std::shared_ptr<FileInstance> ClosedInstance() {
186     return std::shared_ptr<FileInstance>(new FileInstance(-1, EBADF));
187   }
188 
Bind(const struct sockaddr * addr,socklen_t addrlen)189   int Bind(const struct sockaddr* addr, socklen_t addrlen) {
190     errno = 0;
191     int rval = bind(fd_, addr, addrlen);
192     errno_ = errno;
193     return rval;
194   }
195 
Connect(const struct sockaddr * addr,socklen_t addrlen)196   int Connect(const struct sockaddr* addr, socklen_t addrlen) {
197     errno = 0;
198     int rval = connect(fd_, addr, addrlen);
199     errno_ = errno;
200     return rval;
201   }
202 
203   void Close();
204 
205   // Returns true if the entire input was copied.
206   // Otherwise an error will be set either on this file or the input.
207   // The non-const reference is needed to avoid binding this to a particular
208   // reference type.
209   bool CopyFrom(FileInstance& in, size_t length);
210 
UNMANAGED_Dup()211   int UNMANAGED_Dup() {
212     errno = 0;
213     int rval = TEMP_FAILURE_RETRY(dup(fd_));
214     errno_ = errno;
215     return rval;
216   }
217 
UNMANAGED_Dup2(int newfd)218   int UNMANAGED_Dup2(int newfd) {
219     errno = 0;
220     int rval = TEMP_FAILURE_RETRY(dup2(fd_, newfd));
221     errno_ = errno;
222     return rval;
223   }
224 
Fcntl(int command,int value)225   int Fcntl(int command, int value) {
226     errno = 0;
227     int rval = TEMP_FAILURE_RETRY(fcntl(fd_, command, value));
228     errno_ = errno;
229     return rval;
230   }
231 
GetErrno()232   int GetErrno() const { return errno_; }
233 
GetSockName(struct sockaddr * addr,socklen_t * addrlen)234   int GetSockName(struct sockaddr* addr, socklen_t* addrlen) {
235     errno = 0;
236     int rval = TEMP_FAILURE_RETRY(getsockname(fd_, addr, addrlen));
237     if (rval == -1) {
238       errno_ = errno;
239     }
240     return rval;
241   }
242 
VsockServerPort()243   unsigned int VsockServerPort() {
244     struct sockaddr_vm vm_socket;
245     socklen_t length = sizeof(vm_socket);
246     GetSockName(reinterpret_cast<struct sockaddr*>(&vm_socket), &length);
247     return vm_socket.svm_port;
248   }
249 
250   int Ioctl(int request, void* val = nullptr) {
251     errno = 0;
252     int rval = TEMP_FAILURE_RETRY(ioctl(fd_, request, val));
253     errno_ = errno;
254     return rval;
255   }
256 
IsOpen()257   bool IsOpen() const { return fd_ != -1; }
258 
259   // in probably isn't modified, but the API spec doesn't have const.
260   bool IsSet(fd_set* in) const;
261 
262   /**
263    * Adds a hard link to a file descriptor, based on the current working
264    * directory of the process or to some absolute path.
265    *
266    * https://www.man7.org/linux/man-pages/man2/linkat.2.html
267    *
268    * Using this on a file opened with O_TMPFILE can link it into the filesystem.
269    */
270   // Used with O_TMPFILE files to attach them to the filesystem.
LinkAtCwd(const std::string & path)271   int LinkAtCwd(const std::string& path) {
272     std::string name = "/proc/self/fd/";
273     name += std::to_string(fd_);
274     errno = 0;
275     int rval = linkat(
276         -1, name.c_str(), AT_FDCWD, path.c_str(), AT_SYMLINK_FOLLOW);
277     errno_ = errno;
278     return rval;
279   }
280 
Listen(int backlog)281   int Listen(int backlog) {
282     errno = 0;
283     int rval = listen(fd_, backlog);
284     errno_ = errno;
285     return rval;
286   }
287 
288   static void Log(const char* message);
289 
LSeek(off_t offset,int whence)290   off_t LSeek(off_t offset, int whence) {
291     errno = 0;
292     off_t rval = TEMP_FAILURE_RETRY(lseek(fd_, offset, whence));
293     errno_ = errno;
294     return rval;
295   }
296 
Recv(void * buf,size_t len,int flags)297   ssize_t Recv(void* buf, size_t len, int flags) {
298     errno = 0;
299     ssize_t rval = TEMP_FAILURE_RETRY(recv(fd_, buf, len, flags));
300     errno_ = errno;
301     return rval;
302   }
303 
RecvMsg(struct msghdr * msg,int flags)304   ssize_t RecvMsg(struct msghdr* msg, int flags) {
305     errno = 0;
306     ssize_t rval = TEMP_FAILURE_RETRY(recvmsg(fd_, msg, flags));
307     errno_ = errno;
308     return rval;
309   }
310 
Read(void * buf,size_t count)311   ssize_t Read(void* buf, size_t count) {
312     errno = 0;
313     ssize_t rval = TEMP_FAILURE_RETRY(read(fd_, buf, count));
314     errno_ = errno;
315     return rval;
316   }
317 
Send(const void * buf,size_t len,int flags)318   ssize_t Send(const void* buf, size_t len, int flags) {
319     errno = 0;
320     ssize_t rval = TEMP_FAILURE_RETRY(send(fd_, buf, len, flags));
321     errno_ = errno;
322     return rval;
323   }
324 
SendMsg(const struct msghdr * msg,int flags)325   ssize_t SendMsg(const struct msghdr* msg, int flags) {
326     errno = 0;
327     ssize_t rval = TEMP_FAILURE_RETRY(sendmsg(fd_, msg, flags));
328     errno_ = errno;
329     return rval;
330   }
331 
Shutdown(int how)332   int Shutdown(int how) {
333     errno = 0;
334     int rval = shutdown(fd_, how);
335     errno_ = errno;
336     return rval;
337   }
338 
339   void Set(fd_set* dest, int* max_index) const;
340 
SetSockOpt(int level,int optname,const void * optval,socklen_t optlen)341   int SetSockOpt(int level, int optname, const void* optval, socklen_t optlen) {
342     errno = 0;
343     int rval = setsockopt(fd_, level, optname, optval, optlen);
344     errno_ = errno;
345     return rval;
346   }
347 
StrError()348   const char* StrError() const {
349     errno = 0;
350     FileInstance* s = const_cast<FileInstance*>(this);
351     char* out = strerror_r(errno_, s->strerror_buf_, sizeof(strerror_buf_));
352 
353     // From man page:
354     //  strerror_r() returns a pointer to a string containing the error message.
355     //  This may be either a pointer to a string that the function stores in
356     //  buf, or a pointer to some (immutable) static string (in which case buf
357     //  is unused).
358     if (out != s->strerror_buf_) {
359       strncpy(s->strerror_buf_, out, sizeof(strerror_buf_));
360     }
361     return strerror_buf_;
362   }
363 
Truncate(off_t length)364   ssize_t Truncate(off_t length) {
365     errno = 0;
366     ssize_t rval = TEMP_FAILURE_RETRY(ftruncate(fd_, length));
367     errno_ = errno;
368     return rval;
369   }
370 
Write(const void * buf,size_t count)371   ssize_t Write(const void* buf, size_t count) {
372     errno = 0;
373     ssize_t rval = TEMP_FAILURE_RETRY(write(fd_, buf, count));
374     errno_ = errno;
375     return rval;
376   }
377 
378  private:
FileInstance(int fd,int in_errno)379   FileInstance(int fd, int in_errno) : fd_(fd), errno_(in_errno) {
380     // Ensure every file descriptor managed by a FileInstance has the CLOEXEC
381     // flag
382     TEMP_FAILURE_RETRY(fcntl(fd, F_SETFD, FD_CLOEXEC));
383     std::stringstream identity;
384     identity << "fd=" << fd << " @" << this;
385     identity_ = identity.str();
386   }
387 
Accept(struct sockaddr * addr,socklen_t * addrlen)388   FileInstance* Accept(struct sockaddr* addr, socklen_t* addrlen) const {
389     int fd = TEMP_FAILURE_RETRY(accept(fd_, addr, addrlen));
390     if (fd == -1) {
391       return new FileInstance(fd, errno);
392     } else {
393       return new FileInstance(fd, 0);
394     }
395   }
396 
397   int fd_;
398   int errno_;
399   std::string identity_;
400   char strerror_buf_[160];
401 };
402 
403 /* Methods that need both a fully defined SharedFD and a fully defined
404    FileInstance. */
405 
SharedFD()406 inline SharedFD::SharedFD() : value_(FileInstance::ClosedInstance()) {}
407 
408 }  // namespace cuttlefish
409 
410 #endif  // CUTTLEFISH_COMMON_COMMON_LIBS_FS_SHARED_FD_H_
411