1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2013 The FreeBSD Foundation
5 * Copyright (c) 2013 Mariusz Zaborski <oshogbo@FreeBSD.org>
6 * All rights reserved.
7 *
8 * This software was developed by Pawel Jakub Dawidek under sponsorship from
9 * the FreeBSD Foundation.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33 #include <sys/param.h>
34 #include <sys/socket.h>
35 #include <sys/select.h>
36
37 #include <errno.h>
38 #include <fcntl.h>
39 #include <stdbool.h>
40 #include <stdint.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <unistd.h>
44
45 #ifdef HAVE_PJDLOG
46 #include <pjdlog.h>
47 #endif
48
49 #include "common_impl.h"
50 #include "msgio.h"
51
52 #ifndef HAVE_PJDLOG
53 #include <assert.h>
54 #define PJDLOG_ASSERT(...) assert(__VA_ARGS__)
55 #define PJDLOG_RASSERT(expr, ...) assert(expr)
56 #define PJDLOG_ABORT(...) abort()
57 #endif
58
59 #ifdef __linux__
60 /* Linux: arbitrary size, but must be lower than SCM_MAX_FD. */
61 #define PKG_MAX_SIZE ((64U - 1) * CMSG_SPACE(sizeof(int)))
62 #else
63 /*
64 * To work around limitations in 32-bit emulation on 64-bit kernels, use a
65 * machine-independent limit on the number of FDs per message. Each control
66 * message contains 1 FD and requires 12 bytes for the header, 4 pad bytes,
67 * 4 bytes for the descriptor, and another 4 pad bytes.
68 */
69 #define PKG_MAX_SIZE (MCLBYTES / 24)
70 #endif
71
72 static int
msghdr_add_fd(struct cmsghdr * cmsg,int fd)73 msghdr_add_fd(struct cmsghdr *cmsg, int fd)
74 {
75
76 PJDLOG_ASSERT(fd >= 0);
77
78 cmsg->cmsg_level = SOL_SOCKET;
79 cmsg->cmsg_type = SCM_RIGHTS;
80 cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
81 bcopy(&fd, CMSG_DATA(cmsg), sizeof(fd));
82
83 return (0);
84 }
85
86 static void
fd_wait(int fd,bool doread)87 fd_wait(int fd, bool doread)
88 {
89 fd_set fds;
90
91 PJDLOG_ASSERT(fd >= 0);
92
93 FD_ZERO(&fds);
94 FD_SET(fd, &fds);
95 (void)select(fd + 1, doread ? &fds : NULL, doread ? NULL : &fds,
96 NULL, NULL);
97 }
98
99 static int
msg_recv(int sock,struct msghdr * msg)100 msg_recv(int sock, struct msghdr *msg)
101 {
102 int flags;
103
104 PJDLOG_ASSERT(sock >= 0);
105
106 #ifdef MSG_CMSG_CLOEXEC
107 flags = MSG_CMSG_CLOEXEC;
108 #else
109 flags = 0;
110 #endif
111
112 for (;;) {
113 fd_wait(sock, true);
114 if (recvmsg(sock, msg, flags) == -1) {
115 if (errno == EINTR)
116 continue;
117 return (-1);
118 }
119 break;
120 }
121
122 return (0);
123 }
124
125 static int
msg_send(int sock,const struct msghdr * msg)126 msg_send(int sock, const struct msghdr *msg)
127 {
128
129 PJDLOG_ASSERT(sock >= 0);
130
131 for (;;) {
132 fd_wait(sock, false);
133 if (sendmsg(sock, msg, 0) == -1) {
134 if (errno == EINTR)
135 continue;
136 return (-1);
137 }
138 break;
139 }
140
141 return (0);
142 }
143
144 #ifdef __FreeBSD__
145 int
cred_send(int sock)146 cred_send(int sock)
147 {
148 unsigned char credbuf[CMSG_SPACE(sizeof(struct cmsgcred))];
149 struct msghdr msg;
150 struct cmsghdr *cmsg;
151 struct iovec iov;
152 uint8_t dummy;
153
154 bzero(credbuf, sizeof(credbuf));
155 bzero(&msg, sizeof(msg));
156 bzero(&iov, sizeof(iov));
157
158 /*
159 * XXX: We send one byte along with the control message, because
160 * setting msg_iov to NULL only works if this is the first
161 * packet send over the socket. Once we send some data we
162 * won't be able to send credentials anymore. This is most
163 * likely a kernel bug.
164 */
165 dummy = 0;
166 iov.iov_base = &dummy;
167 iov.iov_len = sizeof(dummy);
168
169 msg.msg_iov = &iov;
170 msg.msg_iovlen = 1;
171 msg.msg_control = credbuf;
172 msg.msg_controllen = sizeof(credbuf);
173
174 cmsg = CMSG_FIRSTHDR(&msg);
175 cmsg->cmsg_len = CMSG_LEN(sizeof(struct cmsgcred));
176 cmsg->cmsg_level = SOL_SOCKET;
177 cmsg->cmsg_type = SCM_CREDS;
178
179 if (msg_send(sock, &msg) == -1)
180 return (-1);
181
182 return (0);
183 }
184
185 int
cred_recv(int sock,struct cmsgcred * cred)186 cred_recv(int sock, struct cmsgcred *cred)
187 {
188 unsigned char credbuf[CMSG_SPACE(sizeof(struct cmsgcred))];
189 struct msghdr msg;
190 struct cmsghdr *cmsg;
191 struct iovec iov;
192 uint8_t dummy;
193
194 bzero(credbuf, sizeof(credbuf));
195 bzero(&msg, sizeof(msg));
196 bzero(&iov, sizeof(iov));
197
198 iov.iov_base = &dummy;
199 iov.iov_len = sizeof(dummy);
200
201 msg.msg_iov = &iov;
202 msg.msg_iovlen = 1;
203 msg.msg_control = credbuf;
204 msg.msg_controllen = sizeof(credbuf);
205
206 if (msg_recv(sock, &msg) == -1)
207 return (-1);
208
209 cmsg = CMSG_FIRSTHDR(&msg);
210 if (cmsg == NULL ||
211 cmsg->cmsg_len != CMSG_LEN(sizeof(struct cmsgcred)) ||
212 cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_CREDS) {
213 errno = EINVAL;
214 return (-1);
215 }
216 bcopy(CMSG_DATA(cmsg), cred, sizeof(*cred));
217
218 return (0);
219 }
220 #endif
221
222 static int
fd_package_send(int sock,const int * fds,size_t nfds)223 fd_package_send(int sock, const int *fds, size_t nfds)
224 {
225 struct msghdr msg;
226 struct cmsghdr *cmsg;
227 struct iovec iov;
228 unsigned int i;
229 int serrno, ret;
230 uint8_t dummy;
231
232 PJDLOG_ASSERT(sock >= 0);
233 PJDLOG_ASSERT(fds != NULL);
234 PJDLOG_ASSERT(nfds > 0);
235
236 bzero(&msg, sizeof(msg));
237
238 /*
239 * XXX: Look into cred_send function for more details.
240 */
241 dummy = 0;
242 iov.iov_base = &dummy;
243 iov.iov_len = sizeof(dummy);
244
245 msg.msg_iov = &iov;
246 msg.msg_iovlen = 1;
247 msg.msg_controllen = nfds * CMSG_SPACE(sizeof(int));
248 msg.msg_control = calloc(1, msg.msg_controllen);
249 if (msg.msg_control == NULL)
250 return (-1);
251
252 ret = -1;
253
254 for (i = 0, cmsg = CMSG_FIRSTHDR(&msg); i < nfds && cmsg != NULL;
255 i++, cmsg = CMSG_NXTHDR(&msg, cmsg)) {
256 if (msghdr_add_fd(cmsg, fds[i]) == -1)
257 goto end;
258 }
259
260 if (msg_send(sock, &msg) == -1)
261 goto end;
262
263 ret = 0;
264 end:
265 serrno = errno;
266 free(msg.msg_control);
267 errno = serrno;
268 return (ret);
269 }
270
271 static int
fd_package_recv(int sock,int * fds,size_t nfds)272 fd_package_recv(int sock, int *fds, size_t nfds)
273 {
274 struct msghdr msg;
275 struct cmsghdr *cmsg;
276 unsigned int i;
277 int serrno, ret;
278 struct iovec iov;
279 uint8_t dummy;
280
281 PJDLOG_ASSERT(sock >= 0);
282 PJDLOG_ASSERT(nfds > 0);
283 PJDLOG_ASSERT(fds != NULL);
284
285 bzero(&msg, sizeof(msg));
286 bzero(&iov, sizeof(iov));
287
288 /*
289 * XXX: Look into cred_send function for more details.
290 */
291 iov.iov_base = &dummy;
292 iov.iov_len = sizeof(dummy);
293
294 msg.msg_iov = &iov;
295 msg.msg_iovlen = 1;
296 msg.msg_controllen = nfds * CMSG_SPACE(sizeof(int));
297 msg.msg_control = calloc(1, msg.msg_controllen);
298 if (msg.msg_control == NULL)
299 return (-1);
300
301 ret = -1;
302
303 if (msg_recv(sock, &msg) == -1)
304 goto end;
305
306 i = 0;
307 cmsg = CMSG_FIRSTHDR(&msg);
308 while (cmsg && i < nfds) {
309 unsigned int n;
310
311 if (cmsg->cmsg_level != SOL_SOCKET ||
312 cmsg->cmsg_type != SCM_RIGHTS) {
313 errno = EINVAL;
314 break;
315 }
316 n = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
317 if (i + n > nfds) {
318 errno = EINVAL;
319 break;
320 }
321 bcopy(CMSG_DATA(cmsg), fds + i, sizeof(int) * n);
322 cmsg = CMSG_NXTHDR(&msg, cmsg);
323 i += n;
324 }
325
326 if (cmsg != NULL || i < nfds) {
327 unsigned int last;
328
329 /*
330 * We need to close all received descriptors, even if we have
331 * different control message (eg. SCM_CREDS) in between.
332 */
333 last = i;
334 for (i = 0; i < last; i++) {
335 if (fds[i] >= 0) {
336 close(fds[i]);
337 }
338 }
339 errno = EINVAL;
340 goto end;
341 }
342
343 #ifndef MSG_CMSG_CLOEXEC
344 /*
345 * If the MSG_CMSG_CLOEXEC flag is not available we cannot set the
346 * close-on-exec flag atomically, but we still want to set it for
347 * consistency.
348 */
349 for (i = 0; i < nfds; i++) {
350 (void) fcntl(fds[i], F_SETFD, FD_CLOEXEC);
351 }
352 #endif
353
354 ret = 0;
355 end:
356 serrno = errno;
357 free(msg.msg_control);
358 errno = serrno;
359 return (ret);
360 }
361
362 int
fd_recv(int sock,int * fds,size_t nfds)363 fd_recv(int sock, int *fds, size_t nfds)
364 {
365 unsigned int i, step, j;
366 int ret, serrno;
367
368 if (nfds == 0 || fds == NULL) {
369 errno = EINVAL;
370 return (-1);
371 }
372
373 ret = i = step = 0;
374 while (i < nfds) {
375 if (PKG_MAX_SIZE < nfds - i)
376 step = PKG_MAX_SIZE;
377 else
378 step = nfds - i;
379 ret = fd_package_recv(sock, fds + i, step);
380 if (ret != 0) {
381 /* Close all received descriptors. */
382 serrno = errno;
383 for (j = 0; j < i; j++)
384 close(fds[j]);
385 errno = serrno;
386 break;
387 }
388 i += step;
389 }
390
391 return (ret);
392 }
393
394 int
fd_send(int sock,const int * fds,size_t nfds)395 fd_send(int sock, const int *fds, size_t nfds)
396 {
397 unsigned int i, step;
398 int ret;
399
400 if (nfds == 0 || fds == NULL) {
401 errno = EINVAL;
402 return (-1);
403 }
404
405 ret = i = step = 0;
406 while (i < nfds) {
407 if (PKG_MAX_SIZE < nfds - i)
408 step = PKG_MAX_SIZE;
409 else
410 step = nfds - i;
411 ret = fd_package_send(sock, fds + i, step);
412 if (ret != 0)
413 break;
414 i += step;
415 }
416
417 return (ret);
418 }
419
420 int
buf_send(int sock,void * buf,size_t size)421 buf_send(int sock, void *buf, size_t size)
422 {
423 ssize_t done;
424 unsigned char *ptr;
425
426 PJDLOG_ASSERT(sock >= 0);
427 PJDLOG_ASSERT(size > 0);
428 PJDLOG_ASSERT(buf != NULL);
429
430 ptr = buf;
431 do {
432 fd_wait(sock, false);
433 done = send(sock, ptr, size, 0);
434 if (done == -1) {
435 if (errno == EINTR)
436 continue;
437 return (-1);
438 } else if (done == 0) {
439 errno = ENOTCONN;
440 return (-1);
441 }
442 size -= done;
443 ptr += done;
444 } while (size > 0);
445
446 return (0);
447 }
448
449 int
buf_recv(int sock,void * buf,size_t size,int flags)450 buf_recv(int sock, void *buf, size_t size, int flags)
451 {
452 ssize_t done;
453 unsigned char *ptr;
454
455 PJDLOG_ASSERT(sock >= 0);
456 PJDLOG_ASSERT(buf != NULL);
457
458 ptr = buf;
459 while (size > 0) {
460 fd_wait(sock, true);
461 done = recv(sock, ptr, size, flags);
462 if (done == -1) {
463 if (errno == EINTR)
464 continue;
465 return (-1);
466 } else if (done == 0) {
467 errno = ENOTCONN;
468 return (-1);
469 }
470 size -= done;
471 ptr += done;
472 }
473
474 return (0);
475 }
476