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 <netinet/in.h>
43 #include <arpa/inet.h>
44
45 #include <atf-c.h>
46
47 static struct itimerval itv = {
48 .it_interval = { 0, 0 },
49 .it_value = { 1, 0 }, /* one second */
50 };
51 static sig_atomic_t timer_done = 0;
52 static void
sigalarm(int sig __unused)53 sigalarm(int sig __unused)
54 {
55
56 timer_done = 1;
57 }
58
59 static struct sigaction sigact = {
60 .sa_handler = sigalarm,
61 };
62
63 static struct nlmsghdr hdr = (struct nlmsghdr) {
64 .nlmsg_type = RTM_GETLINK,
65 .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
66 .nlmsg_len = sizeof(struct nlmsghdr),
67 };
68
69 #define BUFLEN 1000
70
71 static int
fullsocket(void)72 fullsocket(void)
73 {
74 char buf[BUFLEN];
75 socklen_t slen = sizeof(int);
76 int fd, sendspace, recvspace, sendavail, recvavail, rsize;
77 u_int cnt = 0;
78
79 ATF_REQUIRE((fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) != -1);
80 ATF_REQUIRE(getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sendspace,
81 &slen) == 0);
82 ATF_REQUIRE(getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &recvspace,
83 &slen) == 0);
84
85 /* Check the expected size of reply on a single RTM_GETLINK. */
86 ATF_REQUIRE(send(fd, &hdr, sizeof(hdr), 0) == sizeof(hdr));
87 ATF_REQUIRE(recv(fd, buf, sizeof(hdr), MSG_WAITALL | MSG_PEEK) ==
88 sizeof(hdr));
89 ATF_REQUIRE(ioctl(fd, FIONREAD, &rsize) != -1);
90
91
92 /*
93 * Flood the socket with requests, without reading out the replies.
94 * While we are flooding, the kernel tries to process the requests.
95 * Kernel takes off requests from the send buffer and puts replies
96 * on receive buffer. Once the receive buffer is full it stops working
97 * on queue in the send buffer. At this point we must get a solid
98 * failure. However, if we flood faster than kernel taskqueue runs,
99 * we may get intermittent failures.
100 */
101 do {
102 ssize_t rv;
103
104 rv = send(fd, &hdr, sizeof(hdr), MSG_DONTWAIT);
105 if (__predict_true(rv == sizeof(hdr)))
106 cnt++;
107 else {
108 ATF_REQUIRE(errno == EAGAIN);
109 ATF_REQUIRE(sizeof(hdr) * cnt > sendspace);
110 }
111 ATF_REQUIRE(ioctl(fd, FIONREAD, &recvavail) != -1);
112 ATF_REQUIRE(ioctl(fd, FIONWRITE, &sendavail) != -1);
113 } while (recvavail <= recvspace - rsize ||
114 sendavail <= sendspace - sizeof(hdr));
115
116 return (fd);
117 }
118
119 ATF_TC_WITHOUT_HEAD(overflow);
ATF_TC_BODY(overflow,tc)120 ATF_TC_BODY(overflow, tc)
121 {
122 char buf[BUFLEN];
123 int fd;
124
125 fd = fullsocket();
126
127 /* Both buffers full: block. */
128 timer_done = 0;
129 ATF_REQUIRE(sigaction(SIGALRM, &sigact, NULL) == 0);
130 ATF_REQUIRE(setitimer(ITIMER_REAL, &itv, NULL) == 0);
131 ATF_REQUIRE(send(fd, &hdr, sizeof(hdr), 0) == -1);
132 ATF_REQUIRE(errno == EINTR);
133 ATF_REQUIRE(timer_done == 1);
134
135 /*
136 * Now, reading something from the receive buffer should wake up the
137 * taskqueue and send buffer should start getting drained.
138 */
139 ATF_REQUIRE(recv(fd, buf, BUFLEN, 0) > sizeof(hdr));
140 timer_done = 0;
141 ATF_REQUIRE(setitimer(ITIMER_REAL, &itv, NULL) == 0);
142 ATF_REQUIRE(send(fd, &hdr, sizeof(hdr), 0) == sizeof(hdr));
143 ATF_REQUIRE(timer_done == 0);
144 }
145
146 ATF_TC_WITHOUT_HEAD(peek);
ATF_TC_BODY(peek,tc)147 ATF_TC_BODY(peek, tc)
148 {
149 char *buf;
150 ssize_t ss, ss1;
151 int fd;
152
153 ATF_REQUIRE((fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) != -1);
154
155 ATF_REQUIRE(send(fd, &hdr, sizeof(hdr), 0) == sizeof(hdr));
156 ss = recv(fd, buf, 0, MSG_WAITALL | MSG_PEEK | MSG_TRUNC);
157 ATF_REQUIRE((buf = malloc(ss)) != NULL);
158 ATF_REQUIRE(recv(fd, buf, ss, MSG_WAITALL) == ss);
159 }
160
161 struct nl_control {
162 struct nlattr nla;
163 uint32_t val;
164 };
165
166 static void
cmsg_check(struct msghdr * msg)167 cmsg_check(struct msghdr *msg)
168 {
169 static pid_t pid = 0;
170 struct cmsghdr *cmsg;
171 struct nl_control *nlc;
172
173 ATF_REQUIRE((cmsg = CMSG_FIRSTHDR(msg)) != NULL);
174 ATF_REQUIRE(cmsg->cmsg_level == SOL_NETLINK);
175 ATF_REQUIRE(cmsg->cmsg_type == NETLINK_MSG_INFO);
176 nlc = (struct nl_control *)CMSG_DATA(cmsg);
177 ATF_REQUIRE(nlc[0].nla.nla_type == NLMSGINFO_ATTR_PROCESS_ID);
178 if (pid == 0)
179 pid = getpid();
180 ATF_REQUIRE(nlc[0].val == pid);
181 ATF_REQUIRE(nlc[1].nla.nla_type == NLMSGINFO_ATTR_PORT_ID);
182 /* XXX need another test to test port id */
183 ATF_REQUIRE(nlc[1].val == 0);
184 ATF_REQUIRE(CMSG_NXTHDR(msg, cmsg) == NULL);
185 ATF_REQUIRE((msg->msg_flags & MSG_CTRUNC) == 0);
186 }
187
188 ATF_TC_WITHOUT_HEAD(sizes);
ATF_TC_BODY(sizes,tc)189 ATF_TC_BODY(sizes, tc)
190 {
191 #define NLMSG_LARGE 2048 /* XXX: match kernel nl_buf */
192 char buf[NLMSG_LARGE * 10];
193 char cbuf[CMSG_SPACE(sizeof(struct nl_control) * 2)];
194 struct iovec iov;
195 struct msghdr msg = {
196 .msg_iov = &iov,
197 .msg_iovlen = 1,
198 .msg_control = cbuf,
199 .msg_controllen = sizeof(cbuf),
200 };
201 ssize_t ss;
202 int fd, size, rsize;
203
204 fd = fullsocket();
205
206 /*
207 * Set NETLINK_MSG_INFO, so that later cmsg_check will check that any
208 * read is accompanied with control data.
209 */
210 ATF_REQUIRE(setsockopt(fd, SOL_NETLINK, NETLINK_MSG_INFO,
211 &(int){1}, sizeof(int)) == 0);
212
213 iov = (struct iovec ){
214 .iov_base = &hdr,
215 .iov_len = sizeof(hdr),
216 };
217 /* Obtain size of the first message in the socket. */
218 ss = recvmsg(fd, &msg, MSG_WAITALL | MSG_PEEK | MSG_TRUNC);
219 ATF_REQUIRE(ss == hdr.nlmsg_len);
220 /* And overall amount of data in the socket. */
221 ATF_REQUIRE(ioctl(fd, FIONREAD, &rsize) != -1);
222 cmsg_check(&msg);
223
224 /* Zero-sized read should not affect state of the socket buffer. */
225 ATF_REQUIRE(recv(fd, buf, 0, 0) == 0);
226 ATF_REQUIRE(ioctl(fd, FIONREAD, &size) != -1);
227 ATF_REQUIRE(size == rsize);
228
229 /*
230 * Undersized read should lose a message. This isn't exactly
231 * pronounced in the Netlink RFC, but it always says that Netlink
232 * socket is an analog of the BSD routing socket, and this is how
233 * a route(4) socket deals with undersized read.
234 */
235 iov = (struct iovec ){
236 .iov_base = buf,
237 .iov_len = sizeof(hdr),
238 };
239 ATF_REQUIRE(recvmsg(fd, &msg, 0) == sizeof(hdr));
240 ATF_REQUIRE(msg.msg_flags & MSG_TRUNC);
241 ATF_REQUIRE(hdr.nlmsg_len > sizeof(hdr));
242 size = rsize - hdr.nlmsg_len;
243 ATF_REQUIRE(ioctl(fd, FIONREAD, &rsize) != -1);
244 ATF_REQUIRE(size == rsize);
245 cmsg_check(&msg);
246
247 /*
248 * Large read should span several nl_bufs, seeing no boundaries.
249 */
250 iov = (struct iovec ){
251 .iov_base = buf,
252 .iov_len = sizeof(buf) < rsize ? sizeof(buf) : rsize,
253 };
254 ss = recvmsg(fd, &msg, 0);
255 ATF_REQUIRE(ss > NLMSG_LARGE * 9 || ss == rsize);
256 cmsg_check(&msg);
257 }
258
259 static struct nlattr *
nla_RTA_DST(struct nlattr * start,ssize_t len)260 nla_RTA_DST(struct nlattr *start, ssize_t len)
261 {
262 struct nlattr *nla;
263
264 for (nla = start; (char *)nla < (char *)start + len;
265 nla = (struct nlattr *)((char *)nla + NLA_ALIGN(nla->nla_len))) {
266 if (nla->nla_type == RTA_DST)
267 return (nla);
268 }
269
270 return (NULL);
271 }
272 /*
273 * Check that NETLINK_ADD_MEMBERSHIP subscribes us. Add & delete a temporary
274 * route and check if announcements came in.
275 */
276 ATF_TC_WITHOUT_HEAD(membership);
ATF_TC_BODY(membership,tc)277 ATF_TC_BODY(membership, tc)
278 {
279 struct {
280 struct nlmsghdr hdr;
281 struct rtmsg rtm;
282 struct nlattr rta_dst;
283 struct in_addr dst;
284 struct nlattr rta_oif;
285 uint32_t oif;
286 } reply, msg = {
287 .hdr.nlmsg_type = RTM_NEWROUTE,
288 .hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL,
289 .hdr.nlmsg_len = sizeof(msg),
290 .rtm.rtm_family = AF_INET,
291 .rtm.rtm_protocol = RTPROT_STATIC,
292 .rtm.rtm_type = RTN_UNICAST,
293 .rtm.rtm_dst_len = 32,
294 .rta_dst.nla_type = RTA_DST,
295 .rta_dst.nla_len = sizeof(struct in_addr) +
296 sizeof(struct nlattr),
297 .dst.s_addr = inet_addr("127.0.0.127"),
298 .rta_oif.nla_type = RTA_OIF,
299 .rta_oif.nla_len = sizeof(uint32_t) + sizeof(struct nlattr),
300 .oif = 1,
301 };
302 struct nlattr *nla;
303 int fd;
304
305 ATF_REQUIRE((fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) != -1);
306 ATF_REQUIRE(setsockopt(fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP,
307 &(int){RTNLGRP_IPV4_ROUTE}, sizeof(int)) == 0);
308
309 ATF_REQUIRE(send(fd, &msg, sizeof(msg), 0) == sizeof(msg));
310 ATF_REQUIRE(recv(fd, &reply, sizeof(reply), 0) == sizeof(reply));
311 ATF_REQUIRE(reply.hdr.nlmsg_type == msg.hdr.nlmsg_type);
312 ATF_REQUIRE(reply.rtm.rtm_type == msg.rtm.rtm_type);
313 ATF_REQUIRE(reply.rtm.rtm_dst_len == msg.rtm.rtm_dst_len);
314 ATF_REQUIRE(nla = nla_RTA_DST(&reply.rta_dst, sizeof(reply)));
315 ATF_REQUIRE(memcmp(&msg.dst, (char *)nla + sizeof(struct nlattr),
316 sizeof(struct in_addr)) == 0);
317
318 msg.hdr.nlmsg_type = RTM_DELROUTE;
319 msg.hdr.nlmsg_len -= sizeof(struct nlattr) + sizeof(uint32_t);
320 ATF_REQUIRE(send(fd, &msg, msg.hdr.nlmsg_len, 0) == msg.hdr.nlmsg_len);
321 ATF_REQUIRE(recv(fd, &reply, sizeof(reply), 0) == sizeof(reply));
322 ATF_REQUIRE(reply.hdr.nlmsg_type == msg.hdr.nlmsg_type);
323 ATF_REQUIRE(reply.rtm.rtm_type == msg.rtm.rtm_type);
324 ATF_REQUIRE(reply.rtm.rtm_dst_len == msg.rtm.rtm_dst_len);
325 ATF_REQUIRE(nla = nla_RTA_DST(&reply.rta_dst, sizeof(reply)));
326 ATF_REQUIRE(memcmp(&msg.dst, (char *)nla + sizeof(struct nlattr),
327 sizeof(struct in_addr)) == 0);
328 }
329
ATF_TP_ADD_TCS(tp)330 ATF_TP_ADD_TCS(tp)
331 {
332 if (modfind("netlink") == -1)
333 atf_tc_skip("netlink module not loaded");
334
335 ATF_TP_ADD_TC(tp, overflow);
336 ATF_TP_ADD_TC(tp, peek);
337 ATF_TP_ADD_TC(tp, sizes);
338 ATF_TP_ADD_TC(tp, membership);
339
340 return (atf_no_error());
341 }
342