1*d865fc92SAndy Fiddaman /* 2*d865fc92SAndy Fiddaman * This file and its contents are supplied under the terms of the 3*d865fc92SAndy Fiddaman * Common Development and Distribution License ("CDDL"), version 1.0. 4*d865fc92SAndy Fiddaman * You may only use this file in accordance with the terms of version 5*d865fc92SAndy Fiddaman * 1.0 of the CDDL. 6*d865fc92SAndy Fiddaman * 7*d865fc92SAndy Fiddaman * A full copy of the text of the CDDL should have accompanied this 8*d865fc92SAndy Fiddaman * source. A copy of the CDDL is also available via the Internet at 9*d865fc92SAndy Fiddaman * http://www.illumos.org/license/CDDL. 10*d865fc92SAndy Fiddaman */ 11*d865fc92SAndy Fiddaman 12*d865fc92SAndy Fiddaman /* 13*d865fc92SAndy Fiddaman * Copyright 2020 OmniOS Community Edition (OmniOSce) Association. 14*d865fc92SAndy Fiddaman */ 15*d865fc92SAndy Fiddaman 16*d865fc92SAndy Fiddaman /* 17*d865fc92SAndy Fiddaman * Test file descriptor passing via SCM_RIGHTS, and in particular what happens 18*d865fc92SAndy Fiddaman * on message truncation in terms of the represented size of the data in the 19*d865fc92SAndy Fiddaman * control message. Ensure that no file descriptors are leaked - the kernel 20*d865fc92SAndy Fiddaman * must close any that would not fit in the available buffer space and the 21*d865fc92SAndy Fiddaman * userland application must close the rest. 22*d865fc92SAndy Fiddaman */ 23*d865fc92SAndy Fiddaman 24*d865fc92SAndy Fiddaman #include <stdio.h> 25*d865fc92SAndy Fiddaman #include <errno.h> 26*d865fc92SAndy Fiddaman #include <fcntl.h> 27*d865fc92SAndy Fiddaman #include <signal.h> 28*d865fc92SAndy Fiddaman #include <stdlib.h> 29*d865fc92SAndy Fiddaman #include <string.h> 30*d865fc92SAndy Fiddaman #include <strings.h> 31*d865fc92SAndy Fiddaman #include <unistd.h> 32*d865fc92SAndy Fiddaman #include <libproc.h> 33*d865fc92SAndy Fiddaman 34*d865fc92SAndy Fiddaman #include <sys/types.h> 35*d865fc92SAndy Fiddaman #include <sys/param.h> 36*d865fc92SAndy Fiddaman #include <sys/socket.h> 37*d865fc92SAndy Fiddaman #include <sys/stat.h> 38*d865fc92SAndy Fiddaman #include <sys/un.h> 39*d865fc92SAndy Fiddaman #include <sys/wait.h> 40*d865fc92SAndy Fiddaman #include <assert.h> 41*d865fc92SAndy Fiddaman #include <alloca.h> 42*d865fc92SAndy Fiddaman #include <err.h> 43*d865fc92SAndy Fiddaman 44*d865fc92SAndy Fiddaman static boolean_t debug; 45*d865fc92SAndy Fiddaman 46*d865fc92SAndy Fiddaman typedef struct cmsg_test { 47*d865fc92SAndy Fiddaman char *name; /* Name of the test */ 48*d865fc92SAndy Fiddaman uint_t send; /* Number of FDs to send */ 49*d865fc92SAndy Fiddaman uint_t recv; /* Size receive buffer for this number of FDs */ 50*d865fc92SAndy Fiddaman size_t predata; /* Prepend dummy cmsg of this size */ 51*d865fc92SAndy Fiddaman int bufsize; /* Explicitly set receive buffer size. */ 52*d865fc92SAndy Fiddaman /* Overrides 'recv' if non-zero */ 53*d865fc92SAndy Fiddaman uint_t x_controllen; /* Expected received msg_controllen */ 54*d865fc92SAndy Fiddaman uint_t x_cmsg_datalen; /* Expected received cmsg data length */ 55*d865fc92SAndy Fiddaman uint32_t x_flags; /* Expected received msf_flags */ 56*d865fc92SAndy Fiddaman } cmsg_test_t; 57*d865fc92SAndy Fiddaman 58*d865fc92SAndy Fiddaman static cmsg_test_t tests[] = { 59*d865fc92SAndy Fiddaman { 60*d865fc92SAndy Fiddaman .name = "send 1, recv 1", 61*d865fc92SAndy Fiddaman .send = 1, 62*d865fc92SAndy Fiddaman .recv = 1, 63*d865fc92SAndy Fiddaman .predata = 0, 64*d865fc92SAndy Fiddaman .bufsize = 0, 65*d865fc92SAndy Fiddaman .x_controllen = 16, 66*d865fc92SAndy Fiddaman .x_cmsg_datalen = 4, 67*d865fc92SAndy Fiddaman .x_flags = 0, 68*d865fc92SAndy Fiddaman }, 69*d865fc92SAndy Fiddaman { 70*d865fc92SAndy Fiddaman .name = "send 10, recv 10", 71*d865fc92SAndy Fiddaman .send = 10, 72*d865fc92SAndy Fiddaman .recv = 10, 73*d865fc92SAndy Fiddaman .predata = 0, 74*d865fc92SAndy Fiddaman .bufsize = 0, 75*d865fc92SAndy Fiddaman .x_controllen = 52, 76*d865fc92SAndy Fiddaman .x_cmsg_datalen = 40, 77*d865fc92SAndy Fiddaman .x_flags = 0, 78*d865fc92SAndy Fiddaman }, 79*d865fc92SAndy Fiddaman { 80*d865fc92SAndy Fiddaman .name = "send 2, recv 1", 81*d865fc92SAndy Fiddaman .send = 2, 82*d865fc92SAndy Fiddaman .recv = 1, 83*d865fc92SAndy Fiddaman .predata = 0, 84*d865fc92SAndy Fiddaman .bufsize = 0, 85*d865fc92SAndy Fiddaman .x_controllen = 16, 86*d865fc92SAndy Fiddaman .x_cmsg_datalen = 4, 87*d865fc92SAndy Fiddaman .x_flags = MSG_CTRUNC, 88*d865fc92SAndy Fiddaman }, 89*d865fc92SAndy Fiddaman { 90*d865fc92SAndy Fiddaman .name = "send 2, recv 1, buffer 5", 91*d865fc92SAndy Fiddaman .send = 2, 92*d865fc92SAndy Fiddaman .recv = 1, 93*d865fc92SAndy Fiddaman .predata = 0, 94*d865fc92SAndy Fiddaman .bufsize = sizeof (int) * 2 - 3, 95*d865fc92SAndy Fiddaman .x_controllen = 17, 96*d865fc92SAndy Fiddaman .x_cmsg_datalen = 5, 97*d865fc92SAndy Fiddaman .x_flags = MSG_CTRUNC, 98*d865fc92SAndy Fiddaman }, 99*d865fc92SAndy Fiddaman { 100*d865fc92SAndy Fiddaman .name = "send 2, recv 1, buffer 6", 101*d865fc92SAndy Fiddaman .send = 2, 102*d865fc92SAndy Fiddaman .recv = 1, 103*d865fc92SAndy Fiddaman .predata = 0, 104*d865fc92SAndy Fiddaman .bufsize = sizeof (int) * 2 - 2, 105*d865fc92SAndy Fiddaman .x_controllen = 18, 106*d865fc92SAndy Fiddaman .x_cmsg_datalen = 6, 107*d865fc92SAndy Fiddaman .x_flags = MSG_CTRUNC, 108*d865fc92SAndy Fiddaman }, 109*d865fc92SAndy Fiddaman { 110*d865fc92SAndy Fiddaman .name = "send 2, recv 1, buffer 7", 111*d865fc92SAndy Fiddaman .send = 2, 112*d865fc92SAndy Fiddaman .recv = 1, 113*d865fc92SAndy Fiddaman .predata = 0, 114*d865fc92SAndy Fiddaman .bufsize = sizeof (int) * 2 - 1, 115*d865fc92SAndy Fiddaman .x_controllen = 19, 116*d865fc92SAndy Fiddaman .x_cmsg_datalen = 7, 117*d865fc92SAndy Fiddaman .x_flags = MSG_CTRUNC, 118*d865fc92SAndy Fiddaman }, 119*d865fc92SAndy Fiddaman 120*d865fc92SAndy Fiddaman /* Tests where there is no room allowed for data */ 121*d865fc92SAndy Fiddaman 122*d865fc92SAndy Fiddaman { 123*d865fc92SAndy Fiddaman .name = "send 2, recv 0, hdronly", 124*d865fc92SAndy Fiddaman .send = 2, 125*d865fc92SAndy Fiddaman .recv = 0, 126*d865fc92SAndy Fiddaman .predata = 0, 127*d865fc92SAndy Fiddaman .bufsize = 0, 128*d865fc92SAndy Fiddaman .x_controllen = 12, 129*d865fc92SAndy Fiddaman .x_cmsg_datalen = 0, 130*d865fc92SAndy Fiddaman .x_flags = MSG_CTRUNC, 131*d865fc92SAndy Fiddaman }, 132*d865fc92SAndy Fiddaman 133*d865fc92SAndy Fiddaman { 134*d865fc92SAndy Fiddaman .name = "send 2, recv 0, hdr - 1", 135*d865fc92SAndy Fiddaman .send = 2, 136*d865fc92SAndy Fiddaman .recv = 0, 137*d865fc92SAndy Fiddaman .predata = 0, 138*d865fc92SAndy Fiddaman .bufsize = -1, 139*d865fc92SAndy Fiddaman .x_controllen = 11, 140*d865fc92SAndy Fiddaman .x_cmsg_datalen = 0, 141*d865fc92SAndy Fiddaman .x_flags = MSG_CTRUNC, 142*d865fc92SAndy Fiddaman }, 143*d865fc92SAndy Fiddaman 144*d865fc92SAndy Fiddaman { 145*d865fc92SAndy Fiddaman .name = "send 2, recv 0, hdr - 5", 146*d865fc92SAndy Fiddaman .send = 2, 147*d865fc92SAndy Fiddaman .recv = 0, 148*d865fc92SAndy Fiddaman .predata = 0, 149*d865fc92SAndy Fiddaman .bufsize = -5, 150*d865fc92SAndy Fiddaman .x_controllen = 7, 151*d865fc92SAndy Fiddaman .x_cmsg_datalen = 0, 152*d865fc92SAndy Fiddaman .x_flags = MSG_CTRUNC, 153*d865fc92SAndy Fiddaman }, 154*d865fc92SAndy Fiddaman 155*d865fc92SAndy Fiddaman /* Tests where SCM_RIGHTS is not the first message */ 156*d865fc92SAndy Fiddaman 157*d865fc92SAndy Fiddaman { 158*d865fc92SAndy Fiddaman .name = "send 1, recv 1, pre 8", 159*d865fc92SAndy Fiddaman .send = 1, 160*d865fc92SAndy Fiddaman .recv = 1, 161*d865fc92SAndy Fiddaman .predata = 8, 162*d865fc92SAndy Fiddaman .bufsize = 0, 163*d865fc92SAndy Fiddaman .x_controllen = 36, 164*d865fc92SAndy Fiddaman .x_cmsg_datalen = 4, 165*d865fc92SAndy Fiddaman .x_flags = 0, 166*d865fc92SAndy Fiddaman }, 167*d865fc92SAndy Fiddaman { 168*d865fc92SAndy Fiddaman .name = "send 1, recv 1, pre 7", 169*d865fc92SAndy Fiddaman .send = 1, 170*d865fc92SAndy Fiddaman .recv = 1, 171*d865fc92SAndy Fiddaman .predata = 7, 172*d865fc92SAndy Fiddaman .bufsize = 0, 173*d865fc92SAndy Fiddaman .x_controllen = 35, 174*d865fc92SAndy Fiddaman .x_cmsg_datalen = 4, 175*d865fc92SAndy Fiddaman .x_flags = 0, 176*d865fc92SAndy Fiddaman }, 177*d865fc92SAndy Fiddaman { 178*d865fc92SAndy Fiddaman .name = "send 1, recv 1, pre 6", 179*d865fc92SAndy Fiddaman .send = 1, 180*d865fc92SAndy Fiddaman .recv = 1, 181*d865fc92SAndy Fiddaman .predata = 6, 182*d865fc92SAndy Fiddaman .bufsize = 0, 183*d865fc92SAndy Fiddaman .x_controllen = 34, 184*d865fc92SAndy Fiddaman .x_cmsg_datalen = 4, 185*d865fc92SAndy Fiddaman .x_flags = 0, 186*d865fc92SAndy Fiddaman }, 187*d865fc92SAndy Fiddaman { 188*d865fc92SAndy Fiddaman .name = "send 1, recv 1, pre 5", 189*d865fc92SAndy Fiddaman .send = 1, 190*d865fc92SAndy Fiddaman .recv = 1, 191*d865fc92SAndy Fiddaman .predata = 5, 192*d865fc92SAndy Fiddaman .bufsize = 0, 193*d865fc92SAndy Fiddaman .x_controllen = 33, 194*d865fc92SAndy Fiddaman .x_cmsg_datalen = 4, 195*d865fc92SAndy Fiddaman .x_flags = 0, 196*d865fc92SAndy Fiddaman }, 197*d865fc92SAndy Fiddaman 198*d865fc92SAndy Fiddaman { 199*d865fc92SAndy Fiddaman .name = "send 2, recv 1, pre 8", 200*d865fc92SAndy Fiddaman .send = 2, 201*d865fc92SAndy Fiddaman .recv = 1, 202*d865fc92SAndy Fiddaman .predata = 8, 203*d865fc92SAndy Fiddaman .bufsize = 0, 204*d865fc92SAndy Fiddaman .x_controllen = 36, 205*d865fc92SAndy Fiddaman .x_cmsg_datalen = 8, 206*d865fc92SAndy Fiddaman .x_flags = MSG_CTRUNC, 207*d865fc92SAndy Fiddaman }, 208*d865fc92SAndy Fiddaman { 209*d865fc92SAndy Fiddaman .name = "send 2, recv 1, pre 7", 210*d865fc92SAndy Fiddaman .send = 2, 211*d865fc92SAndy Fiddaman .recv = 1, 212*d865fc92SAndy Fiddaman .predata = 7, 213*d865fc92SAndy Fiddaman .bufsize = 0, 214*d865fc92SAndy Fiddaman .x_controllen = 36, 215*d865fc92SAndy Fiddaman .x_cmsg_datalen = 8, 216*d865fc92SAndy Fiddaman .x_flags = MSG_CTRUNC, 217*d865fc92SAndy Fiddaman }, 218*d865fc92SAndy Fiddaman { 219*d865fc92SAndy Fiddaman .name = "send 2, recv 1, pre 6", 220*d865fc92SAndy Fiddaman .send = 2, 221*d865fc92SAndy Fiddaman .recv = 1, 222*d865fc92SAndy Fiddaman .predata = 6, 223*d865fc92SAndy Fiddaman .bufsize = 0, 224*d865fc92SAndy Fiddaman .x_controllen = 36, 225*d865fc92SAndy Fiddaman .x_cmsg_datalen = 8, 226*d865fc92SAndy Fiddaman .x_flags = MSG_CTRUNC, 227*d865fc92SAndy Fiddaman }, 228*d865fc92SAndy Fiddaman { 229*d865fc92SAndy Fiddaman .name = "send 2, recv 1, pre 5", 230*d865fc92SAndy Fiddaman .send = 2, 231*d865fc92SAndy Fiddaman .recv = 1, 232*d865fc92SAndy Fiddaman .predata = 5, 233*d865fc92SAndy Fiddaman .bufsize = 0, 234*d865fc92SAndy Fiddaman .x_controllen = 36, 235*d865fc92SAndy Fiddaman .x_cmsg_datalen = 8, 236*d865fc92SAndy Fiddaman .x_flags = MSG_CTRUNC, 237*d865fc92SAndy Fiddaman }, 238*d865fc92SAndy Fiddaman { 239*d865fc92SAndy Fiddaman .name = "send 2, recv 1, pre 4", 240*d865fc92SAndy Fiddaman .send = 2, 241*d865fc92SAndy Fiddaman .recv = 1, 242*d865fc92SAndy Fiddaman .predata = 4, 243*d865fc92SAndy Fiddaman .bufsize = 0, 244*d865fc92SAndy Fiddaman .x_controllen = 32, 245*d865fc92SAndy Fiddaman .x_cmsg_datalen = 8, 246*d865fc92SAndy Fiddaman .x_flags = MSG_CTRUNC, 247*d865fc92SAndy Fiddaman }, 248*d865fc92SAndy Fiddaman { 249*d865fc92SAndy Fiddaman .name = "send 2, recv 1, pre 3", 250*d865fc92SAndy Fiddaman .send = 2, 251*d865fc92SAndy Fiddaman .recv = 1, 252*d865fc92SAndy Fiddaman .predata = 3, 253*d865fc92SAndy Fiddaman .bufsize = 0, 254*d865fc92SAndy Fiddaman .x_controllen = 32, 255*d865fc92SAndy Fiddaman .x_cmsg_datalen = 8, 256*d865fc92SAndy Fiddaman .x_flags = MSG_CTRUNC, 257*d865fc92SAndy Fiddaman }, 258*d865fc92SAndy Fiddaman { 259*d865fc92SAndy Fiddaman .name = "send 2, recv 1, pre 2", 260*d865fc92SAndy Fiddaman .send = 2, 261*d865fc92SAndy Fiddaman .recv = 1, 262*d865fc92SAndy Fiddaman .predata = 2, 263*d865fc92SAndy Fiddaman .bufsize = 0, 264*d865fc92SAndy Fiddaman .x_controllen = 32, 265*d865fc92SAndy Fiddaman .x_cmsg_datalen = 8, 266*d865fc92SAndy Fiddaman .x_flags = MSG_CTRUNC, 267*d865fc92SAndy Fiddaman }, 268*d865fc92SAndy Fiddaman { 269*d865fc92SAndy Fiddaman .name = "send 2, recv 1, pre 1", 270*d865fc92SAndy Fiddaman .send = 2, 271*d865fc92SAndy Fiddaman .recv = 1, 272*d865fc92SAndy Fiddaman .predata = 1, 273*d865fc92SAndy Fiddaman .bufsize = 0, 274*d865fc92SAndy Fiddaman .x_controllen = 32, 275*d865fc92SAndy Fiddaman .x_cmsg_datalen = 8, 276*d865fc92SAndy Fiddaman .x_flags = MSG_CTRUNC, 277*d865fc92SAndy Fiddaman }, 278*d865fc92SAndy Fiddaman 279*d865fc92SAndy Fiddaman { 280*d865fc92SAndy Fiddaman .name = "send 2, recv 1, pre 8, buffer 5", 281*d865fc92SAndy Fiddaman .send = 2, 282*d865fc92SAndy Fiddaman .recv = 1, 283*d865fc92SAndy Fiddaman .predata = 8, 284*d865fc92SAndy Fiddaman .bufsize = sizeof (int) * 2 - 3, 285*d865fc92SAndy Fiddaman .x_controllen = 37, 286*d865fc92SAndy Fiddaman .x_cmsg_datalen = 8, 287*d865fc92SAndy Fiddaman .x_flags = MSG_CTRUNC, 288*d865fc92SAndy Fiddaman }, 289*d865fc92SAndy Fiddaman { 290*d865fc92SAndy Fiddaman .name = "send 2, recv 1, pre 8, buffer 6", 291*d865fc92SAndy Fiddaman .send = 2, 292*d865fc92SAndy Fiddaman .recv = 1, 293*d865fc92SAndy Fiddaman .predata = 8, 294*d865fc92SAndy Fiddaman .bufsize = sizeof (int) * 2 - 2, 295*d865fc92SAndy Fiddaman .x_controllen = 38, 296*d865fc92SAndy Fiddaman .x_cmsg_datalen = 8, 297*d865fc92SAndy Fiddaman .x_flags = MSG_CTRUNC, 298*d865fc92SAndy Fiddaman }, 299*d865fc92SAndy Fiddaman { 300*d865fc92SAndy Fiddaman .name = "send 2, recv 1, pre 8, buffer 7", 301*d865fc92SAndy Fiddaman .send = 2, 302*d865fc92SAndy Fiddaman .recv = 1, 303*d865fc92SAndy Fiddaman .predata = 8, 304*d865fc92SAndy Fiddaman .bufsize = sizeof (int) * 2 - 1, 305*d865fc92SAndy Fiddaman .x_controllen = 39, 306*d865fc92SAndy Fiddaman .x_cmsg_datalen = 8, 307*d865fc92SAndy Fiddaman .x_flags = MSG_CTRUNC, 308*d865fc92SAndy Fiddaman }, 309*d865fc92SAndy Fiddaman { 310*d865fc92SAndy Fiddaman .name = "send 10, recv 1, pre 8", 311*d865fc92SAndy Fiddaman .send = 10, 312*d865fc92SAndy Fiddaman .recv = 1, 313*d865fc92SAndy Fiddaman .predata = 8, 314*d865fc92SAndy Fiddaman .bufsize = 0, 315*d865fc92SAndy Fiddaman .x_controllen = 36, 316*d865fc92SAndy Fiddaman .x_cmsg_datalen = 24, 317*d865fc92SAndy Fiddaman .x_flags = MSG_CTRUNC, 318*d865fc92SAndy Fiddaman }, 319*d865fc92SAndy Fiddaman 320*d865fc92SAndy Fiddaman /* End of tests */ 321*d865fc92SAndy Fiddaman 322*d865fc92SAndy Fiddaman { 323*d865fc92SAndy Fiddaman .name = NULL 324*d865fc92SAndy Fiddaman } 325*d865fc92SAndy Fiddaman }; 326*d865fc92SAndy Fiddaman 327*d865fc92SAndy Fiddaman static int sock = -1, testfd = -1, cfd = -1; 328*d865fc92SAndy Fiddaman static int fdcount; 329*d865fc92SAndy Fiddaman 330*d865fc92SAndy Fiddaman static int 331*d865fc92SAndy Fiddaman fdwalkcb(const prfdinfo_t *info, void *arg) 332*d865fc92SAndy Fiddaman { 333*d865fc92SAndy Fiddaman if (!S_ISDIR(info->pr_mode) && info->pr_fd > 2 && 334*d865fc92SAndy Fiddaman info->pr_fd != sock && info->pr_fd != testfd && 335*d865fc92SAndy Fiddaman info->pr_fd != cfd) { 336*d865fc92SAndy Fiddaman if (debug) { 337*d865fc92SAndy Fiddaman fprintf(stderr, "%s: unexpected fd: %d\n", 338*d865fc92SAndy Fiddaman (char *)arg, info->pr_fd); 339*d865fc92SAndy Fiddaman } 340*d865fc92SAndy Fiddaman fdcount++; 341*d865fc92SAndy Fiddaman } 342*d865fc92SAndy Fiddaman 343*d865fc92SAndy Fiddaman return (0); 344*d865fc92SAndy Fiddaman 345*d865fc92SAndy Fiddaman } 346*d865fc92SAndy Fiddaman 347*d865fc92SAndy Fiddaman static void 348*d865fc92SAndy Fiddaman check_fds(char *tag) 349*d865fc92SAndy Fiddaman { 350*d865fc92SAndy Fiddaman fdcount = 0; 351*d865fc92SAndy Fiddaman proc_fdwalk(getpid(), fdwalkcb, tag); 352*d865fc92SAndy Fiddaman } 353*d865fc92SAndy Fiddaman 354*d865fc92SAndy Fiddaman static void 355*d865fc92SAndy Fiddaman send_and_wait(pid_t pid, sigset_t *set, int osig, int isig) 356*d865fc92SAndy Fiddaman { 357*d865fc92SAndy Fiddaman int sig; 358*d865fc92SAndy Fiddaman 359*d865fc92SAndy Fiddaman if (osig > 0) 360*d865fc92SAndy Fiddaman kill(pid, osig); 361*d865fc92SAndy Fiddaman 362*d865fc92SAndy Fiddaman if (isig > 0) { 363*d865fc92SAndy Fiddaman if (sigwait(set, &sig) != 0) { 364*d865fc92SAndy Fiddaman err(EXIT_FAILURE, 365*d865fc92SAndy Fiddaman "sigwait failed waiting for %d", isig); 366*d865fc92SAndy Fiddaman } 367*d865fc92SAndy Fiddaman if (sig == SIGINT) { 368*d865fc92SAndy Fiddaman exit(1); 369*d865fc92SAndy Fiddaman } 370*d865fc92SAndy Fiddaman if (sig != isig) { 371*d865fc92SAndy Fiddaman err(EXIT_FAILURE, 372*d865fc92SAndy Fiddaman "sigwait returned unexpected signal %d", sig); 373*d865fc92SAndy Fiddaman } 374*d865fc92SAndy Fiddaman } 375*d865fc92SAndy Fiddaman } 376*d865fc92SAndy Fiddaman 377*d865fc92SAndy Fiddaman static void 378*d865fc92SAndy Fiddaman sendtest(cmsg_test_t *t) 379*d865fc92SAndy Fiddaman { 380*d865fc92SAndy Fiddaman struct msghdr msg; 381*d865fc92SAndy Fiddaman struct cmsghdr *cm; 382*d865fc92SAndy Fiddaman struct iovec iov; 383*d865fc92SAndy Fiddaman ssize_t nbytes; 384*d865fc92SAndy Fiddaman char c = '*'; 385*d865fc92SAndy Fiddaman int i, *p; 386*d865fc92SAndy Fiddaman 387*d865fc92SAndy Fiddaman bzero(&msg, sizeof (msg)); 388*d865fc92SAndy Fiddaman 389*d865fc92SAndy Fiddaman msg.msg_name = NULL; 390*d865fc92SAndy Fiddaman msg.msg_namelen = 0; 391*d865fc92SAndy Fiddaman 392*d865fc92SAndy Fiddaman iov.iov_base = &c; 393*d865fc92SAndy Fiddaman iov.iov_len = sizeof (c); 394*d865fc92SAndy Fiddaman msg.msg_iov = &iov; 395*d865fc92SAndy Fiddaman msg.msg_iovlen = 1; 396*d865fc92SAndy Fiddaman 397*d865fc92SAndy Fiddaman msg.msg_flags = 0; 398*d865fc92SAndy Fiddaman 399*d865fc92SAndy Fiddaman msg.msg_controllen = CMSG_SPACE(sizeof (int) * t->send); 400*d865fc92SAndy Fiddaman 401*d865fc92SAndy Fiddaman if (t->predata > 0) { 402*d865fc92SAndy Fiddaman /* A dummy cmsg will be inserted at the head of the data */ 403*d865fc92SAndy Fiddaman msg.msg_controllen += CMSG_SPACE(t->predata); 404*d865fc92SAndy Fiddaman } 405*d865fc92SAndy Fiddaman 406*d865fc92SAndy Fiddaman msg.msg_control = alloca(msg.msg_controllen); 407*d865fc92SAndy Fiddaman bzero(msg.msg_control, msg.msg_controllen); 408*d865fc92SAndy Fiddaman 409*d865fc92SAndy Fiddaman cm = CMSG_FIRSTHDR(&msg); 410*d865fc92SAndy Fiddaman 411*d865fc92SAndy Fiddaman if (t->predata > 0) { 412*d865fc92SAndy Fiddaman /* Insert the dummy cmsg */ 413*d865fc92SAndy Fiddaman cm->cmsg_len = CMSG_LEN(t->predata); 414*d865fc92SAndy Fiddaman cm->cmsg_level = SOL_SOCKET; 415*d865fc92SAndy Fiddaman cm->cmsg_type = 0; 416*d865fc92SAndy Fiddaman cm = CMSG_NXTHDR(&msg, cm); 417*d865fc92SAndy Fiddaman } 418*d865fc92SAndy Fiddaman 419*d865fc92SAndy Fiddaman cm->cmsg_len = CMSG_LEN(sizeof (int) * t->send); 420*d865fc92SAndy Fiddaman cm->cmsg_level = SOL_SOCKET; 421*d865fc92SAndy Fiddaman cm->cmsg_type = SCM_RIGHTS; 422*d865fc92SAndy Fiddaman 423*d865fc92SAndy Fiddaman p = (int *)CMSG_DATA(cm); 424*d865fc92SAndy Fiddaman for (i = 0; i < t->send; i++) { 425*d865fc92SAndy Fiddaman int s = dup(testfd); 426*d865fc92SAndy Fiddaman if (s == -1) 427*d865fc92SAndy Fiddaman err(EXIT_FAILURE, "dup()"); 428*d865fc92SAndy Fiddaman *p++ = s; 429*d865fc92SAndy Fiddaman } 430*d865fc92SAndy Fiddaman 431*d865fc92SAndy Fiddaman if (debug) 432*d865fc92SAndy Fiddaman printf("Sending: controllen=%u\n", msg.msg_controllen); 433*d865fc92SAndy Fiddaman 434*d865fc92SAndy Fiddaman nbytes = sendmsg(cfd, &msg, 0); 435*d865fc92SAndy Fiddaman if (nbytes == -1) 436*d865fc92SAndy Fiddaman err(EXIT_FAILURE, "sendmsg()"); 437*d865fc92SAndy Fiddaman 438*d865fc92SAndy Fiddaman p = (int *)CMSG_DATA(cm); 439*d865fc92SAndy Fiddaman for (i = 0; i < t->send; i++) 440*d865fc92SAndy Fiddaman (void) close(*p++); 441*d865fc92SAndy Fiddaman } 442*d865fc92SAndy Fiddaman 443*d865fc92SAndy Fiddaman static int 444*d865fc92SAndy Fiddaman server(const char *sockpath, pid_t pid) 445*d865fc92SAndy Fiddaman { 446*d865fc92SAndy Fiddaman struct sockaddr_un addr; 447*d865fc92SAndy Fiddaman sigset_t set; 448*d865fc92SAndy Fiddaman cmsg_test_t *t; 449*d865fc92SAndy Fiddaman 450*d865fc92SAndy Fiddaman sigemptyset(&set); 451*d865fc92SAndy Fiddaman sigaddset(&set, SIGUSR2); 452*d865fc92SAndy Fiddaman sigaddset(&set, SIGINT); 453*d865fc92SAndy Fiddaman 454*d865fc92SAndy Fiddaman sock = socket(PF_LOCAL, SOCK_STREAM, 0); 455*d865fc92SAndy Fiddaman if (sock == -1) 456*d865fc92SAndy Fiddaman err(EXIT_FAILURE, "failed to create socket"); 457*d865fc92SAndy Fiddaman addr.sun_family = AF_UNIX; 458*d865fc92SAndy Fiddaman strlcpy(addr.sun_path, sockpath, sizeof (addr.sun_path)); 459*d865fc92SAndy Fiddaman if (bind(sock, (struct sockaddr *)&addr, sizeof (addr)) == -1) 460*d865fc92SAndy Fiddaman err(EXIT_FAILURE, "bind failed"); 461*d865fc92SAndy Fiddaman if (listen(sock, 0) == -1) 462*d865fc92SAndy Fiddaman err(EXIT_FAILURE, "listen failed"); 463*d865fc92SAndy Fiddaman 464*d865fc92SAndy Fiddaman if ((testfd = open("/dev/null", O_RDONLY)) == -1) 465*d865fc92SAndy Fiddaman err(EXIT_FAILURE, "/dev/null"); 466*d865fc92SAndy Fiddaman 467*d865fc92SAndy Fiddaman check_fds("server"); 468*d865fc92SAndy Fiddaman 469*d865fc92SAndy Fiddaman /* Signal the child to connect to the socket */ 470*d865fc92SAndy Fiddaman send_and_wait(pid, &set, SIGUSR1, SIGUSR2); 471*d865fc92SAndy Fiddaman 472*d865fc92SAndy Fiddaman if ((cfd = accept(sock, NULL, 0)) == -1) 473*d865fc92SAndy Fiddaman err(EXIT_FAILURE, "accept failed"); 474*d865fc92SAndy Fiddaman 475*d865fc92SAndy Fiddaman for (t = tests; t->name != NULL; t++) { 476*d865fc92SAndy Fiddaman if (debug) 477*d865fc92SAndy Fiddaman printf("\n>>> Starting test %s\n", t->name); 478*d865fc92SAndy Fiddaman 479*d865fc92SAndy Fiddaman sendtest(t); 480*d865fc92SAndy Fiddaman check_fds("server"); 481*d865fc92SAndy Fiddaman 482*d865fc92SAndy Fiddaman send_and_wait(pid, &set, SIGUSR1, SIGUSR2); 483*d865fc92SAndy Fiddaman } 484*d865fc92SAndy Fiddaman 485*d865fc92SAndy Fiddaman close(cfd); 486*d865fc92SAndy Fiddaman close(testfd); 487*d865fc92SAndy Fiddaman close(sock); 488*d865fc92SAndy Fiddaman 489*d865fc92SAndy Fiddaman return (0); 490*d865fc92SAndy Fiddaman } 491*d865fc92SAndy Fiddaman 492*d865fc92SAndy Fiddaman static boolean_t pass; 493*d865fc92SAndy Fiddaman 494*d865fc92SAndy Fiddaman static void 495*d865fc92SAndy Fiddaman check(uint_t actual, uint_t expected, char *tag) 496*d865fc92SAndy Fiddaman { 497*d865fc92SAndy Fiddaman if (actual != expected) { 498*d865fc92SAndy Fiddaman fprintf(stderr, " !!!: " 499*d865fc92SAndy Fiddaman "%1$s = %2$u(%2$#x) (expected %3$u(%3$#x))\n", 500*d865fc92SAndy Fiddaman tag, actual, expected); 501*d865fc92SAndy Fiddaman pass = _B_FALSE; 502*d865fc92SAndy Fiddaman } else if (debug) { 503*d865fc92SAndy Fiddaman fprintf(stderr, " : " 504*d865fc92SAndy Fiddaman "%1$s = %2$u(%2$#x)\n", 505*d865fc92SAndy Fiddaman tag, actual); 506*d865fc92SAndy Fiddaman } 507*d865fc92SAndy Fiddaman } 508*d865fc92SAndy Fiddaman 509*d865fc92SAndy Fiddaman static boolean_t 510*d865fc92SAndy Fiddaman recvtest(cmsg_test_t *t) 511*d865fc92SAndy Fiddaman { 512*d865fc92SAndy Fiddaman struct msghdr msg; 513*d865fc92SAndy Fiddaman struct cmsghdr *cm; 514*d865fc92SAndy Fiddaman struct iovec iov; 515*d865fc92SAndy Fiddaman size_t bufsize; 516*d865fc92SAndy Fiddaman ssize_t nbytes; 517*d865fc92SAndy Fiddaman char c = '*'; 518*d865fc92SAndy Fiddaman 519*d865fc92SAndy Fiddaman bzero(&msg, sizeof (msg)); 520*d865fc92SAndy Fiddaman 521*d865fc92SAndy Fiddaman msg.msg_name = NULL; 522*d865fc92SAndy Fiddaman msg.msg_namelen = 0; 523*d865fc92SAndy Fiddaman 524*d865fc92SAndy Fiddaman iov.iov_base = &c; 525*d865fc92SAndy Fiddaman iov.iov_len = sizeof (c); 526*d865fc92SAndy Fiddaman msg.msg_iov = &iov; 527*d865fc92SAndy Fiddaman msg.msg_iovlen = 1; 528*d865fc92SAndy Fiddaman 529*d865fc92SAndy Fiddaman msg.msg_flags = 0; 530*d865fc92SAndy Fiddaman 531*d865fc92SAndy Fiddaman /* 532*d865fc92SAndy Fiddaman * If the test does not specify a receive buffer size, calculate one 533*d865fc92SAndy Fiddaman * from the number of file descriptors to receive. 534*d865fc92SAndy Fiddaman */ 535*d865fc92SAndy Fiddaman if (t->bufsize == 0) { 536*d865fc92SAndy Fiddaman bufsize = sizeof (int) * t->recv; 537*d865fc92SAndy Fiddaman bufsize = CMSG_SPACE(bufsize); 538*d865fc92SAndy Fiddaman } else { 539*d865fc92SAndy Fiddaman /* 540*d865fc92SAndy Fiddaman * Use the specific buffer size provided but add in 541*d865fc92SAndy Fiddaman * space for the header 542*d865fc92SAndy Fiddaman */ 543*d865fc92SAndy Fiddaman bufsize = t->bufsize + CMSG_LEN(0); 544*d865fc92SAndy Fiddaman } 545*d865fc92SAndy Fiddaman 546*d865fc92SAndy Fiddaman if (t->predata > 0) { 547*d865fc92SAndy Fiddaman /* A dummy cmsg will be found at the head of the data */ 548*d865fc92SAndy Fiddaman bufsize += CMSG_SPACE(t->predata); 549*d865fc92SAndy Fiddaman } 550*d865fc92SAndy Fiddaman 551*d865fc92SAndy Fiddaman msg.msg_controllen = bufsize; 552*d865fc92SAndy Fiddaman msg.msg_control = alloca(bufsize); 553*d865fc92SAndy Fiddaman bzero(msg.msg_control, msg.msg_controllen); 554*d865fc92SAndy Fiddaman 555*d865fc92SAndy Fiddaman pass = _B_TRUE; 556*d865fc92SAndy Fiddaman 557*d865fc92SAndy Fiddaman if (debug) 558*d865fc92SAndy Fiddaman printf("Receiving: controllen=%u, \n", msg.msg_controllen); 559*d865fc92SAndy Fiddaman 560*d865fc92SAndy Fiddaman nbytes = recvmsg(sock, &msg, 0); 561*d865fc92SAndy Fiddaman 562*d865fc92SAndy Fiddaman if (nbytes == -1) { 563*d865fc92SAndy Fiddaman pass = _B_FALSE; 564*d865fc92SAndy Fiddaman fprintf(stderr, "recvmsg() failed: %s\n", strerror(errno)); 565*d865fc92SAndy Fiddaman goto out; 566*d865fc92SAndy Fiddaman } 567*d865fc92SAndy Fiddaman 568*d865fc92SAndy Fiddaman if (debug) { 569*d865fc92SAndy Fiddaman printf("Received: controllen=%u, flags=%#x\n", 570*d865fc92SAndy Fiddaman msg.msg_controllen, msg.msg_flags); 571*d865fc92SAndy Fiddaman } 572*d865fc92SAndy Fiddaman 573*d865fc92SAndy Fiddaman check(msg.msg_flags, t->x_flags, "msg_flags"); 574*d865fc92SAndy Fiddaman check(msg.msg_controllen, t->x_controllen, "msg_controllen"); 575*d865fc92SAndy Fiddaman 576*d865fc92SAndy Fiddaman for (cm = CMSG_FIRSTHDR(&msg); cm; cm = CMSG_NXTHDR(&msg, cm)) { 577*d865fc92SAndy Fiddaman void *data, *end; 578*d865fc92SAndy Fiddaman 579*d865fc92SAndy Fiddaman if (debug) { 580*d865fc92SAndy Fiddaman printf(" >> : Got cmsg %x/%x - %u\n", cm->cmsg_level, 581*d865fc92SAndy Fiddaman cm->cmsg_type, cm->cmsg_len); 582*d865fc92SAndy Fiddaman } 583*d865fc92SAndy Fiddaman 584*d865fc92SAndy Fiddaman if (cm->cmsg_type != SCM_RIGHTS) { 585*d865fc92SAndy Fiddaman if (debug) 586*d865fc92SAndy Fiddaman printf(" : skipping cmsg\n"); 587*d865fc92SAndy Fiddaman continue; 588*d865fc92SAndy Fiddaman } 589*d865fc92SAndy Fiddaman 590*d865fc92SAndy Fiddaman check(cm->cmsg_len - CMSG_LEN(0), 591*d865fc92SAndy Fiddaman t->x_cmsg_datalen, "cmsg_len"); 592*d865fc92SAndy Fiddaman 593*d865fc92SAndy Fiddaman /* Close any received file descriptors */ 594*d865fc92SAndy Fiddaman data = CMSG_DATA(cm); 595*d865fc92SAndy Fiddaman 596*d865fc92SAndy Fiddaman if ((msg.msg_flags & MSG_CTRUNC) && 597*d865fc92SAndy Fiddaman CMSG_NXTHDR(&msg, cm) == NULL) { 598*d865fc92SAndy Fiddaman /* 599*d865fc92SAndy Fiddaman * illumos did not previously adjust cmsg_len on 600*d865fc92SAndy Fiddaman * truncation. This is the last cmsg, derive the 601*d865fc92SAndy Fiddaman * length from msg_controllen 602*d865fc92SAndy Fiddaman */ 603*d865fc92SAndy Fiddaman end = msg.msg_control + msg.msg_controllen; 604*d865fc92SAndy Fiddaman } else { 605*d865fc92SAndy Fiddaman end = data + cm->cmsg_len - CMSG_LEN(0); 606*d865fc92SAndy Fiddaman } 607*d865fc92SAndy Fiddaman 608*d865fc92SAndy Fiddaman while (data <= end - sizeof (int)) { 609*d865fc92SAndy Fiddaman int *a = (int *)data; 610*d865fc92SAndy Fiddaman if (debug) 611*d865fc92SAndy Fiddaman printf(" : close(%d)\n", *a); 612*d865fc92SAndy Fiddaman if (close(*a) == -1) { 613*d865fc92SAndy Fiddaman pass = _B_FALSE; 614*d865fc92SAndy Fiddaman fprintf(stderr, " !!!: " 615*d865fc92SAndy Fiddaman "failed to close fd %d - %s\n", *a, 616*d865fc92SAndy Fiddaman strerror(errno)); 617*d865fc92SAndy Fiddaman } 618*d865fc92SAndy Fiddaman data += sizeof (int); 619*d865fc92SAndy Fiddaman } 620*d865fc92SAndy Fiddaman } 621*d865fc92SAndy Fiddaman 622*d865fc92SAndy Fiddaman out: 623*d865fc92SAndy Fiddaman 624*d865fc92SAndy Fiddaman check_fds("client"); 625*d865fc92SAndy Fiddaman check(fdcount, 0, "client descriptors"); 626*d865fc92SAndy Fiddaman printf(" + : %s %s\n", pass ? "PASS" : "FAIL", t->name); 627*d865fc92SAndy Fiddaman 628*d865fc92SAndy Fiddaman return (pass); 629*d865fc92SAndy Fiddaman } 630*d865fc92SAndy Fiddaman 631*d865fc92SAndy Fiddaman static int 632*d865fc92SAndy Fiddaman client(const char *sockpath, pid_t pid) 633*d865fc92SAndy Fiddaman { 634*d865fc92SAndy Fiddaman struct sockaddr_un addr; 635*d865fc92SAndy Fiddaman sigset_t set; 636*d865fc92SAndy Fiddaman cmsg_test_t *t; 637*d865fc92SAndy Fiddaman int ret = 0; 638*d865fc92SAndy Fiddaman 639*d865fc92SAndy Fiddaman sigemptyset(&set); 640*d865fc92SAndy Fiddaman sigaddset(&set, SIGUSR1); 641*d865fc92SAndy Fiddaman sigaddset(&set, SIGINT); 642*d865fc92SAndy Fiddaman 643*d865fc92SAndy Fiddaman send_and_wait(pid, &set, 0, SIGUSR1); 644*d865fc92SAndy Fiddaman 645*d865fc92SAndy Fiddaman sock = socket(PF_LOCAL, SOCK_STREAM, 0); 646*d865fc92SAndy Fiddaman if (sock == -1) 647*d865fc92SAndy Fiddaman err(EXIT_FAILURE, "failed to create socket"); 648*d865fc92SAndy Fiddaman addr.sun_family = AF_UNIX; 649*d865fc92SAndy Fiddaman strlcpy(addr.sun_path, sockpath, sizeof (addr.sun_path)); 650*d865fc92SAndy Fiddaman if (connect(sock, (struct sockaddr *)&addr, sizeof (addr)) == -1) 651*d865fc92SAndy Fiddaman err(EXIT_FAILURE, "could not connect to server socket"); 652*d865fc92SAndy Fiddaman 653*d865fc92SAndy Fiddaman for (t = tests; t->name != NULL; t++) { 654*d865fc92SAndy Fiddaman send_and_wait(pid, &set, SIGUSR2, SIGUSR1); 655*d865fc92SAndy Fiddaman if (!recvtest(t)) 656*d865fc92SAndy Fiddaman ret = 1; 657*d865fc92SAndy Fiddaman } 658*d865fc92SAndy Fiddaman 659*d865fc92SAndy Fiddaman close(sock); 660*d865fc92SAndy Fiddaman 661*d865fc92SAndy Fiddaman return (ret); 662*d865fc92SAndy Fiddaman } 663*d865fc92SAndy Fiddaman 664*d865fc92SAndy Fiddaman int 665*d865fc92SAndy Fiddaman main(int argc, const char **argv) 666*d865fc92SAndy Fiddaman { 667*d865fc92SAndy Fiddaman char sockpath[] = "/tmp/cmsg.testsock.XXXXXX"; 668*d865fc92SAndy Fiddaman pid_t pid, ppid; 669*d865fc92SAndy Fiddaman sigset_t set; 670*d865fc92SAndy Fiddaman int ret = 0; 671*d865fc92SAndy Fiddaman 672*d865fc92SAndy Fiddaman if (argc > 1 && strcmp(argv[1], "-d") == 0) 673*d865fc92SAndy Fiddaman debug = _B_TRUE; 674*d865fc92SAndy Fiddaman 675*d865fc92SAndy Fiddaman sigfillset(&set); 676*d865fc92SAndy Fiddaman sigdelset(&set, SIGINT); 677*d865fc92SAndy Fiddaman sigdelset(&set, SIGTSTP); 678*d865fc92SAndy Fiddaman sigprocmask(SIG_BLOCK, &set, NULL); 679*d865fc92SAndy Fiddaman 680*d865fc92SAndy Fiddaman if (mktemp(sockpath) == NULL) 681*d865fc92SAndy Fiddaman err(EXIT_FAILURE, "Failed to make temporary socket path"); 682*d865fc92SAndy Fiddaman 683*d865fc92SAndy Fiddaman ppid = getpid(); 684*d865fc92SAndy Fiddaman pid = fork(); 685*d865fc92SAndy Fiddaman switch (pid) { 686*d865fc92SAndy Fiddaman case -1: 687*d865fc92SAndy Fiddaman err(EXIT_FAILURE, "fork failed"); 688*d865fc92SAndy Fiddaman case 0: 689*d865fc92SAndy Fiddaman return (server(sockpath, ppid)); 690*d865fc92SAndy Fiddaman default: 691*d865fc92SAndy Fiddaman break; 692*d865fc92SAndy Fiddaman } 693*d865fc92SAndy Fiddaman 694*d865fc92SAndy Fiddaman ret = client(sockpath, pid); 695*d865fc92SAndy Fiddaman kill(pid, SIGINT); 696*d865fc92SAndy Fiddaman 697*d865fc92SAndy Fiddaman unlink(sockpath); 698*d865fc92SAndy Fiddaman 699*d865fc92SAndy Fiddaman return (ret); 700*d865fc92SAndy Fiddaman } 701