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