• 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 
37 #include <errno.h>
38 #include <fcntl.h>
39 #include <string.h>
40 #include <unistd.h>
41 
42 #include "common/libs/auto_resources/auto_resources.h"
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 cvd {
65 
66 class FileInstance;
67 
68 /**
69  * Describes the fields in msghdr that are honored by the *MsgAndFDs
70  * calls.
71  */
72 struct InbandMessageHeader {
73   void* msg_name;
74   socklen_t msg_namelen;
75   struct iovec* msg_iov;
76   size_t msg_iovlen;
77   int msg_flags;
78 
ConvertInbandMessageHeader79   void Convert(struct msghdr* dest) const {
80     dest->msg_name = msg_name;
81     dest->msg_namelen = msg_namelen;
82     dest->msg_iov = msg_iov;
83     dest->msg_iovlen = msg_iovlen;
84     dest->msg_flags = msg_flags;
85   }
86 };
87 
88 /**
89  * Counted reference to a FileInstance.
90  *
91  * This is also the place where most new FileInstances are created. The creation
92  * mehtods correspond to the underlying POSIX calls.
93  *
94  * SharedFDs can be compared and stored in STL containers. The semantics are
95  * slightly different from POSIX file descriptors:
96  *
97  * o The value of the SharedFD is the identity of its underlying FileInstance.
98  *
99  * o Each newly created SharedFD has a unique, closed FileInstance:
100  *    SharedFD a, b;
101  *    assert (a != b);
102  *    a = b;
103  *    asssert(a == b);
104  *
105  * o The identity of the FileInstance is not affected by closing the file:
106  *   SharedFD a, b;
107  *   set<SharedFD> s;
108  *   s.insert(a);
109  *   assert(s.count(a) == 1);
110  *   assert(s.count(b) == 0);
111  *   a->Close();
112  *   assert(s.count(a) == 1);
113  *   assert(s.count(b) == 0);
114  *
115  * o FileInstances are never visibly recycled.
116  *
117  * o If all of the SharedFDs referring to a FileInstance go out of scope the
118  *   file is closed and the FileInstance is recycled.
119  *
120  * Creation methods must ensure that no references to the new file descriptor
121  * escape. The underlying FileInstance should have the only reference to the
122  * file descriptor. Any method that needs to know the fd must be in either
123  * SharedFD or FileInstance.
124  *
125  * SharedFDs always have an underlying FileInstance, so all of the method
126  * calls are safe in accordance with the null object pattern.
127  *
128  * Errors on system calls that create new FileInstances, such as Open, are
129  * reported with a new, closed FileInstance with the errno set.
130  */
131 class SharedFD {
132  public:
133   inline SharedFD();
SharedFD(const std::shared_ptr<FileInstance> & in)134   SharedFD(const std::shared_ptr<FileInstance>& in) : value_(in) {}
135   // Reference the listener as a FileInstance to make this FD type agnostic.
136   static SharedFD Accept(const FileInstance& listener, struct sockaddr* addr,
137                          socklen_t* addrlen);
138   static SharedFD Accept(const FileInstance& listener);
139   static SharedFD Dup(int unmanaged_fd);
140   static SharedFD GetControlSocket(const char* name);
141   // All SharedFDs have the O_CLOEXEC flag after creation. To remove use the
142   // Fcntl or Dup functions.
143   static SharedFD Open(const char* pathname, int flags, mode_t mode = 0);
144   static SharedFD Creat(const char* pathname, mode_t mode);
145   static bool Pipe(SharedFD* fd0, SharedFD* fd1);
146   static SharedFD Event(int initval = 0, int flags = 0);
147   static SharedFD Epoll(int flags = 0);
148   static bool SocketPair(int domain, int type, int protocol, SharedFD* fd0,
149                          SharedFD* fd1);
150   static SharedFD Socket(int domain, int socket_type, int protocol);
151   static SharedFD SocketLocalClient(const char* name, bool is_abstract,
152                                     int in_type);
153   static SharedFD SocketLocalClient(int port, int type);
154   static SharedFD SocketLocalServer(const char* name, bool is_abstract,
155                                     int in_type, mode_t mode);
156   static SharedFD SocketLocalServer(int port, int type);
157   static SharedFD SocketSeqPacketServer(const char* name, mode_t mode);
158   static SharedFD SocketSeqPacketClient(const char* name);
159   static SharedFD VsockServer(unsigned int port, int type);
160   static SharedFD VsockClient(unsigned int cid, unsigned int port, int type);
161   static SharedFD TimerFD(int clock, int flags);
162 
163   bool operator==(const SharedFD& rhs) const { return value_ == rhs.value_; }
164 
165   bool operator!=(const SharedFD& rhs) const { return value_ != rhs.value_; }
166 
167   bool operator<(const SharedFD& rhs) const { return value_ < rhs.value_; }
168 
169   bool operator<=(const SharedFD& rhs) const { return value_ <= rhs.value_; }
170 
171   bool operator>(const SharedFD& rhs) const { return value_ > rhs.value_; }
172 
173   bool operator>=(const SharedFD& rhs) const { return value_ >= rhs.value_; }
174 
175   std::shared_ptr<FileInstance> operator->() const { return value_; }
176 
177   const cvd::FileInstance& operator*() const { return *value_; }
178 
179   cvd::FileInstance& operator*() { return *value_; }
180 
181  private:
182   static SharedFD ErrorFD(int error);
183 
184   std::shared_ptr<FileInstance> value_;
185 };
186 
187 /**
188  * Tracks the lifetime of a file descriptor and provides methods to allow
189  * callers to use the file without knowledge of the underlying descriptor
190  * number.
191  *
192  * FileInstances have two states: Open and Closed. They may start in either
193  * state. However, once a FileIntance enters the Closed state it cannot be
194  * reopened.
195  *
196  * Construction of FileInstances is limited to select classes to avoid
197  * escaping file descriptors. At this point SharedFD is the only class
198  * that has access. We may eventually have ScopedFD and WeakFD.
199  */
200 class FileInstance {
201   // Give SharedFD access to the aliasing constructor.
202   friend class SharedFD;
203 
204  public:
~FileInstance()205   virtual ~FileInstance() { Close(); }
206 
207   // This can't be a singleton because our shared_ptr's aren't thread safe.
ClosedInstance()208   static std::shared_ptr<FileInstance> ClosedInstance() {
209     return std::shared_ptr<FileInstance>(new FileInstance(-1, EBADF));
210   }
211 
Bind(const struct sockaddr * addr,socklen_t addrlen)212   int Bind(const struct sockaddr* addr, socklen_t addrlen) {
213     errno = 0;
214     int rval = bind(fd_, addr, addrlen);
215     errno_ = errno;
216     return rval;
217   }
218 
Connect(const struct sockaddr * addr,socklen_t addrlen)219   int Connect(const struct sockaddr* addr, socklen_t addrlen) {
220     errno = 0;
221     int rval = connect(fd_, addr, addrlen);
222     errno_ = errno;
223     return rval;
224   }
225 
226   void Close();
227 
228   // Returns true if the entire input was copied.
229   // Otherwise an error will be set either on this file or the input.
230   // The non-const reference is needed to avoid binding this to a particular
231   // reference type.
232   bool CopyFrom(FileInstance& in);
233   bool CopyFrom(FileInstance& in, size_t length);
234 
UNMANAGED_Dup()235   int UNMANAGED_Dup() {
236     errno = 0;
237     int rval = TEMP_FAILURE_RETRY(dup(fd_));
238     errno_ = errno;
239     return rval;
240   }
241 
UNMANAGED_Dup2(int newfd)242   int UNMANAGED_Dup2(int newfd) {
243     errno = 0;
244     int rval = TEMP_FAILURE_RETRY(dup2(fd_, newfd));
245     errno_ = errno;
246     return rval;
247   }
248 
EpollCtl(int op,cvd::SharedFD new_fd,struct epoll_event * event)249   int EpollCtl(int op, cvd::SharedFD new_fd, struct epoll_event* event) {
250     errno = 0;
251     int rval = TEMP_FAILURE_RETRY(epoll_ctl(fd_, op, new_fd->fd_, event));
252     errno_ = errno;
253     return rval;
254   }
255 
EpollWait(struct epoll_event * events,int maxevents,int timeout)256   int EpollWait(struct epoll_event* events, int maxevents, int timeout) {
257     errno = 0;
258     int rval = TEMP_FAILURE_RETRY(epoll_wait(fd_, events, maxevents, timeout));
259     errno_ = errno;
260     return rval;
261   }
262 
Fchown(uid_t owner,gid_t group)263   int Fchown(uid_t owner, gid_t group) {
264     errno = 0;
265     int rval = TEMP_FAILURE_RETRY(fchown(fd_, owner, group));
266     errno_ = errno;
267     return rval;
268   }
269 
Fcntl(int command,int value)270   int Fcntl(int command, int value) {
271     errno = 0;
272     int rval = TEMP_FAILURE_RETRY(fcntl(fd_, command, value));
273     errno_ = errno;
274     return rval;
275   }
276 
Fstat(struct stat * buf)277   int Fstat(struct stat* buf) {
278     errno = 0;
279     int rval = TEMP_FAILURE_RETRY(fstat(fd_, buf));
280     errno_ = errno;
281     return rval;
282   }
283 
GetErrno()284   int GetErrno() const { return errno_; }
285 
GetSockOpt(int level,int optname,void * optval,socklen_t * optlen)286   int GetSockOpt(int level, int optname, void* optval, socklen_t* optlen) {
287     errno = 0;
288     int rval = getsockopt(fd_, level, optname, optval, optlen);
289     if (rval == -1) {
290       errno_ = errno;
291     }
292     return rval;
293   }
294 
295   void Identify(const char* identity);
296 
297   int Ioctl(int request, void* val = nullptr) {
298     errno = 0;
299     int rval = TEMP_FAILURE_RETRY(ioctl(fd_, request, val));
300     errno_ = errno;
301     return rval;
302   }
303 
IsOpen()304   bool IsOpen() const { return fd_ != -1; }
305 
306   // in probably isn't modified, but the API spec doesn't have const.
307   bool IsSet(fd_set* in) const;
308 
Listen(int backlog)309   int Listen(int backlog) {
310     errno = 0;
311     int rval = listen(fd_, backlog);
312     errno_ = errno;
313     return rval;
314   }
315 
316   static void Log(const char* message);
317 
LSeek(off_t offset,int whence)318   off_t LSeek(off_t offset, int whence) {
319     errno = 0;
320     off_t rval = TEMP_FAILURE_RETRY(lseek(fd_, offset, whence));
321     errno_ = errno;
322     return rval;
323   }
324 
Mmap(void * addr,size_t length,int prot,int flags,off_t offset)325   void* Mmap(void* addr, size_t length, int prot, int flags, off_t offset) {
326     errno = 0;
327     void* rval = mmap(addr, length, prot, flags, fd_, offset);
328     errno_ = errno;
329     return rval;
330   }
331 
Pread(void * buf,size_t count,off_t offset)332   ssize_t Pread(void* buf, size_t count, off_t offset) {
333     errno = 0;
334     ssize_t rval = TEMP_FAILURE_RETRY(pread(fd_, buf, count, offset));
335     errno_ = errno;
336     return rval;
337   }
338 
Recv(void * buf,size_t len,int flags)339   ssize_t Recv(void* buf, size_t len, int flags) {
340     errno = 0;
341     ssize_t rval = TEMP_FAILURE_RETRY(recv(fd_, buf, len, flags));
342     errno_ = errno;
343     return rval;
344   }
345 
RecvFrom(void * buf,size_t len,int flags,struct sockaddr * src_addr,socklen_t * addr_len)346   ssize_t RecvFrom(void* buf, size_t len, int flags, struct sockaddr* src_addr,
347                    socklen_t* addr_len) {
348     errno = 0;
349     ssize_t rval =
350         TEMP_FAILURE_RETRY(recvfrom(fd_, buf, len, flags, src_addr, addr_len));
351     errno_ = errno;
352     return rval;
353   }
354 
RecvMsg(struct msghdr * msg,int flags)355   ssize_t RecvMsg(struct msghdr* msg, int flags) {
356     errno = 0;
357     ssize_t rval = TEMP_FAILURE_RETRY(recvmsg(fd_, msg, flags));
358     errno_ = errno;
359     return rval;
360   }
361 
362   template <size_t SZ>
RecvMsgAndFDs(const struct InbandMessageHeader & msg_in,int flags,SharedFD (* new_fds)[SZ])363   ssize_t RecvMsgAndFDs(const struct InbandMessageHeader& msg_in, int flags,
364                         SharedFD (*new_fds)[SZ]) {
365     // We need to make some modifications to land the fds. Make it clear
366     // that there are no updates to the msg being passed in during this call.
367     struct msghdr msg;
368     msg_in.Convert(&msg);
369     union {
370       char buffer[CMSG_SPACE(SZ * sizeof(int))];
371       struct cmsghdr this_aligns_buffer;
372     } u;
373     msg.msg_control = u.buffer;
374     msg.msg_controllen = sizeof(u.buffer);
375 
376     cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
377     cmsg->cmsg_len = CMSG_LEN(SZ * sizeof(int));
378     cmsg->cmsg_level = SOL_SOCKET;
379     cmsg->cmsg_type = SCM_RIGHTS;
380     int* fd_array = reinterpret_cast<int*>(CMSG_DATA(cmsg));
381     for (size_t i = 0; i < SZ; ++i) {
382       fd_array[i] = -1;
383     }
384     ssize_t rval = RecvMsg(&msg, flags);
385     for (size_t i = 0; i < SZ; ++i) {
386       (*new_fds)[i] =
387           std::shared_ptr<FileInstance>(new FileInstance(fd_array[i], errno));
388     }
389     return rval;
390   }
391 
Read(void * buf,size_t count)392   ssize_t Read(void* buf, size_t count) {
393     errno = 0;
394     ssize_t rval = TEMP_FAILURE_RETRY(read(fd_, buf, count));
395     errno_ = errno;
396     return rval;
397   }
398 
Send(const void * buf,size_t len,int flags)399   ssize_t Send(const void* buf, size_t len, int flags) {
400     errno = 0;
401     ssize_t rval = TEMP_FAILURE_RETRY(send(fd_, buf, len, flags));
402     errno_ = errno;
403     return rval;
404   }
405 
SendMsg(const struct msghdr * msg,int flags)406   ssize_t SendMsg(const struct msghdr* msg, int flags) {
407     errno = 0;
408     ssize_t rval = TEMP_FAILURE_RETRY(sendmsg(fd_, msg, flags));
409     errno_ = errno;
410     return rval;
411   }
412 
413   template <size_t SZ>
SendMsgAndFDs(const struct InbandMessageHeader & msg_in,int flags,const SharedFD (& fds)[SZ])414   ssize_t SendMsgAndFDs(const struct InbandMessageHeader& msg_in, int flags,
415                         const SharedFD (&fds)[SZ]) {
416     struct msghdr msg;
417     msg_in.Convert(&msg);
418     union {
419       char buffer[CMSG_SPACE(SZ * sizeof(int))];
420       struct cmsghdr this_aligns_buffer;
421     } u;
422     msg.msg_control = u.buffer;
423     msg.msg_controllen = sizeof(u.buffer);
424 
425     cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
426     cmsg->cmsg_len = CMSG_LEN(SZ * sizeof(int));
427     cmsg->cmsg_level = SOL_SOCKET;
428     cmsg->cmsg_type = SCM_RIGHTS;
429     int* fd_array = reinterpret_cast<int*>(CMSG_DATA(cmsg));
430     for (size_t i = 0; i < SZ; ++i) {
431       fd_array[i] = fds[i]->fd_;
432     }
433     return SendMsg(&msg, flags);
434   }
435 
Shutdown(int how)436   int Shutdown(int how) {
437     errno = 0;
438     int rval = shutdown(fd_, how);
439     errno_ = errno;
440     return rval;
441   }
442 
SendTo(const void * buf,size_t len,int flags,const struct sockaddr * dest_addr,socklen_t addrlen)443   ssize_t SendTo(const void* buf, size_t len, int flags,
444                  const struct sockaddr* dest_addr, socklen_t addrlen) {
445     errno = 0;
446     ssize_t rval =
447         TEMP_FAILURE_RETRY(sendto(fd_, buf, len, flags, dest_addr, addrlen));
448     errno_ = errno;
449     return rval;
450   }
451 
452   void Set(fd_set* dest, int* max_index) const;
453 
SetSockOpt(int level,int optname,const void * optval,socklen_t optlen)454   int SetSockOpt(int level, int optname, const void* optval, socklen_t optlen) {
455     errno = 0;
456     int rval = setsockopt(fd_, level, optname, optval, optlen);
457     errno_ = errno;
458     return rval;
459   }
460 
StrError()461   const char* StrError() const {
462     errno = 0;
463     FileInstance* s = const_cast<FileInstance*>(this);
464     char* out = strerror_r(errno_, s->strerror_buf_, sizeof(strerror_buf_));
465 
466     // From man page:
467     //  strerror_r() returns a pointer to a string containing the error message.
468     //  This may be either a pointer to a string that the function stores in
469     //  buf, or a pointer to some (immutable) static string (in which case buf
470     //  is unused).
471     if (out != s->strerror_buf_) {
472       strncpy(s->strerror_buf_, out, sizeof(strerror_buf_));
473     }
474     return strerror_buf_;
475   }
476 
TimerGet(struct itimerspec * curr_value)477   int TimerGet(struct itimerspec* curr_value) {
478     errno = 0;
479     int rval = timerfd_gettime(fd_, curr_value);
480     errno_ = errno;
481     return rval;
482   }
483 
TimerSet(int flags,const struct itimerspec * new_value,struct itimerspec * old_value)484   int TimerSet(int flags, const struct itimerspec* new_value,
485                struct itimerspec* old_value) {
486     errno = 0;
487     int rval = timerfd_settime(fd_, flags, new_value, old_value);
488     errno_ = errno;
489     return rval;
490   }
491 
Truncate(off_t length)492   ssize_t Truncate(off_t length) {
493     errno = 0;
494     ssize_t rval = TEMP_FAILURE_RETRY(ftruncate(fd_, length));
495     errno_ = errno;
496     return rval;
497   }
498 
Write(const void * buf,size_t count)499   ssize_t Write(const void* buf, size_t count) {
500     errno = 0;
501     ssize_t rval = TEMP_FAILURE_RETRY(write(fd_, buf, count));
502     errno_ = errno;
503     return rval;
504   }
505 
WriteV(struct iovec * iov,int iovcount)506   ssize_t WriteV(struct iovec* iov, int iovcount) {
507     errno = 0;
508     ssize_t rval = TEMP_FAILURE_RETRY(writev(fd_, iov, iovcount));
509     errno_ = errno;
510     return rval;
511   }
512 
513  private:
FileInstance(int fd,int in_errno)514   FileInstance(int fd, int in_errno) : fd_(fd), errno_(in_errno) {
515     // Ensure every file descriptor managed by a FileInstance has the CLOEXEC
516     // flag
517     TEMP_FAILURE_RETRY(fcntl(fd, F_SETFD, FD_CLOEXEC));
518     identity_.PrintF("fd=%d @%p", fd, this);
519   }
520 
Accept(struct sockaddr * addr,socklen_t * addrlen)521   FileInstance* Accept(struct sockaddr* addr, socklen_t* addrlen) const {
522     int fd = TEMP_FAILURE_RETRY(accept(fd_, addr, addrlen));
523     if (fd == -1) {
524       return new FileInstance(fd, errno);
525     } else {
526       return new FileInstance(fd, 0);
527     }
528   }
529 
530   int fd_;
531   int errno_;
532   AutoFreeBuffer identity_;
533   char strerror_buf_[160];
534 };
535 
536 /* Methods that need both a fully defined SharedFD and a fully defined
537    FileInstance. */
538 
SharedFD()539 inline SharedFD::SharedFD() : value_(FileInstance::ClosedInstance()) {}
540 
541 }  // namespace cvd
542 
543 #endif  // CUTTLEFISH_COMMON_COMMON_LIBS_FS_SHARED_FD_H_
544