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