1*6c259f39Srillig /* $NetBSD: t_bpf.c,v 1.9 2022/09/10 12:14:18 rillig Exp $ */
21a21107aSpooka
31a21107aSpooka /*-
41a21107aSpooka * Copyright (c) 2010 Antti Kantee. All Rights Reserved.
51a21107aSpooka *
61a21107aSpooka * Redistribution and use in source and binary forms, with or without
71a21107aSpooka * modification, are permitted provided that the following conditions
81a21107aSpooka * are met:
91a21107aSpooka * 1. Redistributions of source code must retain the above copyright
101a21107aSpooka * notice, this list of conditions and the following disclaimer.
111a21107aSpooka * 2. Redistributions in binary form must reproduce the above copyright
121a21107aSpooka * notice, this list of conditions and the following disclaimer in the
131a21107aSpooka * documentation and/or other materials provided with the distribution.
141a21107aSpooka *
151a21107aSpooka * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
161a21107aSpooka * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
171a21107aSpooka * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
181a21107aSpooka * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
191a21107aSpooka * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
201a21107aSpooka * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
211a21107aSpooka * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
221a21107aSpooka * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
231a21107aSpooka * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
241a21107aSpooka * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
251a21107aSpooka * SUCH DAMAGE.
261a21107aSpooka */
27a5a1874fSalnsn #include <sys/cdefs.h>
28*6c259f39Srillig __RCSID("$NetBSD: t_bpf.c,v 1.9 2022/09/10 12:14:18 rillig Exp $");
291a21107aSpooka
301a21107aSpooka #include <sys/param.h>
311a21107aSpooka #include <sys/ioctl.h>
321a21107aSpooka #include <sys/socket.h>
331a21107aSpooka #include <sys/mbuf.h>
341a21107aSpooka #include <sys/sysctl.h>
3500a60545Schristos #include <sys/mman.h>
3600a60545Schristos #include <unistd.h>
371a21107aSpooka
381a21107aSpooka #include <net/if.h>
391a21107aSpooka #include <net/bpf.h>
4022c2d28cSozaki-r #include <net/dlt.h>
411a21107aSpooka
421a21107aSpooka #include <fcntl.h>
431a21107aSpooka #include <stdio.h>
441a21107aSpooka #include <string.h>
451a21107aSpooka
461a21107aSpooka #include <rump/rump.h>
471a21107aSpooka #include <rump/rump_syscalls.h>
481a21107aSpooka
491a21107aSpooka /* XXX: atf-c.h has collisions with mbuf */
501a21107aSpooka #undef m_type
511a21107aSpooka #undef m_data
521a21107aSpooka #include <atf-c.h>
531a21107aSpooka
54c54cb811Schristos #include "h_macros.h"
5500a60545Schristos #include "../config/netconfig.c"
561a21107aSpooka
571a21107aSpooka ATF_TC(bpfwriteleak);
ATF_TC_HEAD(bpfwriteleak,tc)581a21107aSpooka ATF_TC_HEAD(bpfwriteleak, tc)
591a21107aSpooka {
601a21107aSpooka
611a21107aSpooka atf_tc_set_md_var(tc, "descr", "Checks that writing to /dev/bpf "
621a21107aSpooka "does not leak mbufs");
631a21107aSpooka }
641a21107aSpooka
651a21107aSpooka static int
getmtdata(void)661a21107aSpooka getmtdata(void)
671a21107aSpooka {
681a21107aSpooka struct mbstat mbstat;
691a21107aSpooka size_t mbstatlen = sizeof(mbstat);
701a21107aSpooka const int mbstat_mib[] = { CTL_KERN, KERN_MBUF, MBUF_STATS };
711a21107aSpooka
721a21107aSpooka RL(rump_sys___sysctl(mbstat_mib, __arraycount(mbstat_mib),
731a21107aSpooka &mbstat, &mbstatlen, NULL, 0));
741a21107aSpooka return mbstat.m_mtypes[MT_DATA];
751a21107aSpooka }
761a21107aSpooka
ATF_TC_BODY(bpfwriteleak,tc)771a21107aSpooka ATF_TC_BODY(bpfwriteleak, tc)
781a21107aSpooka {
791a21107aSpooka char buf[28]; /* sizeof(garbage) > etherhdrlen */
801a21107aSpooka struct ifreq ifr;
811a21107aSpooka int ifnum, bpfd;
821a21107aSpooka
831a21107aSpooka RZ(rump_init());
841a21107aSpooka RZ(rump_pub_shmif_create(NULL, &ifnum));
851a21107aSpooka sprintf(ifr.ifr_name, "shmif%d", ifnum);
861a21107aSpooka
871a21107aSpooka RL(bpfd = rump_sys_open("/dev/bpf", O_RDWR));
881a21107aSpooka RL(rump_sys_ioctl(bpfd, BIOCSETIF, &ifr));
891a21107aSpooka RL(rump_sys_ioctl(bpfd, BIOCSFEEDBACK, &ifr));
901a21107aSpooka
911a21107aSpooka if (getmtdata() != 0)
921a21107aSpooka atf_tc_fail("test precondition failed: MT_DATA mbufs != 0");
931a21107aSpooka
941a21107aSpooka ATF_REQUIRE_ERRNO(ENETDOWN, rump_sys_write(bpfd, buf, sizeof(buf))==-1);
951a21107aSpooka
961a21107aSpooka ATF_REQUIRE_EQ(getmtdata(), 0);
971a21107aSpooka }
981a21107aSpooka
9900a60545Schristos #if (SIZE_MAX > UINT_MAX)
10000a60545Schristos ATF_TC(bpfwritetrunc);
ATF_TC_HEAD(bpfwritetrunc,tc)10100a60545Schristos ATF_TC_HEAD(bpfwritetrunc, tc)
10200a60545Schristos {
10300a60545Schristos atf_tc_set_md_var(tc, "descr", "Checks that write to /dev/bpf "
10400a60545Schristos "does not truncate size_t to int");
10500a60545Schristos }
10600a60545Schristos
ATF_TC_BODY(bpfwritetrunc,tc)10700a60545Schristos ATF_TC_BODY(bpfwritetrunc, tc)
10800a60545Schristos {
10900a60545Schristos int bpfd;
11000a60545Schristos struct ifreq ifr;
11100a60545Schristos struct iovec *iov;
11200a60545Schristos size_t iovlen, sz;
11300a60545Schristos const size_t extra_bytes = 28;
11400a60545Schristos const size_t total = extra_bytes + UINT_MAX + 1;
11500a60545Schristos long iov_max, vm_page_size; /* round_page wants vm_page_size variable */
11600a60545Schristos
11700a60545Schristos memset(&ifr, 0, sizeof(ifr));
11800a60545Schristos
11900a60545Schristos iov_max = sysconf(_SC_IOV_MAX);
12000a60545Schristos vm_page_size = sysconf(_SC_PAGE_SIZE);
12100a60545Schristos ATF_REQUIRE(iov_max > 1 && vm_page_size > 1);
12200a60545Schristos
123a5a1874fSalnsn /*
124a5a1874fSalnsn * Minimize memory consumption by using many iovecs
125a5a1874fSalnsn * all pointing to one memory region.
126a5a1874fSalnsn */
12700a60545Schristos iov = calloc(iov_max, sizeof(struct iovec));
12800a60545Schristos ATF_REQUIRE(iov != NULL);
12900a60545Schristos
13000a60545Schristos sz = round_page((total + (iov_max - 1)) / iov_max);
13100a60545Schristos
13200a60545Schristos iov[0].iov_len = sz;
13300a60545Schristos iov[0].iov_base = mmap(NULL, sz, PROT_READ, MAP_ANON, -1, 0);
13400a60545Schristos ATF_REQUIRE(iov[0].iov_base != MAP_FAILED);
13500a60545Schristos
13600a60545Schristos iovlen = 1;
13700a60545Schristos while (sz + iov[0].iov_len <= total)
13800a60545Schristos {
13900a60545Schristos iov[iovlen].iov_len = iov[0].iov_len;
14000a60545Schristos iov[iovlen].iov_base = iov[0].iov_base;
14100a60545Schristos sz += iov[0].iov_len;
14200a60545Schristos iovlen++;
14300a60545Schristos }
14400a60545Schristos
14500a60545Schristos if (sz < total)
14600a60545Schristos {
14700a60545Schristos iov[iovlen].iov_len = total - sz;
14800a60545Schristos iov[iovlen].iov_base = iov[0].iov_base;
14900a60545Schristos iovlen++;
15000a60545Schristos }
15100a60545Schristos
15200a60545Schristos /* Sanity checks */
15300a60545Schristos ATF_REQUIRE(iovlen >= 1 && iovlen <= (size_t)iov_max);
15400a60545Schristos ATF_REQUIRE_EQ(iov[iovlen-1].iov_len, total % iov[0].iov_len);
15500a60545Schristos
15600a60545Schristos RZ(rump_init());
15700a60545Schristos netcfg_rump_makeshmif("bpfwritetrunc", ifr.ifr_name);
15800a60545Schristos netcfg_rump_if(ifr.ifr_name, "10.1.1.1", "255.0.0.0");
15900a60545Schristos
16000a60545Schristos RL(bpfd = rump_sys_open("/dev/bpf", O_RDWR));
16100a60545Schristos RL(rump_sys_ioctl(bpfd, BIOCSETIF, &ifr));
16200a60545Schristos
16300a60545Schristos ATF_CHECK_ERRNO(EMSGSIZE, rump_sys_writev(bpfd, iov, iovlen) == -1);
16400a60545Schristos
16500a60545Schristos munmap(iov[0].iov_base, iov[0].iov_len);
16600a60545Schristos free(iov);
16700a60545Schristos }
16800a60545Schristos #endif /* #if (SIZE_MAX > UINT_MAX) */
16900a60545Schristos
170b1bee1e6Sozaki-r ATF_TC(bpf_ioctl_BLEN);
ATF_TC_HEAD(bpf_ioctl_BLEN,tc)171b1bee1e6Sozaki-r ATF_TC_HEAD(bpf_ioctl_BLEN, tc)
172b1bee1e6Sozaki-r {
173b1bee1e6Sozaki-r
174b1bee1e6Sozaki-r atf_tc_set_md_var(tc, "descr", "Checks behaviors of BIOCGBLEN and "
175b1bee1e6Sozaki-r "BIOCSBLEN");
176b1bee1e6Sozaki-r }
177b1bee1e6Sozaki-r
ATF_TC_BODY(bpf_ioctl_BLEN,tc)178b1bee1e6Sozaki-r ATF_TC_BODY(bpf_ioctl_BLEN, tc)
179b1bee1e6Sozaki-r {
180b1bee1e6Sozaki-r struct ifreq ifr;
181b1bee1e6Sozaki-r int ifnum, bpfd;
182b1bee1e6Sozaki-r u_int blen = 0;
183b1bee1e6Sozaki-r
184b1bee1e6Sozaki-r RZ(rump_init());
185b1bee1e6Sozaki-r RZ(rump_pub_shmif_create(NULL, &ifnum));
186b1bee1e6Sozaki-r sprintf(ifr.ifr_name, "shmif%d", ifnum);
187b1bee1e6Sozaki-r
188b1bee1e6Sozaki-r RL(bpfd = rump_sys_open("/dev/bpf", O_RDWR));
189b1bee1e6Sozaki-r
190b1bee1e6Sozaki-r RL(rump_sys_ioctl(bpfd, BIOCGBLEN, &blen));
191b1bee1e6Sozaki-r ATF_REQUIRE(blen != 0);
192b1bee1e6Sozaki-r blen = 100;
193b1bee1e6Sozaki-r RL(rump_sys_ioctl(bpfd, BIOCSBLEN, &blen));
194b1bee1e6Sozaki-r RL(rump_sys_ioctl(bpfd, BIOCGBLEN, &blen));
195b1bee1e6Sozaki-r ATF_REQUIRE_EQ(blen, 100);
196b1bee1e6Sozaki-r
197b1bee1e6Sozaki-r RL(rump_sys_ioctl(bpfd, BIOCSETIF, &ifr));
198b1bee1e6Sozaki-r
199b1bee1e6Sozaki-r ATF_REQUIRE_EQ_MSG(rump_sys_ioctl(bpfd, BIOCSBLEN, &blen), -1,
200b1bee1e6Sozaki-r "Don't allow to change buflen after binding bpf to an interface");
201b1bee1e6Sozaki-r }
202b1bee1e6Sozaki-r
20322c2d28cSozaki-r ATF_TC(bpf_ioctl_PROMISC);
ATF_TC_HEAD(bpf_ioctl_PROMISC,tc)20422c2d28cSozaki-r ATF_TC_HEAD(bpf_ioctl_PROMISC, tc)
20522c2d28cSozaki-r {
20622c2d28cSozaki-r
20722c2d28cSozaki-r atf_tc_set_md_var(tc, "descr", "Checks behaviors of BIOCPROMISC");
20822c2d28cSozaki-r }
20922c2d28cSozaki-r
ATF_TC_BODY(bpf_ioctl_PROMISC,tc)21022c2d28cSozaki-r ATF_TC_BODY(bpf_ioctl_PROMISC, tc)
21122c2d28cSozaki-r {
21222c2d28cSozaki-r struct ifreq ifr;
21322c2d28cSozaki-r int ifnum, bpfd;
21422c2d28cSozaki-r
21522c2d28cSozaki-r RZ(rump_init());
21622c2d28cSozaki-r RZ(rump_pub_shmif_create(NULL, &ifnum));
21722c2d28cSozaki-r sprintf(ifr.ifr_name, "shmif%d", ifnum);
21822c2d28cSozaki-r
21922c2d28cSozaki-r RL(bpfd = rump_sys_open("/dev/bpf", O_RDWR));
22022c2d28cSozaki-r
22122c2d28cSozaki-r ATF_REQUIRE_EQ_MSG(rump_sys_ioctl(bpfd, BIOCPROMISC, NULL), -1,
22222c2d28cSozaki-r "Don't allow to call ioctl(BIOCPROMISC) without interface");
22322c2d28cSozaki-r
22422c2d28cSozaki-r RL(rump_sys_ioctl(bpfd, BIOCSETIF, &ifr));
22522c2d28cSozaki-r
22622c2d28cSozaki-r RL(rump_sys_ioctl(bpfd, BIOCPROMISC, NULL));
22722c2d28cSozaki-r /* TODO check if_flags */
22822c2d28cSozaki-r }
22922c2d28cSozaki-r
23022c2d28cSozaki-r ATF_TC(bpf_ioctl_SETIF);
ATF_TC_HEAD(bpf_ioctl_SETIF,tc)23122c2d28cSozaki-r ATF_TC_HEAD(bpf_ioctl_SETIF, tc)
23222c2d28cSozaki-r {
23322c2d28cSozaki-r
23422c2d28cSozaki-r atf_tc_set_md_var(tc, "descr", "Checks behaviors of BIOCSETIF");
23522c2d28cSozaki-r }
23622c2d28cSozaki-r
ATF_TC_BODY(bpf_ioctl_SETIF,tc)23722c2d28cSozaki-r ATF_TC_BODY(bpf_ioctl_SETIF, tc)
23822c2d28cSozaki-r {
23922c2d28cSozaki-r struct ifreq ifr;
24022c2d28cSozaki-r int ifnum, bpfd;
24122c2d28cSozaki-r
24222c2d28cSozaki-r RZ(rump_init());
24322c2d28cSozaki-r
24422c2d28cSozaki-r RL(bpfd = rump_sys_open("/dev/bpf", O_RDWR));
24522c2d28cSozaki-r
24622c2d28cSozaki-r RZ(rump_pub_shmif_create(NULL, &ifnum));
24722c2d28cSozaki-r sprintf(ifr.ifr_name, "shmif%d", ifnum);
24822c2d28cSozaki-r RL(rump_sys_ioctl(bpfd, BIOCSETIF, &ifr));
24922c2d28cSozaki-r
25022c2d28cSozaki-r /* Change the listening interface */
25122c2d28cSozaki-r RZ(rump_pub_shmif_create(NULL, &ifnum));
25222c2d28cSozaki-r sprintf(ifr.ifr_name, "shmif%d", ifnum);
25322c2d28cSozaki-r RL(rump_sys_ioctl(bpfd, BIOCSETIF, &ifr));
25422c2d28cSozaki-r }
25522c2d28cSozaki-r
25622c2d28cSozaki-r ATF_TC(bpf_ioctl_DLT);
ATF_TC_HEAD(bpf_ioctl_DLT,tc)25722c2d28cSozaki-r ATF_TC_HEAD(bpf_ioctl_DLT, tc)
25822c2d28cSozaki-r {
25922c2d28cSozaki-r
26022c2d28cSozaki-r atf_tc_set_md_var(tc, "descr", "Checks behaviors of BIOCGDLT and "
26122c2d28cSozaki-r "BIOCSDLT");
26222c2d28cSozaki-r }
26322c2d28cSozaki-r
ATF_TC_BODY(bpf_ioctl_DLT,tc)26422c2d28cSozaki-r ATF_TC_BODY(bpf_ioctl_DLT, tc)
26522c2d28cSozaki-r {
26622c2d28cSozaki-r struct ifreq ifr;
26722c2d28cSozaki-r int ifnum, bpfd;
26822c2d28cSozaki-r u_int dlt;
26922c2d28cSozaki-r
27022c2d28cSozaki-r RZ(rump_init());
27122c2d28cSozaki-r RL(bpfd = rump_sys_open("/dev/bpf", O_RDWR));
27222c2d28cSozaki-r RZ(rump_pub_shmif_create(NULL, &ifnum));
27322c2d28cSozaki-r sprintf(ifr.ifr_name, "shmif%d", ifnum);
27422c2d28cSozaki-r
27522c2d28cSozaki-r ATF_REQUIRE_EQ_MSG(rump_sys_ioctl(bpfd, BIOCGDLT, &dlt), -1,
27622c2d28cSozaki-r "Don't allow to get a DLT without interfaces");
27722c2d28cSozaki-r
27822c2d28cSozaki-r RL(rump_sys_ioctl(bpfd, BIOCSETIF, &ifr));
27922c2d28cSozaki-r
28022c2d28cSozaki-r RL(rump_sys_ioctl(bpfd, BIOCGDLT, &dlt));
28122c2d28cSozaki-r ATF_REQUIRE(dlt == DLT_EN10MB);
28222c2d28cSozaki-r
28322c2d28cSozaki-r dlt = DLT_NULL;
28422c2d28cSozaki-r ATF_REQUIRE_EQ_MSG(rump_sys_ioctl(bpfd, BIOCSDLT, &dlt), -1,
28522c2d28cSozaki-r "Don't allow to set a DLT that doesn't match any listening "
28622c2d28cSozaki-r "interfaces");
28722c2d28cSozaki-r }
28822c2d28cSozaki-r
28922c2d28cSozaki-r ATF_TC(bpf_ioctl_GDLTLIST);
ATF_TC_HEAD(bpf_ioctl_GDLTLIST,tc)29022c2d28cSozaki-r ATF_TC_HEAD(bpf_ioctl_GDLTLIST, tc)
29122c2d28cSozaki-r {
29222c2d28cSozaki-r
29322c2d28cSozaki-r atf_tc_set_md_var(tc, "descr", "Checks behaviors of BIOCGDLTLIST");
29422c2d28cSozaki-r }
29522c2d28cSozaki-r
ATF_TC_BODY(bpf_ioctl_GDLTLIST,tc)29622c2d28cSozaki-r ATF_TC_BODY(bpf_ioctl_GDLTLIST, tc)
29722c2d28cSozaki-r {
29822c2d28cSozaki-r struct ifreq ifr;
29922c2d28cSozaki-r int ifnum, bpfd;
30022c2d28cSozaki-r struct bpf_dltlist dltlist;
30122c2d28cSozaki-r
30222c2d28cSozaki-r RZ(rump_init());
30322c2d28cSozaki-r RL(bpfd = rump_sys_open("/dev/bpf", O_RDWR));
30422c2d28cSozaki-r RZ(rump_pub_shmif_create(NULL, &ifnum));
30522c2d28cSozaki-r sprintf(ifr.ifr_name, "shmif%d", ifnum);
30622c2d28cSozaki-r
30722c2d28cSozaki-r dltlist.bfl_len = 0;
30822c2d28cSozaki-r dltlist.bfl_list = NULL;
30922c2d28cSozaki-r ATF_REQUIRE_EQ_MSG(rump_sys_ioctl(bpfd, BIOCGDLTLIST, &dltlist), -1,
31022c2d28cSozaki-r "Don't allow to get a DLT list without interfaces");
31122c2d28cSozaki-r
31222c2d28cSozaki-r RL(rump_sys_ioctl(bpfd, BIOCSETIF, &ifr));
31322c2d28cSozaki-r
314*6c259f39Srillig /* Get the size of an available DLT list */
31522c2d28cSozaki-r dltlist.bfl_len = 0;
31622c2d28cSozaki-r dltlist.bfl_list = NULL;
31722c2d28cSozaki-r RL(rump_sys_ioctl(bpfd, BIOCGDLTLIST, &dltlist));
31822c2d28cSozaki-r ATF_REQUIRE(dltlist.bfl_len == 1);
31922c2d28cSozaki-r
320*6c259f39Srillig /* Get an available DLT list */
32122c2d28cSozaki-r dltlist.bfl_list = calloc(sizeof(u_int), 1);
32222c2d28cSozaki-r dltlist.bfl_len = 1;
32322c2d28cSozaki-r RL(rump_sys_ioctl(bpfd, BIOCGDLTLIST, &dltlist));
32422c2d28cSozaki-r ATF_REQUIRE(dltlist.bfl_len == 1);
32522c2d28cSozaki-r ATF_REQUIRE(dltlist.bfl_list[0] == DLT_EN10MB);
32622c2d28cSozaki-r
327*6c259f39Srillig /* Get an available DLT list with a less buffer (fake with bfl_len) */
32822c2d28cSozaki-r dltlist.bfl_len = 0;
32922c2d28cSozaki-r ATF_REQUIRE_EQ_MSG(rump_sys_ioctl(bpfd, BIOCGDLTLIST, &dltlist), -1,
33022c2d28cSozaki-r "This should fail with ENOMEM");
33122c2d28cSozaki-r
33222c2d28cSozaki-r free(dltlist.bfl_list);
33322c2d28cSozaki-r }
33422c2d28cSozaki-r
ATF_TP_ADD_TCS(tp)3351a21107aSpooka ATF_TP_ADD_TCS(tp)
3361a21107aSpooka {
3371a21107aSpooka
3381a21107aSpooka ATF_TP_ADD_TC(tp, bpfwriteleak);
33900a60545Schristos #if (SIZE_MAX > UINT_MAX)
34000a60545Schristos ATF_TP_ADD_TC(tp, bpfwritetrunc);
34100a60545Schristos #endif
342b1bee1e6Sozaki-r ATF_TP_ADD_TC(tp, bpf_ioctl_BLEN);
34322c2d28cSozaki-r ATF_TP_ADD_TC(tp, bpf_ioctl_PROMISC);
34422c2d28cSozaki-r ATF_TP_ADD_TC(tp, bpf_ioctl_SETIF);
34522c2d28cSozaki-r ATF_TP_ADD_TC(tp, bpf_ioctl_DLT);
34622c2d28cSozaki-r ATF_TP_ADD_TC(tp, bpf_ioctl_GDLTLIST);
3471a21107aSpooka return atf_no_error();
3481a21107aSpooka }
349