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