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