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