1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (c) 2001 Wayne Boyer International Business Machines 4 * Copyright (c) Linux Test Project, 2002-2022 5 * Copyright (c) 2023 Wei Gao <wegao@suse.com> 6 */ 7 8/*\ 9 * [Description] 10 * 11 * Verify that recvmsg() returns the proper errno for various failure cases. 12 */ 13 14#include <stdio.h> 15#include <stdlib.h> 16#include <sys/wait.h> 17#include "tst_test.h" 18 19#define MSG "from recvmsg01 server" 20#define BUF_SIZE 1024 21#define CONTROL_LEN (128 * 1024) 22 23static char recv_buf[BUF_SIZE], cbuf[BUF_SIZE]; 24static int sock; 25static struct sockaddr_in sin1, from; 26static struct sockaddr_un sun1; 27static struct msghdr msgdat; 28static struct cmsghdr *control; 29static int controllen; 30static struct iovec iov[1]; 31static int sfd; /* shared between do_child and start_server */ 32static int ufd; /* shared between do_child and start_server */ 33static pid_t pid; 34static char tmpsunpath[BUF_SIZE]; 35 36static void setup_all(void); 37static void setup_invalid_sock(int); 38static void setup_valid_sock(int); 39static void setup_valid_msg_control(int); 40static void setup_large_msg_control(int); 41static void cleanup_all(void); 42static void cleanup_invalid_sock(int); 43static void cleanup_close_sock(int); 44static void cleanup_reset_all(int); 45static void do_child(void); 46static pid_t start_server(struct sockaddr_in *, struct sockaddr_un *); 47 48static struct tcase { 49 int domain; 50 int type; 51 int protocol; 52 struct iovec *iov; 53 int iovcnt; 54 void *recv_buf; 55 int buflen; 56 struct msghdr *msg; 57 unsigned int flags; 58 struct sockaddr *from; 59 int fromlen; 60 int exp_errno; 61 void (*setup)(int n); 62 void (*cleanup)(int n); 63 char *desc; 64} tcases[] = { 65 { 66 .domain = PF_INET, 67 .type = SOCK_STREAM, 68 .iov = iov, 69 .iovcnt = 1, 70 .recv_buf = recv_buf, 71 .buflen = sizeof(recv_buf), 72 .msg = &msgdat, 73 .from = (struct sockaddr *)&from, 74 .fromlen = sizeof(from), 75 .exp_errno = EBADF, 76 .setup = setup_invalid_sock, 77 .cleanup = cleanup_invalid_sock, 78 .desc = "bad file descriptor", 79 }, 80 { 81 .domain = PF_INET, 82 .type = SOCK_STREAM, 83 .iov = iov, 84 .iovcnt = 1, 85 .recv_buf = (void *)recv_buf, 86 .buflen = sizeof(recv_buf), 87 .msg = &msgdat, 88 .from = (struct sockaddr *)&from, 89 .fromlen = sizeof(from), 90 .exp_errno = ENOTSOCK, 91 .setup = setup_invalid_sock, 92 .cleanup = cleanup_invalid_sock, 93 .desc = "invalid socket", 94 }, 95 { 96 .domain = PF_INET, 97 .type = SOCK_STREAM, 98 .iov = iov, 99 .iovcnt = 1, 100 .recv_buf = (void *)recv_buf, 101 .buflen = sizeof(recv_buf), 102 .msg = &msgdat, 103 .flags = -1, 104 .from = (struct sockaddr *)&from, 105 .fromlen = -1, 106 .exp_errno = EINVAL, 107 .setup = setup_valid_sock, 108 .cleanup = cleanup_close_sock, 109 .desc = "invalid socket length", 110 }, 111 { 112 .domain = PF_INET, 113 .type = SOCK_STREAM, 114 .iov = iov, 115 .iovcnt = 1, 116 .recv_buf = (void *)-1, 117 .buflen = sizeof(recv_buf), 118 .msg = &msgdat, 119 .from = (struct sockaddr *)&from, 120 .fromlen = sizeof(from), 121 .exp_errno = EFAULT, 122 .setup = setup_valid_sock, 123 .cleanup = cleanup_close_sock, 124 .desc = "invalid recv buffer", 125 }, 126 { 127 .domain = PF_INET, 128 .type = SOCK_STREAM, 129 .iovcnt = 1, 130 .recv_buf = recv_buf, 131 .buflen = sizeof(recv_buf), 132 .msg = &msgdat, 133 .from = (struct sockaddr *)&from, 134 .fromlen = sizeof(from), 135 .exp_errno = EFAULT, 136 .setup = setup_valid_sock, 137 .cleanup = cleanup_close_sock, 138 .desc = "invalid iovec buffer", 139 }, 140 { 141 .domain = PF_INET, 142 .type = SOCK_STREAM, 143 .iov = iov, 144 .iovcnt = -1, 145 .recv_buf = recv_buf, 146 .buflen = sizeof(recv_buf), 147 .msg = &msgdat, 148 .from = (struct sockaddr *)&from, 149 .fromlen = sizeof(from), 150 .exp_errno = EMSGSIZE, 151 .setup = setup_valid_sock, 152 .cleanup = cleanup_close_sock, 153 .desc = "invalid iovec count", 154 }, 155 { 156 .domain = PF_INET, 157 .type = SOCK_STREAM, 158 .iov = iov, 159 .iovcnt = 1, 160 .recv_buf = recv_buf, 161 .buflen = sizeof(recv_buf), 162 .msg = &msgdat, 163 .from = (struct sockaddr *)&from, 164 .fromlen = sizeof(from), 165 .setup = setup_valid_msg_control, 166 .cleanup = cleanup_reset_all, 167 .desc = "permission reception", 168 }, 169 { 170 .domain = PF_INET, 171 .type = SOCK_STREAM, 172 .iov = iov, 173 .iovcnt = 1, 174 .recv_buf = recv_buf, 175 .buflen = sizeof(recv_buf), 176 .msg = &msgdat, 177 .flags = MSG_OOB, 178 .from = (struct sockaddr *)&from, 179 .fromlen = sizeof(from), 180 .exp_errno = EINVAL, 181 .setup = setup_valid_sock, 182 .cleanup = cleanup_close_sock, 183 .desc = "invalid MSG_OOB flag set", 184 }, 185 { 186 .domain = PF_INET, 187 .type = SOCK_STREAM, 188 .iov = iov, 189 .iovcnt = 1, 190 .recv_buf = recv_buf, 191 .buflen = sizeof(recv_buf), 192 .msg = &msgdat, 193 .flags = MSG_ERRQUEUE, 194 .from = (struct sockaddr *)&from, 195 .fromlen = sizeof(from), 196 .exp_errno = EAGAIN, 197 .setup = setup_valid_sock, 198 .cleanup = cleanup_close_sock, 199 .desc = "invalid MSG_ERRQUEUE flag set", 200 }, 201 { 202 .domain = PF_INET, 203 .type = SOCK_STREAM, 204 .iov = iov, 205 .iovcnt = 1, 206 .recv_buf = recv_buf, 207 .buflen = sizeof(recv_buf), 208 .msg = &msgdat, 209 .from = (struct sockaddr *)&from, 210 .fromlen = sizeof(from), 211 .setup = setup_large_msg_control, 212 .cleanup = cleanup_reset_all, 213 .desc = "large cmesg length", 214 }, 215 216}; 217 218static void run(unsigned int n) 219{ 220 struct tcase *tc = &tcases[n]; 221 int ret = tc->exp_errno ? -1 : 0; 222 223 if ((tst_kvercmp(3, 17, 0) < 0) 224 && (tc->flags & MSG_ERRQUEUE) 225 && (tc->type & SOCK_STREAM)) { 226 tst_res(TCONF, "MSG_ERRQUEUE requires kernel >= 3.17"); 227 return; 228 } 229 230 setup_all(); 231 tc->setup(n); 232 233 iov[0].iov_base = tc->recv_buf; 234 iov[0].iov_len = tc->buflen; 235 msgdat.msg_name = tc->from; 236 msgdat.msg_namelen = tc->fromlen; 237 msgdat.msg_iov = tc->iov; 238 msgdat.msg_iovlen = tc->iovcnt; 239 msgdat.msg_control = control; 240 msgdat.msg_controllen = controllen; 241 msgdat.msg_flags = 0; 242 243 TEST(recvmsg(sock, tc->msg, tc->flags)); 244 if (TST_RET >= 0) 245 TST_RET = 0; 246 247 if (TST_RET != ret) { 248 tst_res(TFAIL | TTERRNO, "%s: expected %d, returned %ld", 249 tc->desc, ret, TST_RET); 250 } else if (TST_ERR != tc->exp_errno) { 251 tst_res(TFAIL | TTERRNO, 252 "%s: expected %s", 253 tc->desc, tst_strerrno(tc->exp_errno)); 254 } else { 255 tst_res(TPASS, "%s passed", tc->desc); 256 } 257 258 tc->cleanup(n); 259 cleanup_all(); 260} 261 262 263static void setup_all(void) 264{ 265 int tfd; 266 267 sun1.sun_family = AF_UNIX; 268 269 (void)strcpy(tmpsunpath, "udsockXXXXXX"); 270 tfd = mkstemp(tmpsunpath); 271 SAFE_CLOSE(tfd); 272 SAFE_UNLINK(tmpsunpath); 273 (void)strcpy(sun1.sun_path, tmpsunpath); 274 SAFE_SIGNAL(SIGPIPE, SIG_IGN); 275 pid = start_server(&sin1, &sun1); 276} 277 278static void cleanup_all(void) 279{ 280 if (pid > 0) { 281 (void)kill(pid, SIGKILL); /* kill server */ 282 wait(NULL); 283 } 284 285 if (tmpsunpath[0] != '\0') 286 (void)SAFE_UNLINK(tmpsunpath); 287} 288 289static void setup_invalid_sock(int n) 290{ 291 if (tcases[n].exp_errno == EBADF) 292 sock = 400; /* anything not an open file */ 293 else 294 sock = SAFE_OPEN("/dev/null", O_WRONLY); 295} 296 297static void cleanup_invalid_sock(int n) 298{ 299 if (tcases[n].exp_errno == EBADF) 300 sock = -1; 301 else 302 SAFE_CLOSE(sock); 303} 304 305static void setup_valid_sock(int n) 306{ 307 fd_set rdfds; 308 struct timeval timeout; 309 310 sock = SAFE_SOCKET(tcases[n].domain, tcases[n].type, tcases[n].protocol); 311 312 if (tcases[n].type == SOCK_STREAM) { 313 if (tcases[n].domain == PF_INET) { 314 SAFE_CONNECT(sock, (struct sockaddr *)&sin1, sizeof(sin1)); 315 /* Wait for something to be readable, else we won't detect EFAULT on recv */ 316 FD_ZERO(&rdfds); 317 FD_SET(sock, &rdfds); 318 timeout.tv_sec = 2; 319 timeout.tv_usec = 0; 320 n = select(sock + 1, &rdfds, 0, 0, &timeout); 321 322 if (n != 1 || !FD_ISSET(sock, &rdfds)) 323 tst_brk(TBROK, "no message ready in %d sec", (int)timeout.tv_sec); 324 325 } else if (tcases[n].domain == PF_UNIX) { 326 SAFE_CONNECT(sock, (struct sockaddr *)&sun1, sizeof(sun1)); 327 } 328 } 329} 330 331static void setup_valid_msg_control(int n) 332{ 333 setup_valid_sock(n); 334 SAFE_SEND(1, sock, "R", 1, 0); 335 control = (struct cmsghdr *)cbuf; 336 controllen = control->cmsg_len = sizeof(cbuf); 337} 338 339static void setup_large_msg_control(int n) 340{ 341 setup_valid_msg_control(n); 342 controllen = CONTROL_LEN; 343} 344 345static void cleanup_close_sock(int n LTP_ATTRIBUTE_UNUSED) 346{ 347 SAFE_CLOSE(sock); 348} 349 350static void cleanup_reset_all(int n LTP_ATTRIBUTE_UNUSED) 351{ 352 SAFE_CLOSE(sock); 353 354 control = 0; 355 controllen = 0; 356} 357 358pid_t start_server(struct sockaddr_in *ssin, struct sockaddr_un *ssun) 359{ 360 pid_t pid; 361 socklen_t slen = sizeof(*ssin); 362 363 ssin->sin_family = AF_INET; 364 ssin->sin_port = 0; /* pick random free port */ 365 ssin->sin_addr.s_addr = INADDR_ANY; 366 367 /* set up inet socket */ 368 sfd = SAFE_SOCKET(PF_INET, SOCK_STREAM, 0); 369 SAFE_BIND(sfd, (struct sockaddr *)ssin, sizeof(*ssin)); 370 SAFE_LISTEN(sfd, 10); 371 SAFE_GETSOCKNAME(sfd, (struct sockaddr *)ssin, &slen); 372 373 /* set up UNIX-domain socket */ 374 ufd = SAFE_SOCKET(PF_UNIX, SOCK_STREAM, 0); 375 SAFE_BIND(ufd, (struct sockaddr *)ssun, sizeof(*ssun)); 376 SAFE_LISTEN(ufd, 10); 377 378 pid = SAFE_FORK(); 379 if (!pid) { 380 do_child(); 381 exit(1); 382 } 383 384 SAFE_CLOSE(sfd); 385 SAFE_CLOSE(ufd); 386 387 return pid; 388} 389 390/* for permission test */ 391static void sender(int fd) 392{ 393 struct msghdr mh = {}; 394 struct cmsghdr *control; 395 char tmpfn[BUF_SIZE] = ""; 396 char snd_cbuf[BUF_SIZE] = ""; 397 int tfd; 398 399 (void)strcpy(tmpfn, "smtXXXXXX"); 400 tfd = mkstemp(tmpfn); 401 if (tfd < 0) 402 return; 403 404 /* set up cmsghdr */ 405 control = (struct cmsghdr *)snd_cbuf; 406 control->cmsg_len = sizeof(struct cmsghdr) + 4; 407 control->cmsg_level = SOL_SOCKET; 408 control->cmsg_type = SCM_RIGHTS; 409 *(int *)CMSG_DATA(control) = tfd; 410 411 /* set up msghdr */ 412 iov[0].iov_base = MSG; 413 iov[0].iov_len = sizeof(MSG); 414 mh.msg_iov = iov; 415 mh.msg_iovlen = 1; 416 mh.msg_flags = 0; 417 mh.msg_control = control; 418 mh.msg_controllen = control->cmsg_len; 419 420 /* do it */ 421 SAFE_SENDMSG(sizeof(MSG), fd, &mh, 0); 422 SAFE_CLOSE(tfd); 423 (void)SAFE_UNLINK(tmpfn); 424} 425 426static void do_child(void) 427{ 428 struct sockaddr_in fsin; 429 struct sockaddr_un fsun; 430 fd_set afds, rfds; 431 int nfds, fd; 432 433 FD_ZERO(&afds); 434 FD_SET(sfd, &afds); 435 FD_SET(ufd, &afds); 436 437 nfds = MAX(sfd + 1, ufd + 1); 438 439 /* accept connections until killed */ 440 while (1) { 441 socklen_t fromlen; 442 443 memcpy(&rfds, &afds, sizeof(rfds)); 444 445 if (select(nfds, &rfds, NULL, NULL, 446 NULL) < 0) { 447 if (errno != EINTR) { 448 perror("server select"); 449 exit(1); 450 } 451 continue; 452 } 453 if (FD_ISSET(sfd, &rfds)) { 454 int newfd; 455 456 fromlen = sizeof(fsin); 457 newfd = SAFE_ACCEPT(sfd, (struct sockaddr *)&fsin, &fromlen); 458 if (newfd >= 0) { 459 FD_SET(newfd, &afds); 460 nfds = MAX(nfds, newfd + 1); 461 /* send something back */ 462 SAFE_SEND(1, newfd, "hi", 2, 0); 463 } 464 } 465 if (FD_ISSET(ufd, &rfds)) { 466 int newfd; 467 468 fromlen = sizeof(fsun); 469 newfd = SAFE_ACCEPT(ufd, (struct sockaddr *)&fsun, &fromlen); 470 if (newfd >= 0) { 471 FD_SET(newfd, &afds); 472 nfds = MAX(nfds, newfd + 1); 473 } 474 } 475 for (fd = 0; fd < nfds; ++fd) 476 if (fd != sfd && fd != ufd && FD_ISSET(fd, &rfds)) { 477 char rbuf[BUF_SIZE]; 478 479 TEST(read(fd, rbuf, sizeof(rbuf))); 480 if (TST_RET > 0 && rbuf[0] == 'R') 481 sender(fd); 482 if (TST_RET == 0 || (TST_RET < 0 && TST_ERR != EINTR)) { 483 close(fd); 484 FD_CLR(fd, &afds); 485 } 486 } 487 } 488} 489 490static struct tst_test test = { 491 .test = run, 492 .tcnt = ARRAY_SIZE(tcases), 493 .forks_child = 1, 494 .needs_tmpdir = 1, 495}; 496