1 /*- 2 * Copyright (c) 2009-2016 The NetBSD Foundation, Inc. 3 * All rights reserved. 4 * 5 * This material is based upon work partially supported by The 6 * NetBSD Foundation under a contract with Mindaugas Rasiukevicius. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 * POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 /* 31 * NPF main: dynamic load/initialisation and unload routines. 32 */ 33 34 #ifdef _KERNEL 35 #include <sys/cdefs.h> 36 __KERNEL_RCSID(0, "$NetBSD: npf_os.c,v 1.28 2026/09/22 16:29:11 joe Exp $"); 37 38 #ifdef _KERNEL_OPT 39 #include "pf.h" 40 #if NPF > 0 41 #error "NPF and PF are mutually exclusive; please select one" 42 #endif 43 #endif 44 45 #include <sys/param.h> 46 #include <sys/types.h> 47 48 #include <sys/conf.h> 49 #include <sys/kauth.h> 50 #include <sys/kmem.h> 51 #include <sys/lwp.h> 52 #include <sys/module.h> 53 #include <sys/pserialize.h> 54 #include <sys/socketvar.h> 55 #include <sys/uio.h> 56 57 #include <netinet/in.h> 58 #include <netinet6/in6_var.h> 59 #endif 60 61 #include "npf_impl.h" 62 #include "npfkern.h" 63 64 #ifdef _KERNEL 65 #ifndef _MODULE 66 #include "opt_modular.h" 67 #include "opt_net_mpsafe.h" 68 #endif 69 #include "ioconf.h" 70 #endif 71 72 /* 73 * Module and device structures. 74 */ 75 #ifndef _MODULE 76 /* 77 * Modular kernels load drivers too early, and we need percpu to be inited 78 * So we make this misc; a better way would be to have early boot and late 79 * boot drivers. 80 */ 81 MODULE(MODULE_CLASS_MISC, npf, "bpf_filter"); 82 #else 83 /* This module autoloads via /dev/npf so it needs to be a driver */ 84 MODULE(MODULE_CLASS_DRIVER, npf, "bpf_filter"); 85 #endif 86 87 #define NPF_IOCTL_DATA_LIMIT (4 * 1024 * 1024) 88 89 static int npf_pfil_register(bool); 90 static void npf_pfil_unregister(bool); 91 92 static int npf_dev_open(dev_t, int, int, lwp_t *); 93 static int npf_dev_close(dev_t, int, int, lwp_t *); 94 static int npf_dev_ioctl(dev_t, u_long, void *, int, lwp_t *); 95 static int npf_dev_poll(dev_t, int, lwp_t *); 96 static int npf_dev_read(dev_t, struct uio *, int); 97 98 const struct cdevsw npf_cdevsw = { 99 .d_open = npf_dev_open, 100 .d_close = npf_dev_close, 101 .d_read = npf_dev_read, 102 .d_write = nowrite, 103 .d_ioctl = npf_dev_ioctl, 104 .d_stop = nostop, 105 .d_tty = notty, 106 .d_poll = npf_dev_poll, 107 .d_mmap = nommap, 108 .d_kqfilter = nokqfilter, 109 .d_discard = nodiscard, 110 .d_flag = D_OTHER | D_MPSAFE 111 }; 112 113 static const char * npf_ifop_getname(npf_t *, ifnet_t *); 114 static ifnet_t * npf_ifop_lookup(npf_t *, const char *); 115 static void npf_ifop_flush(npf_t *, void *); 116 static void * npf_ifop_getmeta(npf_t *, const ifnet_t *); 117 static void npf_ifop_setmeta(npf_t *, ifnet_t *, void *); 118 119 static const unsigned nworkers = 1; 120 121 static bool pfil_registered = false; 122 static pfil_head_t * npf_ph_if = NULL; 123 static pfil_head_t * npf_ph_inet = NULL; 124 static pfil_head_t * npf_ph_inet6 = NULL; 125 static pfil_head_t * npf_ph_etherlist[NPF_MAX_IFMAP]; 126 127 static const npf_ifops_t kern_ifops = { 128 .getname = npf_ifop_getname, 129 .lookup = npf_ifop_lookup, 130 .flush = npf_ifop_flush, 131 .getmeta = npf_ifop_getmeta, 132 .setmeta = npf_ifop_setmeta, 133 }; 134 135 static int 136 npf_fini(void) 137 { 138 npf_t *npf = npf_getkernctx(); 139 140 /* At first, detach device and remove pfil hooks. */ 141 #ifdef _MODULE 142 devsw_detach(NULL, &npf_cdevsw); 143 #endif 144 npf_pfil_unregister(true); 145 npfk_destroy(npf); 146 npfk_sysfini(); 147 return 0; 148 } 149 150 static int 151 npf_init(void) 152 { 153 npf_t *npf; 154 int error = 0; 155 156 error = npfk_sysinit(nworkers); 157 if (error) 158 return error; 159 npf = npfk_create(0, NULL, &kern_ifops, NULL); 160 npf_setkernctx(npf); 161 npf_pfil_register(true); 162 163 #ifdef _MODULE 164 devmajor_t bmajor = NODEVMAJOR, cmajor = NODEVMAJOR; 165 166 /* Attach /dev/npf device. */ 167 error = devsw_attach("npf", NULL, &bmajor, &npf_cdevsw, &cmajor); 168 if (error) { 169 /* It will call devsw_detach(), which is safe. */ 170 (void)npf_fini(); 171 } 172 #endif 173 return error; 174 } 175 176 177 /* 178 * Module interface. 179 */ 180 static int 181 npf_modcmd(modcmd_t cmd, void *arg) 182 { 183 switch (cmd) { 184 case MODULE_CMD_INIT: 185 return npf_init(); 186 case MODULE_CMD_FINI: 187 return npf_fini(); 188 case MODULE_CMD_AUTOUNLOAD: 189 /* 190 * XXX npf_autounload_p() is insufficient here. At least one other 191 * XXX path leads to unloading while something tries later on to 192 * XXX continue (perhaps closing of an open fd). For now, just 193 * XXX disabble autounload. 194 */ 195 return EBUSY; 196 default: 197 return ENOTTY; 198 } 199 return 0; 200 } 201 202 void 203 npfattach(int nunits) 204 { 205 /* Nothing */ 206 } 207 208 static int 209 npf_dev_open(dev_t dev, int flag, int mode, lwp_t *l) 210 { 211 /* Available only for super-user. */ 212 if (kauth_authorize_network(l->l_cred, KAUTH_NETWORK_FIREWALL, 213 KAUTH_REQ_NETWORK_FIREWALL_FW, NULL, NULL, NULL)) { 214 return EPERM; 215 } 216 return 0; 217 } 218 219 static int 220 npf_dev_close(dev_t dev, int flag, int mode, lwp_t *l) 221 { 222 return 0; 223 } 224 225 static int 226 npf_stats_export(npf_t *npf, void *data) 227 { 228 uint64_t *fullst, *uptr = *(uint64_t **)data; 229 int error; 230 231 fullst = kmem_alloc(NPF_STATS_SIZE, KM_SLEEP); 232 npfk_stats(npf, fullst); /* will zero the buffer */ 233 error = copyout(fullst, uptr, NPF_STATS_SIZE); 234 kmem_free(fullst, NPF_STATS_SIZE); 235 return error; 236 } 237 238 /* 239 * npfctl_switch: enable or disable packet inspection. 240 */ 241 static int 242 npfctl_switch(void *data) 243 { 244 const bool onoff = *(int *)data ? true : false; 245 int error; 246 247 if (onoff) { 248 /* Enable: add pfil hooks. */ 249 error = npf_pfil_register(false); 250 } else { 251 /* Disable: remove pfil hooks. */ 252 npf_pfil_unregister(false); 253 error = 0; 254 } 255 return error; 256 } 257 258 static int 259 npf_dev_ioctl(dev_t dev, u_long cmd, void *data, int flag, lwp_t *l) 260 { 261 npf_t *npf = npf_getkernctx(); 262 nvlist_t *req, *resp; 263 int error; 264 265 /* Available only for super-user. */ 266 if (kauth_authorize_network(l->l_cred, KAUTH_NETWORK_FIREWALL, 267 KAUTH_REQ_NETWORK_FIREWALL_FW, NULL, NULL, NULL)) { 268 return EPERM; 269 } 270 271 switch (cmd) { 272 case IOC_NPF_VERSION: 273 *(int *)data = NPF_VERSION; 274 return 0; 275 case IOC_NPF_SWITCH: 276 return npfctl_switch(data); 277 case IOC_NPF_TABLE: 278 return npfctl_table(npf, data); 279 case IOC_NPF_STATS: 280 return npf_stats_export(npf, data); 281 case IOC_NPF_STATS_RESET: 282 npfk_stats_clear(npf); 283 return 0; 284 case IOC_NPF_LOAD: 285 case IOC_NPF_SAVE: 286 case IOC_NPF_RULE: 287 case IOC_NPF_CONN_LOOKUP: 288 case IOC_NPF_TABLE_REPLACE: 289 /* nvlist_ref_t argument, handled below */ 290 break; 291 default: 292 return EINVAL; 293 } 294 295 error = nvlist_copyin(data, &req, NPF_IOCTL_DATA_LIMIT); 296 if (__predict_false(error)) { 297 #ifdef __NetBSD__ 298 /* Until the version bump. */ 299 if (cmd != IOC_NPF_SAVE) { 300 return error; 301 } 302 req = nvlist_create(0); 303 #else 304 return error; 305 #endif 306 } 307 resp = nvlist_create(0); 308 309 if ((error = npfctl_run_op(npf, cmd, req, resp)) == 0) { 310 error = nvlist_copyout(data, resp); 311 } 312 313 nvlist_destroy(resp); 314 nvlist_destroy(req); 315 316 return error; 317 } 318 319 static int 320 npf_dev_poll(dev_t dev, int events, lwp_t *l) 321 { 322 return ENOTSUP; 323 } 324 325 static int 326 npf_dev_read(dev_t dev, struct uio *uio, int flag) 327 { 328 return ENOTSUP; 329 } 330 331 bool 332 npf_autounload_p(void) 333 { 334 if (npf_active_p()) 335 return false; 336 337 npf_t *npf = npf_getkernctx(); 338 339 npf_config_enter(npf); 340 bool pass = npf_default_pass(npf); 341 npf_config_exit(npf); 342 343 return pass; 344 } 345 346 /* 347 * Interface operations. 348 */ 349 350 static const char * 351 npf_ifop_getname(npf_t *npf __unused, ifnet_t *ifp) 352 { 353 return ifp->if_xname; 354 } 355 356 static ifnet_t * 357 npf_ifop_lookup(npf_t *npf __unused, const char *name) 358 { 359 return ifunit(name); 360 } 361 362 static void 363 npf_ifop_flush(npf_t *npf __unused, void *arg) 364 { 365 ifnet_t *ifp; 366 367 KERNEL_LOCK(1, NULL); 368 IFNET_GLOBAL_LOCK(); 369 IFNET_WRITER_FOREACH(ifp) { 370 ifp->if_npf_private = arg; 371 } 372 IFNET_GLOBAL_UNLOCK(); 373 KERNEL_UNLOCK_ONE(NULL); 374 } 375 376 static void * 377 npf_ifop_getmeta(npf_t *npf __unused, const ifnet_t *ifp) 378 { 379 return ifp->if_npf_private; 380 } 381 382 static void 383 npf_ifop_setmeta(npf_t *npf __unused, ifnet_t *ifp, void *arg) 384 { 385 ifp->if_npf_private = arg; 386 } 387 388 #ifdef _KERNEL 389 390 /* 391 * Wrapper of the main packet handler to pass the kernel NPF context. 392 */ 393 static int 394 npfos_packet_handler(void *arg, struct mbuf **mp, ifnet_t *ifp, int di) 395 { 396 npf_t *npf = npf_getkernctx(); 397 return npfk_packet_handler(npf, mp, ifp, di); 398 } 399 400 static int 401 npfos_layer2_handler(void *arg, struct mbuf **mp, ifnet_t *ifp, int di) 402 { 403 npf_t *npf = npf_getkernctx(); 404 return npfk_layer2_handler(npf, mp, ifp, di); 405 } 406 407 /* 408 * npf_ifhook: hook handling interface changes. 409 */ 410 static void 411 npf_ifhook(void *arg, unsigned long cmd, void *arg2) 412 { 413 npf_t *npf = npf_getkernctx(); 414 ifnet_t *ifp = arg2; 415 416 switch (cmd) { 417 case PFIL_IFNET_ATTACH: 418 npfk_ifmap_attach(npf, ifp); 419 npf_ifaddr_sync(npf, ifp); 420 break; 421 case PFIL_IFNET_DETACH: 422 npfk_ifmap_detach(npf, ifp); 423 npf_ifaddr_flush(npf, ifp); 424 break; 425 } 426 } 427 428 static void 429 npf_ifaddrhook(void *arg, u_long cmd, void *arg2) 430 { 431 npf_t *npf = npf_getkernctx(); 432 struct ifaddr *ifa = arg2; 433 434 switch (cmd) { 435 case SIOCSIFADDR: 436 case SIOCAIFADDR: 437 case SIOCDIFADDR: 438 #ifdef INET6 439 case SIOCSIFADDR_IN6: 440 case SIOCAIFADDR_IN6: 441 case SIOCDIFADDR_IN6: 442 #endif 443 KASSERT(ifa != NULL); 444 break; 445 default: 446 return; 447 } 448 npf_ifaddr_sync(npf, ifa->ifa_ifp); 449 } 450 451 static int 452 register_etherpfil_hook(npf_t *npf, ifnet_t *ifp, int i) 453 { 454 int error = 0; 455 static pfil_head_t *npf_ph_ether; 456 /* Capture points of activity at link layer */ 457 if ((npf_ph_ether = pfil_head_get(PFIL_TYPE_IFNET, ifp)) == NULL) { 458 error = ENOENT; 459 return error; 460 } 461 462 if (npf_ph_ether) { 463 error = pfil_add_hook(npfos_layer2_handler, npf, 464 PFIL_ALL, npf_ph_ether); 465 KASSERT(error == 0); 466 } 467 npf_ph_etherlist[i] = npf_ph_ether; 468 469 return error; 470 } 471 472 static int 473 get_etherpfil_head(npf_t *npf) 474 { 475 int error = 0, i = 0; 476 ifnet_t *ifp; 477 478 KERNEL_LOCK(1, NULL); 479 IFNET_GLOBAL_LOCK(); 480 IFNET_WRITER_FOREACH(ifp) { 481 error = register_etherpfil_hook(npf, ifp, i); 482 if (!error) 483 break; 484 i++; 485 } 486 IFNET_GLOBAL_UNLOCK(); 487 KERNEL_UNLOCK_ONE(NULL); 488 return error; 489 } 490 491 static void 492 destroy_pfilether_hook(npf_t *npf) 493 { 494 int i = 0; 495 while (npf_ph_etherlist[i]) { 496 pfil_head_t *npf_ph_ether = npf_ph_etherlist[i]; 497 498 if (npf_ph_ether) { 499 (void)pfil_remove_hook(npfos_layer2_handler, npf, 500 PFIL_ALL, npf_ph_ether); 501 } 502 i++; 503 } 504 } 505 506 /* 507 * npf_pfil_register: register pfil(9) hooks. 508 */ 509 static int 510 npf_pfil_register(bool init) 511 { 512 npf_t *npf = npf_getkernctx(); 513 int error = 0; 514 515 SOFTNET_KERNEL_LOCK_UNLESS_NET_MPSAFE(); 516 517 /* Init: interface re-config and attach/detach hook. */ 518 if (!npf_ph_if) { 519 npf_ph_if = pfil_head_get(PFIL_TYPE_IFNET, 0); 520 if (!npf_ph_if) { 521 error = ENOENT; 522 goto out; 523 } 524 525 error = pfil_add_ihook(npf_ifhook, NULL, 526 PFIL_IFNET, npf_ph_if); 527 KASSERT(error == 0); 528 529 error = pfil_add_ihook(npf_ifaddrhook, NULL, 530 PFIL_IFADDR, npf_ph_if); 531 KASSERT(error == 0); 532 } 533 if (init) { 534 goto out; 535 } 536 537 /* Check if pfil hooks are not already registered. */ 538 if (pfil_registered) { 539 error = EEXIST; 540 goto out; 541 } 542 543 /* Capture points of the activity in the IP layer. */ 544 npf_ph_inet = pfil_head_get(PFIL_TYPE_AF, (void *)AF_INET); 545 npf_ph_inet6 = pfil_head_get(PFIL_TYPE_AF, (void *)AF_INET6); 546 if (!npf_ph_inet && !npf_ph_inet6) { 547 error = ENOENT; 548 goto out; 549 } 550 551 /* Packet IN/OUT handlers for IP layer. */ 552 if (npf_ph_inet) { 553 error = pfil_add_hook(npfos_packet_handler, npf, 554 PFIL_ALL, npf_ph_inet); 555 KASSERT(error == 0); 556 } 557 if (npf_ph_inet6) { 558 error = pfil_add_hook(npfos_packet_handler, npf, 559 PFIL_ALL, npf_ph_inet6); 560 KASSERT(error == 0); 561 } 562 563 get_etherpfil_head(npf); 564 565 /* 566 * It is necessary to re-sync all/any interface address tables, 567 * since we did not listen for any changes. 568 */ 569 npf_ifaddr_syncall(npf); 570 pfil_registered = true; 571 out: 572 SOFTNET_KERNEL_UNLOCK_UNLESS_NET_MPSAFE(); 573 574 return error; 575 } 576 577 /* 578 * npf_pfil_unregister: unregister pfil(9) hooks. 579 */ 580 static void 581 npf_pfil_unregister(bool fini) 582 { 583 npf_t *npf = npf_getkernctx(); 584 585 SOFTNET_KERNEL_LOCK_UNLESS_NET_MPSAFE(); 586 587 if (fini && npf_ph_if) { 588 (void)pfil_remove_ihook(npf_ifhook, NULL, 589 PFIL_IFNET, npf_ph_if); 590 (void)pfil_remove_ihook(npf_ifaddrhook, NULL, 591 PFIL_IFADDR, npf_ph_if); 592 } 593 if (npf_ph_inet) { 594 (void)pfil_remove_hook(npfos_packet_handler, npf, 595 PFIL_ALL, npf_ph_inet); 596 } 597 if (npf_ph_inet6) { 598 (void)pfil_remove_hook(npfos_packet_handler, npf, 599 PFIL_ALL, npf_ph_inet6); 600 } 601 destroy_pfilether_hook(npf); 602 pfil_registered = false; 603 604 SOFTNET_KERNEL_UNLOCK_UNLESS_NET_MPSAFE(); 605 } 606 607 bool 608 npf_active_p(void) 609 { 610 return pfil_registered; 611 } 612 613 #endif 614 615 #ifdef __NetBSD__ 616 617 /* 618 * Epoch-Based Reclamation (EBR) wrappers: in NetBSD, we rely on the 619 * passive serialization mechanism (see pserialize(9) manual page), 620 * which provides sufficient guarantees for NPF. 621 */ 622 623 ebr_t * 624 npf_ebr_create(void) 625 { 626 return pserialize_create(); 627 } 628 629 void 630 npf_ebr_destroy(ebr_t *ebr) 631 { 632 pserialize_destroy(ebr); 633 } 634 635 void 636 npf_ebr_register(ebr_t *ebr) 637 { 638 KASSERT(ebr != NULL); (void)ebr; 639 } 640 641 void 642 npf_ebr_unregister(ebr_t *ebr) 643 { 644 KASSERT(ebr != NULL); (void)ebr; 645 } 646 647 int 648 npf_ebr_enter(ebr_t *ebr) 649 { 650 KASSERT(ebr != NULL); (void)ebr; 651 return pserialize_read_enter(); 652 } 653 654 void 655 npf_ebr_exit(ebr_t *ebr, int s) 656 { 657 KASSERT(ebr != NULL); (void)ebr; 658 pserialize_read_exit(s); 659 } 660 661 void 662 npf_ebr_full_sync(ebr_t *ebr) 663 { 664 pserialize_perform(ebr); 665 } 666 667 bool 668 npf_ebr_incrit_p(ebr_t *ebr) 669 { 670 KASSERT(ebr != NULL); (void)ebr; 671 return pserialize_in_read_section(); 672 } 673 674 #endif 675