blob: b597aca4aca081b8e09f29c88c3cb96df292094b [file] [log] [blame]
Avi Drissmane4622aa2022-09-08 20:36:061// Copyright 2011 The Chromium Authors
[email protected]cc8f1462009-06-12 17:36:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
danakj51d26a42024-04-25 14:23:565#ifdef UNSAFE_BUFFERS_BUILD
6// TODO(crbug.com/40284755): Remove this and spanify to fix the errors.
7#pragma allow_unsafe_buffers
8#endif
9
Boris Vidolov8ecb49e2017-07-26 06:35:4610#include "base/posix/unix_domain_socket.h"
[email protected]cc8f1462009-06-12 17:36:5511
[email protected]f884f2a2010-02-02 01:24:4912#include <errno.h>
[email protected]cc8f1462009-06-12 17:36:5513#include <sys/socket.h>
Nico Weber2388b392021-12-09 00:15:2514#include <sys/uio.h>
Boris Vidolov8ecb49e2017-07-26 06:35:4615#include <sys/un.h>
[email protected]8c89c592013-01-18 10:34:2916#include <unistd.h>
[email protected]cc8f1462009-06-12 17:36:5517
[email protected]8feaa672014-04-30 21:57:1018#include <vector>
19
20#include "base/files/scoped_file.h"
[email protected]cc8f1462009-06-12 17:36:5521#include "base/logging.h"
Hans Wennborgafeb3902020-06-17 14:42:2922#include "base/notreached.h"
Peter Kastingb74454862022-07-13 00:40:1223#include "base/numerics/safe_conversions.h"
[email protected]43235a02009-06-18 00:44:4224#include "base/pickle.h"
[email protected]2025d002012-11-14 20:54:3525#include "base/posix/eintr_wrapper.h"
avi9b6f42932015-12-26 22:15:1426#include "build/build_config.h"
[email protected]cc8f1462009-06-12 17:36:5527
brettwa027ae32015-06-02 19:48:2928namespace base {
29
[email protected]375a8462012-10-12 19:59:3930const size_t UnixDomainSocket::kMaxFileDescriptors = 16;
31
shunhsingou6a524792017-04-06 04:17:0632bool CreateSocketPair(ScopedFD* one, ScopedFD* two) {
[email protected]8feaa672014-04-30 21:57:1033 int raw_socks[2];
Xiaohan Wang1a8409ee2022-01-15 14:56:4134#if BUILDFLAG(IS_APPLE)
Boris Vidolov8ecb49e2017-07-26 06:35:4635 // macOS does not support SEQPACKET.
36 const int flags = SOCK_STREAM;
37#else
38 const int flags = SOCK_SEQPACKET;
39#endif
Peter Kasting134ef9af2024-12-28 02:30:0940 if (socketpair(AF_UNIX, flags, 0, raw_socks) == -1) {
[email protected]8feaa672014-04-30 21:57:1041 return false;
Peter Kasting134ef9af2024-12-28 02:30:0942 }
[email protected]8feaa672014-04-30 21:57:1043 one->reset(raw_socks[0]);
44 two->reset(raw_socks[1]);
45 return true;
46}
47
[email protected]cf3ac3972010-12-22 20:02:2948// static
[email protected]1dc3796b2014-04-24 23:42:4249bool UnixDomainSocket::EnableReceiveProcessId(int fd) {
Xiaohan Wang1a8409ee2022-01-15 14:56:4150#if !BUILDFLAG(IS_APPLE)
[email protected]1dc3796b2014-04-24 23:42:4251 const int enable = 1;
52 return setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &enable, sizeof(enable)) == 0;
Boris Vidolov8ecb49e2017-07-26 06:35:4653#else
54 // SO_PASSCRED is not supported on macOS.
55 return true;
Xiaohan Wang1a8409ee2022-01-15 14:56:4156#endif // BUILDFLAG(IS_APPLE)
[email protected]1dc3796b2014-04-24 23:42:4257}
58
59// static
[email protected]cf3ac3972010-12-22 20:02:2960bool UnixDomainSocket::SendMsg(int fd,
61 const void* buf,
62 size_t length,
63 const std::vector<int>& fds) {
[email protected]8c89c592013-01-18 10:34:2964 struct msghdr msg = {};
Boris Vidolov8ecb49e2017-07-26 06:35:4665 struct iovec iov = {const_cast<void*>(buf), length};
[email protected]cc8f1462009-06-12 17:36:5566 msg.msg_iov = &iov;
67 msg.msg_iovlen = 1;
68
Ivan Kotenkova16212a52017-11-08 12:37:3369 char* control_buffer = nullptr;
[email protected]cc8f1462009-06-12 17:36:5570 if (fds.size()) {
Peter Kasting0aa382f62022-07-05 15:57:0771 const size_t control_len = CMSG_SPACE(sizeof(int) * fds.size());
[email protected]cc8f1462009-06-12 17:36:5572 control_buffer = new char[control_len];
[email protected]cc8f1462009-06-12 17:36:5573
[email protected]8c89c592013-01-18 10:34:2974 struct cmsghdr* cmsg;
[email protected]cc8f1462009-06-12 17:36:5575 msg.msg_control = control_buffer;
Peter Kasting2f61c8b2022-07-19 23:43:4676#if BUILDFLAG(IS_APPLE)
Peter Kastingb74454862022-07-13 00:40:1277 msg.msg_controllen = checked_cast<socklen_t>(control_len);
Peter Kasting2f61c8b2022-07-19 23:43:4678#else
79 msg.msg_controllen = control_len;
80#endif
[email protected]cc8f1462009-06-12 17:36:5581 cmsg = CMSG_FIRSTHDR(&msg);
82 cmsg->cmsg_level = SOL_SOCKET;
83 cmsg->cmsg_type = SCM_RIGHTS;
Peter Kasting2f61c8b2022-07-19 23:43:4684#if BUILDFLAG(IS_APPLE)
85 cmsg->cmsg_len = checked_cast<u_int>(CMSG_LEN(sizeof(int) * fds.size()));
86#else
87 cmsg->cmsg_len = CMSG_LEN(sizeof(int) * fds.size());
88#endif
[email protected]cc8f1462009-06-12 17:36:5589 memcpy(CMSG_DATA(cmsg), &fds[0], sizeof(int) * fds.size());
90 msg.msg_controllen = cmsg->cmsg_len;
91 }
92
Nico Weberb8da41e22024-11-25 20:51:3293 // Avoid a SIGPIPE if the other end breaks the connection.
94 // Due to a bug in the Linux kernel (net/unix/af_unix.c) MSG_NOSIGNAL isn't
95 // regarded for SOCK_SEQPACKET in the AF_UNIX domain, but it is mandated by
96 // POSIX.
97 const ssize_t r = HANDLE_EINTR(sendmsg(fd, &msg, MSG_NOSIGNAL));
[email protected]cc8f1462009-06-12 17:36:5598 const bool ret = static_cast<ssize_t>(length) == r;
99 delete[] control_buffer;
100 return ret;
101}
102
[email protected]cf3ac3972010-12-22 20:02:29103// static
104ssize_t UnixDomainSocket::RecvMsg(int fd,
105 void* buf,
106 size_t length,
mdempskyf12295a2015-12-09 22:54:46107 std::vector<ScopedFD>* fds) {
Ivan Kotenkova16212a52017-11-08 12:37:33108 return UnixDomainSocket::RecvMsgWithPid(fd, buf, length, fds, nullptr);
[email protected]1dc3796b2014-04-24 23:42:42109}
110
111// static
112ssize_t UnixDomainSocket::RecvMsgWithPid(int fd,
113 void* buf,
114 size_t length,
mdempskyf12295a2015-12-09 22:54:46115 std::vector<ScopedFD>* fds,
brettwa027ae32015-06-02 19:48:29116 ProcessId* pid) {
[email protected]1dc3796b2014-04-24 23:42:42117 return UnixDomainSocket::RecvMsgWithFlags(fd, buf, length, 0, fds, pid);
[email protected]b0984152013-04-26 00:34:54118}
119
120// static
121ssize_t UnixDomainSocket::RecvMsgWithFlags(int fd,
122 void* buf,
123 size_t length,
124 int flags,
mdempskyf12295a2015-12-09 22:54:46125 std::vector<ScopedFD>* fds,
brettwa027ae32015-06-02 19:48:29126 ProcessId* out_pid) {
[email protected]cc8f1462009-06-12 17:36:55127 fds->clear();
128
[email protected]8c89c592013-01-18 10:34:29129 struct msghdr msg = {};
Boris Vidolov8ecb49e2017-07-26 06:35:46130 struct iovec iov = {buf, length};
[email protected]cc8f1462009-06-12 17:36:55131 msg.msg_iov = &iov;
132 msg.msg_iovlen = 1;
133
hidehiko2b720d22014-10-17 06:40:30134 const size_t kControlBufferSize =
135 CMSG_SPACE(sizeof(int) * kMaxFileDescriptors)
Xiaohan Wang1a8409ee2022-01-15 14:56:41136#if !BUILDFLAG(IS_APPLE)
Nico Weber2388b392021-12-09 00:15:25137 // macOS does not support ucred.
138 // macOS supports xucred, but this structure is insufficient.
hidehiko2b720d22014-10-17 06:40:30139 + CMSG_SPACE(sizeof(struct ucred))
Xiaohan Wang1a8409ee2022-01-15 14:56:41140#endif // !BUILDFLAG(IS_APPLE)
hidehiko2b720d22014-10-17 06:40:30141 ;
142 char control_buffer[kControlBufferSize];
[email protected]cc8f1462009-06-12 17:36:55143 msg.msg_control = control_buffer;
144 msg.msg_controllen = sizeof(control_buffer);
145
[email protected]b0984152013-04-26 00:34:54146 const ssize_t r = HANDLE_EINTR(recvmsg(fd, &msg, flags));
Peter Kasting134ef9af2024-12-28 02:30:09147 if (r == -1) {
[email protected]cc8f1462009-06-12 17:36:55148 return -1;
Peter Kasting134ef9af2024-12-28 02:30:09149 }
[email protected]cc8f1462009-06-12 17:36:55150
Ivan Kotenkova16212a52017-11-08 12:37:33151 int* wire_fds = nullptr;
Peter Kasting0aa382f62022-07-05 15:57:07152 size_t wire_fds_len = 0;
brettwa027ae32015-06-02 19:48:29153 ProcessId pid = -1;
[email protected]cc8f1462009-06-12 17:36:55154
155 if (msg.msg_controllen > 0) {
156 struct cmsghdr* cmsg;
157 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
Peter Kasting0aa382f62022-07-05 15:57:07158 const size_t payload_len = cmsg->cmsg_len - CMSG_LEN(0);
Boris Vidolov8ecb49e2017-07-26 06:35:46159 if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
danakj94219a212015-03-09 22:27:25160 DCHECK_EQ(payload_len % sizeof(int), 0u);
161 DCHECK_EQ(wire_fds, static_cast<void*>(nullptr));
[email protected]cc8f1462009-06-12 17:36:55162 wire_fds = reinterpret_cast<int*>(CMSG_DATA(cmsg));
163 wire_fds_len = payload_len / sizeof(int);
[email protected]1dc3796b2014-04-24 23:42:42164 }
Xiaohan Wang1a8409ee2022-01-15 14:56:41165#if !BUILDFLAG(IS_APPLE)
Nico Weber2388b392021-12-09 00:15:25166 // macOS does not support SCM_CREDENTIALS.
[email protected]1dc3796b2014-04-24 23:42:42167 if (cmsg->cmsg_level == SOL_SOCKET &&
168 cmsg->cmsg_type == SCM_CREDENTIALS) {
danakj94219a212015-03-09 22:27:25169 DCHECK_EQ(payload_len, sizeof(struct ucred));
170 DCHECK_EQ(pid, -1);
[email protected]1dc3796b2014-04-24 23:42:42171 pid = reinterpret_cast<struct ucred*>(CMSG_DATA(cmsg))->pid;
[email protected]cc8f1462009-06-12 17:36:55172 }
Xiaohan Wang1a8409ee2022-01-15 14:56:41173#endif // !BUILDFLAG(IS_APPLE)
[email protected]cc8f1462009-06-12 17:36:55174 }
175 }
176
177 if (msg.msg_flags & MSG_TRUNC || msg.msg_flags & MSG_CTRUNC) {
Harald Alvestrand67def1f2018-04-12 11:33:58178 if (msg.msg_flags & MSG_CTRUNC) {
179 // Extraordinary case, not caller fixable. Log something.
180 LOG(ERROR) << "recvmsg returned MSG_CTRUNC flag, buffer len is "
181 << msg.msg_controllen;
182 }
Peter Kasting134ef9af2024-12-28 02:30:09183 for (size_t i = 0; i < wire_fds_len; ++i) {
[email protected]cc8f1462009-06-12 17:36:55184 close(wire_fds[i]);
Peter Kasting134ef9af2024-12-28 02:30:09185 }
[email protected]cc8f1462009-06-12 17:36:55186 errno = EMSGSIZE;
187 return -1;
188 }
189
[email protected]a4a55802014-03-17 22:00:24190 if (wire_fds) {
Peter Kasting134ef9af2024-12-28 02:30:09191 for (size_t i = 0; i < wire_fds_len; ++i) {
Peter Kasting811504a72025-01-09 03:18:50192 fds->emplace_back(wire_fds[i]);
Peter Kasting134ef9af2024-12-28 02:30:09193 }
[email protected]a4a55802014-03-17 22:00:24194 }
[email protected]cc8f1462009-06-12 17:36:55195
[email protected]1dc3796b2014-04-24 23:42:42196 if (out_pid) {
Xiaohan Wang1a8409ee2022-01-15 14:56:41197#if BUILDFLAG(IS_APPLE)
Boris Vidolov8ecb49e2017-07-26 06:35:46198 socklen_t pid_size = sizeof(pid);
Peter Kasting134ef9af2024-12-28 02:30:09199 if (getsockopt(fd, SOL_LOCAL, LOCAL_PEERPID, &pid, &pid_size) != 0) {
Boris Vidolov8ecb49e2017-07-26 06:35:46200 pid = -1;
Peter Kasting134ef9af2024-12-28 02:30:09201 }
Boris Vidolov8ecb49e2017-07-26 06:35:46202#else
[email protected]d4380132014-05-16 08:57:55203 // |pid| will legitimately be -1 if we read EOF, so only DCHECK if we
204 // actually received a message. Unfortunately, Linux allows sending zero
205 // length messages, which are indistinguishable from EOF, so this check
206 // has false negatives.
Peter Kasting134ef9af2024-12-28 02:30:09207 if (r > 0 || msg.msg_controllen > 0) {
[email protected]d4380132014-05-16 08:57:55208 DCHECK_GE(pid, 0);
Peter Kasting134ef9af2024-12-28 02:30:09209 }
Boris Vidolov8ecb49e2017-07-26 06:35:46210#endif
[email protected]d4380132014-05-16 08:57:55211
[email protected]1dc3796b2014-04-24 23:42:42212 *out_pid = pid;
213 }
214
[email protected]cc8f1462009-06-12 17:36:55215 return r;
216}
217
[email protected]cf3ac3972010-12-22 20:02:29218// static
219ssize_t UnixDomainSocket::SendRecvMsg(int fd,
220 uint8_t* reply,
221 unsigned max_reply_len,
222 int* result_fd,
223 const Pickle& request) {
[email protected]b0984152013-04-26 00:34:54224 return UnixDomainSocket::SendRecvMsgWithFlags(fd, reply, max_reply_len,
Boris Vidolov8ecb49e2017-07-26 06:35:46225 0, /* recvmsg_flags */
[email protected]b0984152013-04-26 00:34:54226 result_fd, request);
227}
228
229// static
230ssize_t UnixDomainSocket::SendRecvMsgWithFlags(int fd,
231 uint8_t* reply,
232 unsigned max_reply_len,
233 int recvmsg_flags,
234 int* result_fd,
235 const Pickle& request) {
[email protected]43235a02009-06-18 00:44:42236 // This socketpair is only used for the IPC and is cleaned up before
237 // returning.
brettwa027ae32015-06-02 19:48:29238 ScopedFD recv_sock, send_sock;
Peter Kasting134ef9af2024-12-28 02:30:09239 if (!CreateSocketPair(&recv_sock, &send_sock)) {
[email protected]6729422d2012-10-12 05:51:18240 return -1;
Peter Kasting134ef9af2024-12-28 02:30:09241 }
[email protected]43235a02009-06-18 00:44:42242
[email protected]8feaa672014-04-30 21:57:10243 {
244 std::vector<int> send_fds;
245 send_fds.push_back(send_sock.get());
Peter Kasting134ef9af2024-12-28 02:30:09246 if (!SendMsg(fd, request.data(), request.size(), send_fds)) {
[email protected]8feaa672014-04-30 21:57:10247 return -1;
Peter Kasting134ef9af2024-12-28 02:30:09248 }
[email protected]43235a02009-06-18 00:44:42249 }
[email protected]43235a02009-06-18 00:44:42250
[email protected]8feaa672014-04-30 21:57:10251 // Close the sending end of the socket right away so that if our peer closes
252 // it before sending a response (e.g., from exiting), RecvMsgWithFlags() will
253 // return EOF instead of hanging.
254 send_sock.reset();
255
mdempskyf12295a2015-12-09 22:54:46256 std::vector<ScopedFD> recv_fds;
[email protected]1dc3796b2014-04-24 23:42:42257 const ssize_t reply_len = RecvMsgWithFlags(
Ivan Kotenkova16212a52017-11-08 12:37:33258 recv_sock.get(), reply, max_reply_len, recvmsg_flags, &recv_fds, nullptr);
[email protected]8feaa672014-04-30 21:57:10259 recv_sock.reset();
Peter Kasting134ef9af2024-12-28 02:30:09260 if (reply_len == -1) {
[email protected]43235a02009-06-18 00:44:42261 return -1;
Peter Kasting134ef9af2024-12-28 02:30:09262 }
[email protected]43235a02009-06-18 00:44:42263
[email protected]8feaa672014-04-30 21:57:10264 // If we received more file descriptors than caller expected, then we treat
265 // that as an error.
Ivan Kotenkova16212a52017-11-08 12:37:33266 if (recv_fds.size() > (result_fd != nullptr ? 1 : 0)) {
Peter Boströmde573332024-08-26 20:42:45267 NOTREACHED();
[email protected]43235a02009-06-18 00:44:42268 }
269
Peter Kasting134ef9af2024-12-28 02:30:09270 if (result_fd) {
mdempskyf12295a2015-12-09 22:54:46271 *result_fd = recv_fds.empty() ? -1 : recv_fds[0].release();
Peter Kasting134ef9af2024-12-28 02:30:09272 }
[email protected]43235a02009-06-18 00:44:42273
274 return reply_len;
275}
brettwa027ae32015-06-02 19:48:29276
277} // namespace base