Home | History | Annotate | Line # | Download | only in bpf
      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);
     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
     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 
     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);
    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 
    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);
    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 
    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);
    204 ATF_TC_HEAD(bpf_ioctl_PROMISC, tc)
    205 {
    206 
    207 	atf_tc_set_md_var(tc, "descr", "Checks behaviors of BIOCPROMISC");
    208 }
    209 
    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);
    231 ATF_TC_HEAD(bpf_ioctl_SETIF, tc)
    232 {
    233 
    234 	atf_tc_set_md_var(tc, "descr", "Checks behaviors of BIOCSETIF");
    235 }
    236 
    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);
    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 
    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);
    290 ATF_TC_HEAD(bpf_ioctl_GDLTLIST, tc)
    291 {
    292 
    293 	atf_tc_set_md_var(tc, "descr", "Checks behaviors of BIOCGDLTLIST");
    294 }
    295 
    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 
    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