1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2023 Gleb Smirnoff <glebius@FreeBSD.org> 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/param.h> 29 #include <sys/ioctl.h> 30 #include <sys/time.h> 31 #include <sys/socket.h> 32 #include <sys/module.h> 33 #include <errno.h> 34 #include <fcntl.h> 35 #include <signal.h> 36 #include <stdlib.h> 37 #include <unistd.h> 38 39 #include <netlink/netlink.h> 40 #include <netlink/netlink_route.h> 41 42 #include <atf-c.h> 43 44 static struct itimerval itv = { 45 .it_interval = { 0, 0 }, 46 .it_value = { 1, 0 }, /* one second */ 47 }; 48 static sig_atomic_t timer_done = 0; 49 static void 50 sigalarm(int sig __unused) 51 { 52 53 timer_done = 1; 54 } 55 56 static struct sigaction sigact = { 57 .sa_handler = sigalarm, 58 }; 59 60 static struct nlmsghdr hdr = (struct nlmsghdr) { 61 .nlmsg_type = RTM_GETLINK, 62 .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK, 63 .nlmsg_len = sizeof(struct nlmsghdr), 64 }; 65 66 #define BUFLEN 1000 67 68 static int 69 fullsocket(void) 70 { 71 char buf[BUFLEN]; 72 socklen_t slen = sizeof(int); 73 int fd, sendspace, recvspace, sendavail, recvavail, rsize; 74 u_int cnt = 0; 75 76 ATF_REQUIRE((fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) != -1); 77 ATF_REQUIRE(getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sendspace, 78 &slen) == 0); 79 ATF_REQUIRE(getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &recvspace, 80 &slen) == 0); 81 82 /* Check the expected size of reply on a single RTM_GETLINK. */ 83 ATF_REQUIRE(send(fd, &hdr, sizeof(hdr), 0) == sizeof(hdr)); 84 ATF_REQUIRE(recv(fd, buf, sizeof(hdr), MSG_WAITALL | MSG_PEEK) == 85 sizeof(hdr)); 86 ATF_REQUIRE(ioctl(fd, FIONREAD, &rsize) != -1); 87 88 89 /* 90 * Flood the socket with requests, without reading out the replies. 91 * While we are flooding, the kernel tries to process the requests. 92 * Kernel takes off requests from the send buffer and puts replies 93 * on receive buffer. Once the receive buffer is full it stops working 94 * on queue in the send buffer. At this point we must get a solid 95 * failure. However, if we flood faster than kernel taskqueue runs, 96 * we may get intermittent failures. 97 */ 98 do { 99 ssize_t rv; 100 101 rv = send(fd, &hdr, sizeof(hdr), MSG_DONTWAIT); 102 if (__predict_true(rv == sizeof(hdr))) 103 cnt++; 104 else { 105 ATF_REQUIRE(errno == EAGAIN); 106 ATF_REQUIRE(sizeof(hdr) * cnt > sendspace); 107 } 108 ATF_REQUIRE(ioctl(fd, FIONREAD, &recvavail) != -1); 109 ATF_REQUIRE(ioctl(fd, FIONWRITE, &sendavail) != -1); 110 } while (recvavail <= recvspace - rsize || 111 sendavail <= sendspace - sizeof(hdr)); 112 113 return (fd); 114 } 115 116 ATF_TC_WITHOUT_HEAD(overflow); 117 ATF_TC_BODY(overflow, tc) 118 { 119 char buf[BUFLEN]; 120 int fd; 121 122 fd = fullsocket(); 123 124 /* Both buffers full: block. */ 125 timer_done = 0; 126 ATF_REQUIRE(sigaction(SIGALRM, &sigact, NULL) == 0); 127 ATF_REQUIRE(setitimer(ITIMER_REAL, &itv, NULL) == 0); 128 ATF_REQUIRE(send(fd, &hdr, sizeof(hdr), 0) == -1); 129 ATF_REQUIRE(errno == EINTR); 130 ATF_REQUIRE(timer_done == 1); 131 132 /* 133 * Now, reading something from the receive buffer should wake up the 134 * taskqueue and send buffer should start getting drained. 135 */ 136 ATF_REQUIRE(recv(fd, buf, BUFLEN, 0) > sizeof(hdr)); 137 timer_done = 0; 138 ATF_REQUIRE(setitimer(ITIMER_REAL, &itv, NULL) == 0); 139 ATF_REQUIRE(send(fd, &hdr, sizeof(hdr), 0) == sizeof(hdr)); 140 ATF_REQUIRE(timer_done == 0); 141 } 142 143 ATF_TC_WITHOUT_HEAD(peek); 144 ATF_TC_BODY(peek, tc) 145 { 146 char *buf; 147 ssize_t ss, ss1; 148 int fd; 149 150 ATF_REQUIRE((fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) != -1); 151 152 ATF_REQUIRE(send(fd, &hdr, sizeof(hdr), 0) == sizeof(hdr)); 153 ss = recv(fd, buf, 0, MSG_WAITALL | MSG_PEEK | MSG_TRUNC); 154 ATF_REQUIRE((buf = malloc(ss)) != NULL); 155 ATF_REQUIRE(recv(fd, buf, ss, MSG_WAITALL) == ss); 156 } 157 158 struct nl_control { 159 struct nlattr nla; 160 uint32_t val; 161 }; 162 163 static void 164 cmsg_check(struct msghdr *msg) 165 { 166 static pid_t pid = 0; 167 struct cmsghdr *cmsg; 168 struct nl_control *nlc; 169 170 ATF_REQUIRE((cmsg = CMSG_FIRSTHDR(msg)) != NULL); 171 ATF_REQUIRE(cmsg->cmsg_level == SOL_NETLINK); 172 ATF_REQUIRE(cmsg->cmsg_type == NETLINK_MSG_INFO); 173 nlc = (struct nl_control *)CMSG_DATA(cmsg); 174 ATF_REQUIRE(nlc[0].nla.nla_type == NLMSGINFO_ATTR_PROCESS_ID); 175 if (pid == 0) 176 pid = getpid(); 177 ATF_REQUIRE(nlc[0].val == pid); 178 ATF_REQUIRE(nlc[1].nla.nla_type == NLMSGINFO_ATTR_PORT_ID); 179 /* XXX need another test to test port id */ 180 ATF_REQUIRE(nlc[1].val == 0); 181 ATF_REQUIRE(CMSG_NXTHDR(msg, cmsg) == NULL); 182 ATF_REQUIRE((msg->msg_flags & MSG_CTRUNC) == 0); 183 } 184 185 ATF_TC_WITHOUT_HEAD(sizes); 186 ATF_TC_BODY(sizes, tc) 187 { 188 #define NLMSG_LARGE 2048 /* XXX: match kernel nl_buf */ 189 char buf[NLMSG_LARGE * 10]; 190 char cbuf[CMSG_SPACE(sizeof(struct nl_control) * 2)]; 191 struct iovec iov; 192 struct msghdr msg = { 193 .msg_iov = &iov, 194 .msg_iovlen = 1, 195 .msg_control = cbuf, 196 .msg_controllen = sizeof(cbuf), 197 }; 198 ssize_t ss; 199 int fd, size, rsize; 200 201 fd = fullsocket(); 202 203 /* 204 * Set NETLINK_MSG_INFO, so that later cmsg_check will check that any 205 * read is accompanied with control data. 206 */ 207 ATF_REQUIRE(setsockopt(fd, SOL_NETLINK, NETLINK_MSG_INFO, 208 &(int){1}, sizeof(int)) == 0); 209 210 iov = (struct iovec ){ 211 .iov_base = &hdr, 212 .iov_len = sizeof(hdr), 213 }; 214 /* Obtain size of the first message in the socket. */ 215 ss = recvmsg(fd, &msg, MSG_WAITALL | MSG_PEEK | MSG_TRUNC); 216 ATF_REQUIRE(ss == hdr.nlmsg_len); 217 /* And overall amount of data in the socket. */ 218 ATF_REQUIRE(ioctl(fd, FIONREAD, &rsize) != -1); 219 cmsg_check(&msg); 220 221 /* Zero-sized read should not affect state of the socket buffer. */ 222 ATF_REQUIRE(recv(fd, buf, 0, 0) == 0); 223 ATF_REQUIRE(ioctl(fd, FIONREAD, &size) != -1); 224 ATF_REQUIRE(size == rsize); 225 226 /* 227 * Undersized read should lose a message. This isn't exactly 228 * pronounced in the Netlink RFC, but it always says that Netlink 229 * socket is an analog of the BSD routing socket, and this is how 230 * a route(4) socket deals with undersized read. 231 */ 232 iov = (struct iovec ){ 233 .iov_base = buf, 234 .iov_len = sizeof(hdr), 235 }; 236 ATF_REQUIRE(recvmsg(fd, &msg, 0) == sizeof(hdr)); 237 ATF_REQUIRE(msg.msg_flags & MSG_TRUNC); 238 ATF_REQUIRE(hdr.nlmsg_len > sizeof(hdr)); 239 size = rsize - hdr.nlmsg_len; 240 ATF_REQUIRE(ioctl(fd, FIONREAD, &rsize) != -1); 241 ATF_REQUIRE(size == rsize); 242 cmsg_check(&msg); 243 244 /* 245 * Large read should span several nl_bufs, seeing no boundaries. 246 */ 247 iov = (struct iovec ){ 248 .iov_base = buf, 249 .iov_len = sizeof(buf) < rsize ? sizeof(buf) : rsize, 250 }; 251 ss = recvmsg(fd, &msg, 0); 252 ATF_REQUIRE(ss > NLMSG_LARGE * 9 || ss == rsize); 253 cmsg_check(&msg); 254 } 255 256 ATF_TP_ADD_TCS(tp) 257 { 258 if (modfind("netlink") == -1) 259 atf_tc_skip("netlink module not loaded"); 260 261 ATF_TP_ADD_TC(tp, overflow); 262 ATF_TP_ADD_TC(tp, peek); 263 ATF_TP_ADD_TC(tp, sizes); 264 265 return (atf_no_error()); 266 } 267