OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include <dirent.h> |
| 6 #include <errno.h> |
| 7 #include <fcntl.h> |
| 8 #include <stdarg.h> |
| 9 #include <stdlib.h> |
| 10 #include <string.h> |
| 11 #include <sys/socket.h> |
| 12 #include <sys/types.h> |
| 13 #include <unistd.h> |
| 14 |
| 15 #include "sandbox_bpf.h" |
| 16 #include "util.h" |
| 17 |
| 18 namespace playground2 { |
| 19 |
| 20 bool Util::sendFds(int transport, const void *buf, size_t len, ...) { |
| 21 int count = 0; |
| 22 va_list ap; |
| 23 va_start(ap, len); |
| 24 while (va_arg(ap, int) >= 0) { |
| 25 ++count; |
| 26 } |
| 27 va_end(ap); |
| 28 if (!count) { |
| 29 return false; |
| 30 } |
| 31 char cmsg_buf[CMSG_SPACE(count*sizeof(int))]; |
| 32 memset(cmsg_buf, 0, sizeof(cmsg_buf)); |
| 33 struct iovec iov[2] = { { 0 } }; |
| 34 struct msghdr msg = { 0 }; |
| 35 int dummy = 0; |
| 36 iov[0].iov_base = &dummy; |
| 37 iov[0].iov_len = sizeof(dummy); |
| 38 if (buf && len > 0) { |
| 39 iov[1].iov_base = const_cast<void *>(buf); |
| 40 iov[1].iov_len = len; |
| 41 } |
| 42 msg.msg_iov = iov; |
| 43 msg.msg_iovlen = (buf && len > 0) ? 2 : 1; |
| 44 msg.msg_control = cmsg_buf; |
| 45 msg.msg_controllen = CMSG_LEN(count*sizeof(int)); |
| 46 struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg); |
| 47 cmsg->cmsg_level = SOL_SOCKET; |
| 48 cmsg->cmsg_type = SCM_RIGHTS; |
| 49 cmsg->cmsg_len = CMSG_LEN(count*sizeof(int)); |
| 50 va_start(ap, len); |
| 51 for (int i = 0, fd; (fd = va_arg(ap, int)) >= 0; ++i) { |
| 52 ((int *)CMSG_DATA(cmsg))[i] = fd; |
| 53 } |
| 54 return sendmsg(transport, &msg, 0) == |
| 55 (ssize_t)(sizeof(dummy) + ((buf && len > 0) ? len : 0)); |
| 56 } |
| 57 |
| 58 bool Util::getFds(int transport, void *buf, size_t *len, ...) { |
| 59 int count = 0; |
| 60 va_list ap; |
| 61 va_start(ap, len); |
| 62 for (int *fd; (fd = va_arg(ap, int *)) != NULL; ++count) { |
| 63 *fd = -1; |
| 64 } |
| 65 va_end(ap); |
| 66 if (!count) { |
| 67 return false; |
| 68 } |
| 69 char cmsg_buf[CMSG_SPACE(count*sizeof(int))]; |
| 70 memset(cmsg_buf, 0, sizeof(cmsg_buf)); |
| 71 struct iovec iov[2] = { { 0 } }; |
| 72 struct msghdr msg = { 0 }; |
| 73 int err; |
| 74 iov[0].iov_base = &err; |
| 75 iov[0].iov_len = sizeof(int); |
| 76 if (buf && len && *len > 0) { |
| 77 iov[1].iov_base = buf; |
| 78 iov[1].iov_len = *len; |
| 79 } |
| 80 msg.msg_iov = iov; |
| 81 msg.msg_iovlen = (buf && len && *len > 0) ? 2 : 1; |
| 82 msg.msg_control = cmsg_buf; |
| 83 msg.msg_controllen = CMSG_LEN(count*sizeof(int)); |
| 84 ssize_t bytes = recvmsg(transport, &msg, 0); |
| 85 if (len) { |
| 86 *len = bytes > (int)sizeof(int) ? bytes - sizeof(int) : 0; |
| 87 } |
| 88 if (bytes != (ssize_t)(sizeof(int) + iov[1].iov_len)) { |
| 89 if (bytes >= 0) { |
| 90 errno = 0; |
| 91 } |
| 92 return false; |
| 93 } |
| 94 if (err) { |
| 95 // "err" is the first four bytes of the payload. If these are non-zero, |
| 96 // the sender on the other side of the socketpair sent us an errno value. |
| 97 // We don't expect to get any file handles in this case. |
| 98 errno = err; |
| 99 return false; |
| 100 } |
| 101 struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg); |
| 102 if ((msg.msg_flags & (MSG_TRUNC|MSG_CTRUNC)) || |
| 103 !cmsg || |
| 104 cmsg->cmsg_level != SOL_SOCKET || |
| 105 cmsg->cmsg_type != SCM_RIGHTS || |
| 106 cmsg->cmsg_len != CMSG_LEN(count*sizeof(int))) { |
| 107 errno = EBADF; |
| 108 return false; |
| 109 } |
| 110 va_start(ap, len); |
| 111 for (int *fd, i = 0; (fd = va_arg(ap, int *)) != NULL; ++i) { |
| 112 *fd = ((int *)CMSG_DATA(cmsg))[i]; |
| 113 } |
| 114 va_end(ap); |
| 115 return true; |
| 116 } |
| 117 |
| 118 void Util::closeAllBut(int fd, ...) { |
| 119 int proc_fd; |
| 120 int fdir; |
| 121 if ((proc_fd = Sandbox::getProcFd()) < 0 || |
| 122 (fdir = openat(proc_fd, "self/fd", O_RDONLY|O_DIRECTORY)) < 0) { |
| 123 Sandbox::die("Cannot access \"/proc/self/fd\""); |
| 124 } |
| 125 int dev_null = open("/dev/null", O_RDWR); |
| 126 DIR *dir = fdopendir(fdir); |
| 127 struct dirent de, *res; |
| 128 while (!readdir_r(dir, &de, &res) && res) { |
| 129 if (res->d_name[0] < '0') { |
| 130 continue; |
| 131 } |
| 132 int i = atoi(res->d_name); |
| 133 if (i >= 0 && i != dirfd(dir) && i != dev_null) { |
| 134 va_list ap; |
| 135 va_start(ap, fd); |
| 136 for (int f = fd;; f = va_arg(ap, int)) { |
| 137 if (f < 0) { |
| 138 if (i <= 2) { |
| 139 // Never ever close 0..2. If we cannot redirect to /dev/null, |
| 140 // then we are better off leaving the standard descriptors open. |
| 141 if (dev_null >= 0) { |
| 142 TEMP_FAILURE_RETRY(dup2(dev_null, i)); |
| 143 } |
| 144 } else { |
| 145 TEMP_FAILURE_RETRY(close(i)); |
| 146 } |
| 147 break; |
| 148 } else if (i == f) { |
| 149 break; |
| 150 } |
| 151 } |
| 152 va_end(ap); |
| 153 } |
| 154 } |
| 155 closedir(dir); |
| 156 if (dev_null >= 0) { |
| 157 TEMP_FAILURE_RETRY(close(dev_null)); |
| 158 } |
| 159 return; |
| 160 } |
| 161 |
| 162 } // namespace |
OLD | NEW |