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