| 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/linux/seccomp-bpf/sandbox_bpf.h" | |
| 16 #include "sandbox/linux/seccomp-bpf/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 (reinterpret_cast<int *>(CMSG_DATA(cmsg)))[i] = fd; | |
| 53 } | |
| 54 return sendmsg(transport, &msg, 0) == | |
| 55 static_cast<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 > static_cast<int>(sizeof(int)) ? bytes - sizeof(int) : 0; | |
| 87 } | |
| 88 if (bytes != static_cast<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 = (reinterpret_cast<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::proc_fd()) < 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 if (HANDLE_EINTR(dup2(dev_null, i))) { | |
| 143 SANDBOX_DIE("Cannot dup2()"); | |
| 144 } | |
| 145 } | |
| 146 } else { | |
| 147 if (HANDLE_EINTR(close(i))) { } | |
| 148 } | |
| 149 break; | |
| 150 } else if (i == f) { | |
| 151 break; | |
| 152 } | |
| 153 } | |
| 154 va_end(ap); | |
| 155 } | |
| 156 } | |
| 157 closedir(dir); | |
| 158 if (dev_null >= 0) { | |
| 159 if (HANDLE_EINTR(close(dev_null))) { } | |
| 160 } | |
| 161 return; | |
| 162 } | |
| 163 | |
| 164 } // namespace | |
| OLD | NEW |