xref: /netbsd-src/tests/net/bpf/t_bpf.c (revision 6c259f3957f89c11609ed3fdf8d0040e66d0ae42)
1 /*	$NetBSD: t_bpf.c,v 1.9 2022/09/10 12:14:18 rillig Exp $	*/
2 
3 /*-
4  * Copyright (c) 2010 Antti Kantee.  All Rights Reserved.
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 ``AS IS'' AND ANY EXPRESS
16  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18  * 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 OR
21  * 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 #include <sys/cdefs.h>
28 __RCSID("$NetBSD: t_bpf.c,v 1.9 2022/09/10 12:14:18 rillig Exp $");
29 
30 #include <sys/param.h>
31 #include <sys/ioctl.h>
32 #include <sys/socket.h>
33 #include <sys/mbuf.h>
34 #include <sys/sysctl.h>
35 #include <sys/mman.h>
36 #include <unistd.h>
37 
38 #include <net/if.h>
39 #include <net/bpf.h>
40 #include <net/dlt.h>
41 
42 #include <fcntl.h>
43 #include <stdio.h>
44 #include <string.h>
45 
46 #include <rump/rump.h>
47 #include <rump/rump_syscalls.h>
48 
49 /* XXX: atf-c.h has collisions with mbuf */
50 #undef m_type
51 #undef m_data
52 #include <atf-c.h>
53 
54 #include "h_macros.h"
55 #include "../config/netconfig.c"
56 
57 ATF_TC(bpfwriteleak);
ATF_TC_HEAD(bpfwriteleak,tc)58 ATF_TC_HEAD(bpfwriteleak, tc)
59 {
60 
61 	atf_tc_set_md_var(tc, "descr", "Checks that writing to /dev/bpf "
62 	    "does not leak mbufs");
63 }
64 
65 static int
getmtdata(void)66 getmtdata(void)
67 {
68 	struct mbstat mbstat;
69 	size_t mbstatlen = sizeof(mbstat);
70 	const int mbstat_mib[] = { CTL_KERN, KERN_MBUF, MBUF_STATS };
71 
72 	RL(rump_sys___sysctl(mbstat_mib, __arraycount(mbstat_mib),
73 	    &mbstat, &mbstatlen, NULL, 0));
74 	return mbstat.m_mtypes[MT_DATA];
75 }
76 
ATF_TC_BODY(bpfwriteleak,tc)77 ATF_TC_BODY(bpfwriteleak, tc)
78 {
79 	char buf[28]; /* sizeof(garbage) > etherhdrlen */
80 	struct ifreq ifr;
81 	int ifnum, bpfd;
82 
83 	RZ(rump_init());
84 	RZ(rump_pub_shmif_create(NULL, &ifnum));
85 	sprintf(ifr.ifr_name, "shmif%d", ifnum);
86 
87 	RL(bpfd = rump_sys_open("/dev/bpf", O_RDWR));
88 	RL(rump_sys_ioctl(bpfd, BIOCSETIF, &ifr));
89 	RL(rump_sys_ioctl(bpfd, BIOCSFEEDBACK, &ifr));
90 
91 	if (getmtdata() != 0)
92 		atf_tc_fail("test precondition failed: MT_DATA mbufs != 0");
93 
94 	ATF_REQUIRE_ERRNO(ENETDOWN, rump_sys_write(bpfd, buf, sizeof(buf))==-1);
95 
96 	ATF_REQUIRE_EQ(getmtdata(), 0);
97 }
98 
99 #if (SIZE_MAX > UINT_MAX)
100 ATF_TC(bpfwritetrunc);
ATF_TC_HEAD(bpfwritetrunc,tc)101 ATF_TC_HEAD(bpfwritetrunc, tc)
102 {
103 	atf_tc_set_md_var(tc, "descr", "Checks that write to /dev/bpf "
104 	    "does not truncate size_t to int");
105 }
106 
ATF_TC_BODY(bpfwritetrunc,tc)107 ATF_TC_BODY(bpfwritetrunc, tc)
108 {
109 	int bpfd;
110 	struct ifreq ifr;
111 	struct iovec *iov;
112 	size_t iovlen, sz;
113 	const size_t extra_bytes = 28;
114 	const size_t total = extra_bytes + UINT_MAX + 1;
115 	long iov_max, vm_page_size; /* round_page wants vm_page_size variable */
116 
117 	memset(&ifr, 0, sizeof(ifr));
118 
119 	iov_max      = sysconf(_SC_IOV_MAX);
120 	vm_page_size = sysconf(_SC_PAGE_SIZE);
121 	ATF_REQUIRE(iov_max > 1 && vm_page_size > 1);
122 
123 	/*
124 	 * Minimize memory consumption by using many iovecs
125 	 * all pointing to one memory region.
126 	 */
127 	iov = calloc(iov_max, sizeof(struct iovec));
128 	ATF_REQUIRE(iov != NULL);
129 
130 	sz = round_page((total + (iov_max - 1)) / iov_max);
131 
132 	iov[0].iov_len = sz;
133 	iov[0].iov_base = mmap(NULL, sz, PROT_READ, MAP_ANON, -1, 0);
134 	ATF_REQUIRE(iov[0].iov_base != MAP_FAILED);
135 
136 	iovlen = 1;
137 	while (sz + iov[0].iov_len <= total)
138 	{
139 		iov[iovlen].iov_len  = iov[0].iov_len;
140 		iov[iovlen].iov_base = iov[0].iov_base;
141 		sz += iov[0].iov_len;
142 		iovlen++;
143 	}
144 
145 	if (sz < total)
146 	{
147 		iov[iovlen].iov_len = total - sz;
148 		iov[iovlen].iov_base = iov[0].iov_base;
149 		iovlen++;
150 	}
151 
152 	/* Sanity checks */
153 	ATF_REQUIRE(iovlen >= 1 && iovlen <= (size_t)iov_max);
154 	ATF_REQUIRE_EQ(iov[iovlen-1].iov_len, total % iov[0].iov_len);
155 
156 	RZ(rump_init());
157 	netcfg_rump_makeshmif("bpfwritetrunc", ifr.ifr_name);
158 	netcfg_rump_if(ifr.ifr_name, "10.1.1.1", "255.0.0.0");
159 
160 	RL(bpfd = rump_sys_open("/dev/bpf", O_RDWR));
161 	RL(rump_sys_ioctl(bpfd, BIOCSETIF, &ifr));
162 
163 	ATF_CHECK_ERRNO(EMSGSIZE, rump_sys_writev(bpfd, iov, iovlen) == -1);
164 
165 	munmap(iov[0].iov_base, iov[0].iov_len);
166 	free(iov);
167 }
168 #endif /* #if (SIZE_MAX > UINT_MAX) */
169 
170 ATF_TC(bpf_ioctl_BLEN);
ATF_TC_HEAD(bpf_ioctl_BLEN,tc)171 ATF_TC_HEAD(bpf_ioctl_BLEN, tc)
172 {
173 
174 	atf_tc_set_md_var(tc, "descr", "Checks behaviors of BIOCGBLEN and "
175 	    "BIOCSBLEN");
176 }
177 
ATF_TC_BODY(bpf_ioctl_BLEN,tc)178 ATF_TC_BODY(bpf_ioctl_BLEN, tc)
179 {
180 	struct ifreq ifr;
181 	int ifnum, bpfd;
182 	u_int blen = 0;
183 
184 	RZ(rump_init());
185 	RZ(rump_pub_shmif_create(NULL, &ifnum));
186 	sprintf(ifr.ifr_name, "shmif%d", ifnum);
187 
188 	RL(bpfd = rump_sys_open("/dev/bpf", O_RDWR));
189 
190 	RL(rump_sys_ioctl(bpfd, BIOCGBLEN, &blen));
191 	ATF_REQUIRE(blen != 0);
192 	blen = 100;
193 	RL(rump_sys_ioctl(bpfd, BIOCSBLEN, &blen));
194 	RL(rump_sys_ioctl(bpfd, BIOCGBLEN, &blen));
195 	ATF_REQUIRE_EQ(blen, 100);
196 
197 	RL(rump_sys_ioctl(bpfd, BIOCSETIF, &ifr));
198 
199 	ATF_REQUIRE_EQ_MSG(rump_sys_ioctl(bpfd, BIOCSBLEN, &blen), -1,
200 	    "Don't allow to change buflen after binding bpf to an interface");
201 }
202 
203 ATF_TC(bpf_ioctl_PROMISC);
ATF_TC_HEAD(bpf_ioctl_PROMISC,tc)204 ATF_TC_HEAD(bpf_ioctl_PROMISC, tc)
205 {
206 
207 	atf_tc_set_md_var(tc, "descr", "Checks behaviors of BIOCPROMISC");
208 }
209 
ATF_TC_BODY(bpf_ioctl_PROMISC,tc)210 ATF_TC_BODY(bpf_ioctl_PROMISC, tc)
211 {
212 	struct ifreq ifr;
213 	int ifnum, bpfd;
214 
215 	RZ(rump_init());
216 	RZ(rump_pub_shmif_create(NULL, &ifnum));
217 	sprintf(ifr.ifr_name, "shmif%d", ifnum);
218 
219 	RL(bpfd = rump_sys_open("/dev/bpf", O_RDWR));
220 
221 	ATF_REQUIRE_EQ_MSG(rump_sys_ioctl(bpfd, BIOCPROMISC, NULL), -1,
222 	    "Don't allow to call ioctl(BIOCPROMISC) without interface");
223 
224 	RL(rump_sys_ioctl(bpfd, BIOCSETIF, &ifr));
225 
226 	RL(rump_sys_ioctl(bpfd, BIOCPROMISC, NULL));
227 	/* TODO check if_flags */
228 }
229 
230 ATF_TC(bpf_ioctl_SETIF);
ATF_TC_HEAD(bpf_ioctl_SETIF,tc)231 ATF_TC_HEAD(bpf_ioctl_SETIF, tc)
232 {
233 
234 	atf_tc_set_md_var(tc, "descr", "Checks behaviors of BIOCSETIF");
235 }
236 
ATF_TC_BODY(bpf_ioctl_SETIF,tc)237 ATF_TC_BODY(bpf_ioctl_SETIF, tc)
238 {
239 	struct ifreq ifr;
240 	int ifnum, bpfd;
241 
242 	RZ(rump_init());
243 
244 	RL(bpfd = rump_sys_open("/dev/bpf", O_RDWR));
245 
246 	RZ(rump_pub_shmif_create(NULL, &ifnum));
247 	sprintf(ifr.ifr_name, "shmif%d", ifnum);
248 	RL(rump_sys_ioctl(bpfd, BIOCSETIF, &ifr));
249 
250 	/* Change the listening interface */
251 	RZ(rump_pub_shmif_create(NULL, &ifnum));
252 	sprintf(ifr.ifr_name, "shmif%d", ifnum);
253 	RL(rump_sys_ioctl(bpfd, BIOCSETIF, &ifr));
254 }
255 
256 ATF_TC(bpf_ioctl_DLT);
ATF_TC_HEAD(bpf_ioctl_DLT,tc)257 ATF_TC_HEAD(bpf_ioctl_DLT, tc)
258 {
259 
260 	atf_tc_set_md_var(tc, "descr", "Checks behaviors of BIOCGDLT and "
261 	    "BIOCSDLT");
262 }
263 
ATF_TC_BODY(bpf_ioctl_DLT,tc)264 ATF_TC_BODY(bpf_ioctl_DLT, tc)
265 {
266 	struct ifreq ifr;
267 	int ifnum, bpfd;
268 	u_int dlt;
269 
270 	RZ(rump_init());
271 	RL(bpfd = rump_sys_open("/dev/bpf", O_RDWR));
272 	RZ(rump_pub_shmif_create(NULL, &ifnum));
273 	sprintf(ifr.ifr_name, "shmif%d", ifnum);
274 
275 	ATF_REQUIRE_EQ_MSG(rump_sys_ioctl(bpfd, BIOCGDLT, &dlt), -1,
276 	    "Don't allow to get a DLT without interfaces");
277 
278 	RL(rump_sys_ioctl(bpfd, BIOCSETIF, &ifr));
279 
280 	RL(rump_sys_ioctl(bpfd, BIOCGDLT, &dlt));
281 	ATF_REQUIRE(dlt == DLT_EN10MB);
282 
283 	dlt = DLT_NULL;
284 	ATF_REQUIRE_EQ_MSG(rump_sys_ioctl(bpfd, BIOCSDLT, &dlt), -1,
285 	    "Don't allow to set a DLT that doesn't match any listening "
286 	    "interfaces");
287 }
288 
289 ATF_TC(bpf_ioctl_GDLTLIST);
ATF_TC_HEAD(bpf_ioctl_GDLTLIST,tc)290 ATF_TC_HEAD(bpf_ioctl_GDLTLIST, tc)
291 {
292 
293 	atf_tc_set_md_var(tc, "descr", "Checks behaviors of BIOCGDLTLIST");
294 }
295 
ATF_TC_BODY(bpf_ioctl_GDLTLIST,tc)296 ATF_TC_BODY(bpf_ioctl_GDLTLIST, tc)
297 {
298 	struct ifreq ifr;
299 	int ifnum, bpfd;
300 	struct bpf_dltlist dltlist;
301 
302 	RZ(rump_init());
303 	RL(bpfd = rump_sys_open("/dev/bpf", O_RDWR));
304 	RZ(rump_pub_shmif_create(NULL, &ifnum));
305 	sprintf(ifr.ifr_name, "shmif%d", ifnum);
306 
307 	dltlist.bfl_len = 0;
308 	dltlist.bfl_list = NULL;
309 	ATF_REQUIRE_EQ_MSG(rump_sys_ioctl(bpfd, BIOCGDLTLIST, &dltlist), -1,
310 	    "Don't allow to get a DLT list without interfaces");
311 
312 	RL(rump_sys_ioctl(bpfd, BIOCSETIF, &ifr));
313 
314 	/* Get the size of an available DLT list */
315 	dltlist.bfl_len = 0;
316 	dltlist.bfl_list = NULL;
317 	RL(rump_sys_ioctl(bpfd, BIOCGDLTLIST, &dltlist));
318 	ATF_REQUIRE(dltlist.bfl_len == 1);
319 
320 	/* Get an available DLT list */
321 	dltlist.bfl_list = calloc(sizeof(u_int), 1);
322 	dltlist.bfl_len = 1;
323 	RL(rump_sys_ioctl(bpfd, BIOCGDLTLIST, &dltlist));
324 	ATF_REQUIRE(dltlist.bfl_len == 1);
325 	ATF_REQUIRE(dltlist.bfl_list[0] == DLT_EN10MB);
326 
327 	/* Get an available DLT list with a less buffer (fake with bfl_len) */
328 	dltlist.bfl_len = 0;
329 	ATF_REQUIRE_EQ_MSG(rump_sys_ioctl(bpfd, BIOCGDLTLIST, &dltlist), -1,
330 	    "This should fail with ENOMEM");
331 
332 	free(dltlist.bfl_list);
333 }
334 
ATF_TP_ADD_TCS(tp)335 ATF_TP_ADD_TCS(tp)
336 {
337 
338 	ATF_TP_ADD_TC(tp, bpfwriteleak);
339 #if (SIZE_MAX > UINT_MAX)
340 	ATF_TP_ADD_TC(tp, bpfwritetrunc);
341 #endif
342 	ATF_TP_ADD_TC(tp, bpf_ioctl_BLEN);
343 	ATF_TP_ADD_TC(tp, bpf_ioctl_PROMISC);
344 	ATF_TP_ADD_TC(tp, bpf_ioctl_SETIF);
345 	ATF_TP_ADD_TC(tp, bpf_ioctl_DLT);
346 	ATF_TP_ADD_TC(tp, bpf_ioctl_GDLTLIST);
347 	return atf_no_error();
348 }
349