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 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 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 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 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 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 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 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 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 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 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 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 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