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