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