1*8f0ba417SAndroid Build Coastguard Worker /*
2*8f0ba417SAndroid Build Coastguard Worker * Copyright (C) 2019 The Android Open Source Project
3*8f0ba417SAndroid Build Coastguard Worker *
4*8f0ba417SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*8f0ba417SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*8f0ba417SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*8f0ba417SAndroid Build Coastguard Worker *
8*8f0ba417SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*8f0ba417SAndroid Build Coastguard Worker *
10*8f0ba417SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*8f0ba417SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*8f0ba417SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*8f0ba417SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*8f0ba417SAndroid Build Coastguard Worker * limitations under the License.
15*8f0ba417SAndroid Build Coastguard Worker */
16*8f0ba417SAndroid Build Coastguard Worker
17*8f0ba417SAndroid Build Coastguard Worker #include <android-base/cmsg.h>
18*8f0ba417SAndroid Build Coastguard Worker
19*8f0ba417SAndroid Build Coastguard Worker #include <errno.h>
20*8f0ba417SAndroid Build Coastguard Worker #include <fcntl.h>
21*8f0ba417SAndroid Build Coastguard Worker #include <stdlib.h>
22*8f0ba417SAndroid Build Coastguard Worker #include <sys/socket.h>
23*8f0ba417SAndroid Build Coastguard Worker #include <sys/user.h>
24*8f0ba417SAndroid Build Coastguard Worker
25*8f0ba417SAndroid Build Coastguard Worker #include <memory>
26*8f0ba417SAndroid Build Coastguard Worker
27*8f0ba417SAndroid Build Coastguard Worker #include <android-base/logging.h>
28*8f0ba417SAndroid Build Coastguard Worker
29*8f0ba417SAndroid Build Coastguard Worker namespace android {
30*8f0ba417SAndroid Build Coastguard Worker namespace base {
31*8f0ba417SAndroid Build Coastguard Worker
SendFileDescriptorVector(borrowed_fd sockfd,const void * data,size_t len,const std::vector<int> & fds)32*8f0ba417SAndroid Build Coastguard Worker ssize_t SendFileDescriptorVector(borrowed_fd sockfd, const void* data, size_t len,
33*8f0ba417SAndroid Build Coastguard Worker const std::vector<int>& fds) {
34*8f0ba417SAndroid Build Coastguard Worker static const size_t page_size = sysconf(_SC_PAGE_SIZE);
35*8f0ba417SAndroid Build Coastguard Worker size_t cmsg_space = CMSG_SPACE(sizeof(int) * fds.size());
36*8f0ba417SAndroid Build Coastguard Worker size_t cmsg_len = CMSG_LEN(sizeof(int) * fds.size());
37*8f0ba417SAndroid Build Coastguard Worker if (cmsg_space >= page_size) {
38*8f0ba417SAndroid Build Coastguard Worker errno = ENOMEM;
39*8f0ba417SAndroid Build Coastguard Worker return -1;
40*8f0ba417SAndroid Build Coastguard Worker }
41*8f0ba417SAndroid Build Coastguard Worker
42*8f0ba417SAndroid Build Coastguard Worker alignas(struct cmsghdr) char cmsg_buf[cmsg_space];
43*8f0ba417SAndroid Build Coastguard Worker iovec iov = {.iov_base = const_cast<void*>(data), .iov_len = len};
44*8f0ba417SAndroid Build Coastguard Worker msghdr msg = {
45*8f0ba417SAndroid Build Coastguard Worker .msg_name = nullptr,
46*8f0ba417SAndroid Build Coastguard Worker .msg_namelen = 0,
47*8f0ba417SAndroid Build Coastguard Worker .msg_iov = &iov,
48*8f0ba417SAndroid Build Coastguard Worker .msg_iovlen = 1,
49*8f0ba417SAndroid Build Coastguard Worker .msg_control = cmsg_buf,
50*8f0ba417SAndroid Build Coastguard Worker // We can't cast to the actual type of the field, because it's different across platforms.
51*8f0ba417SAndroid Build Coastguard Worker .msg_controllen = static_cast<unsigned int>(cmsg_space),
52*8f0ba417SAndroid Build Coastguard Worker .msg_flags = 0,
53*8f0ba417SAndroid Build Coastguard Worker };
54*8f0ba417SAndroid Build Coastguard Worker
55*8f0ba417SAndroid Build Coastguard Worker struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
56*8f0ba417SAndroid Build Coastguard Worker cmsg->cmsg_level = SOL_SOCKET;
57*8f0ba417SAndroid Build Coastguard Worker cmsg->cmsg_type = SCM_RIGHTS;
58*8f0ba417SAndroid Build Coastguard Worker cmsg->cmsg_len = cmsg_len;
59*8f0ba417SAndroid Build Coastguard Worker
60*8f0ba417SAndroid Build Coastguard Worker int* cmsg_fds = reinterpret_cast<int*>(CMSG_DATA(cmsg));
61*8f0ba417SAndroid Build Coastguard Worker for (size_t i = 0; i < fds.size(); ++i) {
62*8f0ba417SAndroid Build Coastguard Worker cmsg_fds[i] = fds[i];
63*8f0ba417SAndroid Build Coastguard Worker }
64*8f0ba417SAndroid Build Coastguard Worker
65*8f0ba417SAndroid Build Coastguard Worker #if defined(__linux__)
66*8f0ba417SAndroid Build Coastguard Worker int flags = MSG_NOSIGNAL;
67*8f0ba417SAndroid Build Coastguard Worker #else
68*8f0ba417SAndroid Build Coastguard Worker int flags = 0;
69*8f0ba417SAndroid Build Coastguard Worker #endif
70*8f0ba417SAndroid Build Coastguard Worker
71*8f0ba417SAndroid Build Coastguard Worker return TEMP_FAILURE_RETRY(sendmsg(sockfd.get(), &msg, flags));
72*8f0ba417SAndroid Build Coastguard Worker }
73*8f0ba417SAndroid Build Coastguard Worker
ReceiveFileDescriptorVector(borrowed_fd sockfd,void * data,size_t len,size_t max_fds,std::vector<unique_fd> * fds)74*8f0ba417SAndroid Build Coastguard Worker ssize_t ReceiveFileDescriptorVector(borrowed_fd sockfd, void* data, size_t len, size_t max_fds,
75*8f0ba417SAndroid Build Coastguard Worker std::vector<unique_fd>* fds) {
76*8f0ba417SAndroid Build Coastguard Worker fds->clear();
77*8f0ba417SAndroid Build Coastguard Worker
78*8f0ba417SAndroid Build Coastguard Worker static const size_t page_size = sysconf(_SC_PAGE_SIZE);
79*8f0ba417SAndroid Build Coastguard Worker size_t cmsg_space = CMSG_SPACE(sizeof(int) * max_fds);
80*8f0ba417SAndroid Build Coastguard Worker if (cmsg_space >= page_size) {
81*8f0ba417SAndroid Build Coastguard Worker errno = ENOMEM;
82*8f0ba417SAndroid Build Coastguard Worker return -1;
83*8f0ba417SAndroid Build Coastguard Worker }
84*8f0ba417SAndroid Build Coastguard Worker
85*8f0ba417SAndroid Build Coastguard Worker alignas(struct cmsghdr) char cmsg_buf[cmsg_space];
86*8f0ba417SAndroid Build Coastguard Worker iovec iov = {.iov_base = data, .iov_len = len};
87*8f0ba417SAndroid Build Coastguard Worker msghdr msg = {
88*8f0ba417SAndroid Build Coastguard Worker .msg_name = nullptr,
89*8f0ba417SAndroid Build Coastguard Worker .msg_namelen = 0,
90*8f0ba417SAndroid Build Coastguard Worker .msg_iov = &iov,
91*8f0ba417SAndroid Build Coastguard Worker .msg_iovlen = 1,
92*8f0ba417SAndroid Build Coastguard Worker .msg_control = cmsg_buf,
93*8f0ba417SAndroid Build Coastguard Worker // We can't cast to the actual type of the field, because it's different across platforms.
94*8f0ba417SAndroid Build Coastguard Worker .msg_controllen = static_cast<unsigned int>(cmsg_space),
95*8f0ba417SAndroid Build Coastguard Worker .msg_flags = 0,
96*8f0ba417SAndroid Build Coastguard Worker };
97*8f0ba417SAndroid Build Coastguard Worker
98*8f0ba417SAndroid Build Coastguard Worker int flags = MSG_TRUNC | MSG_CTRUNC;
99*8f0ba417SAndroid Build Coastguard Worker #if defined(__linux__)
100*8f0ba417SAndroid Build Coastguard Worker flags |= MSG_CMSG_CLOEXEC | MSG_NOSIGNAL;
101*8f0ba417SAndroid Build Coastguard Worker #endif
102*8f0ba417SAndroid Build Coastguard Worker
103*8f0ba417SAndroid Build Coastguard Worker ssize_t rc = TEMP_FAILURE_RETRY(recvmsg(sockfd.get(), &msg, flags));
104*8f0ba417SAndroid Build Coastguard Worker
105*8f0ba417SAndroid Build Coastguard Worker if (rc == -1) {
106*8f0ba417SAndroid Build Coastguard Worker return -1;
107*8f0ba417SAndroid Build Coastguard Worker }
108*8f0ba417SAndroid Build Coastguard Worker
109*8f0ba417SAndroid Build Coastguard Worker int error = 0;
110*8f0ba417SAndroid Build Coastguard Worker if ((msg.msg_flags & MSG_TRUNC)) {
111*8f0ba417SAndroid Build Coastguard Worker LOG(ERROR) << "message was truncated when receiving file descriptors";
112*8f0ba417SAndroid Build Coastguard Worker error = EMSGSIZE;
113*8f0ba417SAndroid Build Coastguard Worker } else if ((msg.msg_flags & MSG_CTRUNC)) {
114*8f0ba417SAndroid Build Coastguard Worker LOG(ERROR) << "control message was truncated when receiving file descriptors";
115*8f0ba417SAndroid Build Coastguard Worker error = EMSGSIZE;
116*8f0ba417SAndroid Build Coastguard Worker }
117*8f0ba417SAndroid Build Coastguard Worker
118*8f0ba417SAndroid Build Coastguard Worker std::vector<unique_fd> received_fds;
119*8f0ba417SAndroid Build Coastguard Worker struct cmsghdr* cmsg;
120*8f0ba417SAndroid Build Coastguard Worker for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != nullptr; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
121*8f0ba417SAndroid Build Coastguard Worker if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
122*8f0ba417SAndroid Build Coastguard Worker LOG(ERROR) << "received unexpected cmsg: [" << cmsg->cmsg_level << ", " << cmsg->cmsg_type
123*8f0ba417SAndroid Build Coastguard Worker << "]";
124*8f0ba417SAndroid Build Coastguard Worker error = EBADMSG;
125*8f0ba417SAndroid Build Coastguard Worker continue;
126*8f0ba417SAndroid Build Coastguard Worker }
127*8f0ba417SAndroid Build Coastguard Worker
128*8f0ba417SAndroid Build Coastguard Worker // There isn't a macro that does the inverse of CMSG_LEN, so hack around it ourselves, with
129*8f0ba417SAndroid Build Coastguard Worker // some asserts to ensure that CMSG_LEN behaves as we expect.
130*8f0ba417SAndroid Build Coastguard Worker #if defined(__linux__)
131*8f0ba417SAndroid Build Coastguard Worker #define CMSG_ASSERT static_assert
132*8f0ba417SAndroid Build Coastguard Worker #else
133*8f0ba417SAndroid Build Coastguard Worker // CMSG_LEN is somehow not constexpr on darwin.
134*8f0ba417SAndroid Build Coastguard Worker #define CMSG_ASSERT CHECK
135*8f0ba417SAndroid Build Coastguard Worker #endif
136*8f0ba417SAndroid Build Coastguard Worker CMSG_ASSERT(CMSG_LEN(0) + 1 * sizeof(int) == CMSG_LEN(1 * sizeof(int)));
137*8f0ba417SAndroid Build Coastguard Worker CMSG_ASSERT(CMSG_LEN(0) + 2 * sizeof(int) == CMSG_LEN(2 * sizeof(int)));
138*8f0ba417SAndroid Build Coastguard Worker CMSG_ASSERT(CMSG_LEN(0) + 3 * sizeof(int) == CMSG_LEN(3 * sizeof(int)));
139*8f0ba417SAndroid Build Coastguard Worker CMSG_ASSERT(CMSG_LEN(0) + 4 * sizeof(int) == CMSG_LEN(4 * sizeof(int)));
140*8f0ba417SAndroid Build Coastguard Worker
141*8f0ba417SAndroid Build Coastguard Worker if (cmsg->cmsg_len % sizeof(int) != 0) {
142*8f0ba417SAndroid Build Coastguard Worker LOG(FATAL) << "cmsg_len(" << cmsg->cmsg_len << ") not aligned to sizeof(int)";
143*8f0ba417SAndroid Build Coastguard Worker } else if (cmsg->cmsg_len <= CMSG_LEN(0)) {
144*8f0ba417SAndroid Build Coastguard Worker LOG(FATAL) << "cmsg_len(" << cmsg->cmsg_len << ") not long enough to hold any data";
145*8f0ba417SAndroid Build Coastguard Worker }
146*8f0ba417SAndroid Build Coastguard Worker
147*8f0ba417SAndroid Build Coastguard Worker int* cmsg_fds = reinterpret_cast<int*>(CMSG_DATA(cmsg));
148*8f0ba417SAndroid Build Coastguard Worker size_t cmsg_fdcount = static_cast<size_t>(cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
149*8f0ba417SAndroid Build Coastguard Worker for (size_t i = 0; i < cmsg_fdcount; ++i) {
150*8f0ba417SAndroid Build Coastguard Worker #if !defined(__linux__)
151*8f0ba417SAndroid Build Coastguard Worker // Linux uses MSG_CMSG_CLOEXEC instead of doing this manually.
152*8f0ba417SAndroid Build Coastguard Worker fcntl(cmsg_fds[i], F_SETFD, FD_CLOEXEC);
153*8f0ba417SAndroid Build Coastguard Worker #endif
154*8f0ba417SAndroid Build Coastguard Worker received_fds.emplace_back(cmsg_fds[i]);
155*8f0ba417SAndroid Build Coastguard Worker }
156*8f0ba417SAndroid Build Coastguard Worker }
157*8f0ba417SAndroid Build Coastguard Worker
158*8f0ba417SAndroid Build Coastguard Worker if (error != 0) {
159*8f0ba417SAndroid Build Coastguard Worker errno = error;
160*8f0ba417SAndroid Build Coastguard Worker return -1;
161*8f0ba417SAndroid Build Coastguard Worker }
162*8f0ba417SAndroid Build Coastguard Worker
163*8f0ba417SAndroid Build Coastguard Worker if (received_fds.size() > max_fds) {
164*8f0ba417SAndroid Build Coastguard Worker LOG(ERROR) << "received too many file descriptors, expected " << fds->size() << ", received "
165*8f0ba417SAndroid Build Coastguard Worker << received_fds.size();
166*8f0ba417SAndroid Build Coastguard Worker errno = EMSGSIZE;
167*8f0ba417SAndroid Build Coastguard Worker return -1;
168*8f0ba417SAndroid Build Coastguard Worker }
169*8f0ba417SAndroid Build Coastguard Worker
170*8f0ba417SAndroid Build Coastguard Worker *fds = std::move(received_fds);
171*8f0ba417SAndroid Build Coastguard Worker return rc;
172*8f0ba417SAndroid Build Coastguard Worker }
173*8f0ba417SAndroid Build Coastguard Worker
174*8f0ba417SAndroid Build Coastguard Worker } // namespace base
175*8f0ba417SAndroid Build Coastguard Worker } // namespace android
176