xref: /aosp_15_r20/system/libbase/cmsg.cpp (revision 8f0ba417480079999ba552f1087ae592091b9d02)
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