1 /* $OpenBSD: ungc.c,v 1.4 2022/02/03 17:22:01 bluhm Exp $ */ 2 3 /* 4 * Copyright (c) 2021 Vitaliy Makkoveev <mvs@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 #include <sys/socket.h> 21 #include <sys/time.h> 22 #include <sys/un.h> 23 #include <stdio.h> 24 #include <err.h> 25 #include <errno.h> 26 #include <fcntl.h> 27 #include <string.h> 28 #include <time.h> 29 #include <unistd.h> 30 31 union msg_control{ 32 struct cmsghdr cmsgh; 33 char control[CMSG_SPACE(sizeof(int) * 2)]; 34 }; 35 36 int main(int argc, char *argv[]) 37 { 38 struct timespec ts_start, ts_now, ts_time; 39 union msg_control msg_control; 40 int iov_buf; 41 struct iovec iov; 42 struct msghdr msgh; 43 struct cmsghdr *cmsgh; 44 int sp[2], sl[2], ts; 45 int infinite = 0; 46 47 if (argc > 1 && !strcmp(argv[1], "--infinite")) 48 infinite = 1; 49 50 if (!infinite) 51 if (clock_gettime(CLOCK_BOOTTIME, &ts_start) <0) 52 err(1, "clock_gettime"); 53 54 while (1) { 55 if (socketpair(AF_UNIX, SOCK_STREAM|O_NONBLOCK, 0, sp) < 0) 56 err(1, "socketpair"); 57 58 iov_buf = 0; 59 iov.iov_base = &iov_buf; 60 iov.iov_len = sizeof(iov_buf); 61 msgh.msg_control = msg_control.control; 62 msgh.msg_controllen = CMSG_SPACE(sizeof(int)); 63 msgh.msg_iov = &iov; 64 msgh.msg_iovlen = 1; 65 msgh.msg_name = NULL; 66 msgh.msg_namelen = 0; 67 cmsgh = CMSG_FIRSTHDR(&msgh); 68 cmsgh->cmsg_len = CMSG_LEN(sizeof(int)); 69 cmsgh->cmsg_level = SOL_SOCKET; 70 cmsgh->cmsg_type = SCM_RIGHTS; 71 72 *((int *)CMSG_DATA(cmsgh)) = sp[0]; 73 74 if (sendmsg(sp[0], &msgh, 0) < 0) { 75 if (errno == EMFILE) { 76 /* Too may sockets in flight */ 77 close(sp[0]); 78 goto skip; 79 } 80 81 err(1, "sendmsg sp0"); 82 } 83 84 *((int *)CMSG_DATA(cmsgh)) = sp[1]; 85 86 if (sendmsg(sp[1], &msgh, 0) < 0) { 87 if (errno == EMFILE) { 88 /* Too may sockets in flight */ 89 close(sp[0]); 90 goto skip; 91 } 92 93 err(1, "sendmsg sp1"); 94 } 95 96 /* 97 * After following close(2), the sp[0] socket has 98 * f_count equal to unp_msgcount. This socket is not 99 * in the loop and should not be killed by unp_gc(). 100 * This sockets should be successfully received. 101 * The sp[1] socket is stored within sp[0] receive 102 * buffer. This socket should be also successfully 103 * received. 104 */ 105 106 close(sp[0]); 107 108 if (socketpair(AF_UNIX, SOCK_STREAM|O_NONBLOCK, 0, sl) < 0) 109 err(1, "socketpair"); 110 111 iov_buf = 0; 112 iov.iov_base = &iov_buf; 113 iov.iov_len = sizeof(iov_buf); 114 msgh.msg_control = msg_control.control; 115 msgh.msg_controllen = CMSG_SPACE(sizeof(int) * 2); 116 msgh.msg_iov = &iov; 117 msgh.msg_iovlen = 1; 118 msgh.msg_name = NULL; 119 msgh.msg_namelen = 0; 120 cmsgh = CMSG_FIRSTHDR(&msgh); 121 cmsgh->cmsg_len = CMSG_LEN(sizeof(int) * 2); 122 cmsgh->cmsg_level = SOL_SOCKET; 123 cmsgh->cmsg_type = SCM_RIGHTS; 124 125 *((int *)CMSG_DATA(cmsgh) + 0) = sl[0]; 126 *((int *)CMSG_DATA(cmsgh) + 1) = sl[1]; 127 128 if (sendmsg(sl[0], &msgh, 0) < 0) { 129 if (errno != EMFILE) 130 err(1, "sendmsg sl0"); 131 } 132 133 /* 134 * After following close(2), the sl[0] socket is not 135 * in the loop and should be disposed by sorflush(). 136 * The sl[1] socket is in the loop and should be 137 * killed by unp_gc(). 138 */ 139 140 close(sl[0]); 141 close(sl[1]); 142 143 if (recvmsg(sp[1], &msgh, 0) < 0) { 144 if (errno == EMSGSIZE) 145 goto skip; 146 err(1, "recvmsg sp1"); 147 } 148 149 if (!(cmsgh = CMSG_FIRSTHDR(&msgh))) 150 errx(1, "bad cmsg header"); 151 if (cmsgh->cmsg_level != SOL_SOCKET) 152 errx(1, "bad cmsg level"); 153 if (cmsgh->cmsg_type != SCM_RIGHTS) 154 errx(1, "bad cmsg type"); 155 if (cmsgh->cmsg_len != CMSG_LEN(sizeof(ts))) 156 errx(1, "bad cmsg length"); 157 158 ts = *((int *)CMSG_DATA(cmsgh)); 159 160 if (recvmsg(ts, &msgh, 0) < 0) { 161 if (errno == EMSGSIZE) 162 goto skip; 163 err(1, "recvmsg ts"); 164 } 165 166 close(ts); 167 168 if (!(cmsgh = CMSG_FIRSTHDR(&msgh))) 169 errx(1, "bad cmsg header"); 170 if (cmsgh->cmsg_level != SOL_SOCKET) 171 errx(1, "bad cmsg level"); 172 if (cmsgh->cmsg_type != SCM_RIGHTS) 173 errx(1, "bad cmsg type"); 174 if (cmsgh->cmsg_len != CMSG_LEN(sizeof(ts))) 175 errx(1, "bad cmsg length"); 176 177 ts = *((int *)CMSG_DATA(cmsgh)); 178 close(ts); 179 180 skip: 181 close(sp[1]); 182 183 if (!infinite) { 184 if (clock_gettime(CLOCK_BOOTTIME, &ts_now) <0) 185 err(1, "clock_gettime"); 186 187 timespecsub(&ts_now, &ts_start, &ts_time); 188 if (ts_time.tv_sec >= 20) 189 break; 190 } 191 } 192 193 return 0; 194 } 195