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.23 2025/07/01 18:42:37 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"); 82 #else 83 /* This module autoloads via /dev/npf so it needs to be a driver */ 84 MODULE(MODULE_CLASS_DRIVER, npf, "bpf"); 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_LOAD: 282 case IOC_NPF_SAVE: 283 case IOC_NPF_RULE: 284 case IOC_NPF_CONN_LOOKUP: 285 case IOC_NPF_TABLE_REPLACE: 286 /* nvlist_ref_t argument, handled below */ 287 break; 288 default: 289 return EINVAL; 290 } 291 292 error = nvlist_copyin(data, &req, NPF_IOCTL_DATA_LIMIT); 293 if (__predict_false(error)) { 294 #ifdef __NetBSD__ 295 /* Until the version bump. */ 296 if (cmd != IOC_NPF_SAVE) { 297 return error; 298 } 299 req = nvlist_create(0); 300 #else 301 return error; 302 #endif 303 } 304 resp = nvlist_create(0); 305 306 if ((error = npfctl_run_op(npf, cmd, req, resp)) == 0) { 307 error = nvlist_copyout(data, resp); 308 } 309 310 nvlist_destroy(resp); 311 nvlist_destroy(req); 312 313 return error; 314 } 315 316 static int 317 npf_dev_poll(dev_t dev, int events, lwp_t *l) 318 { 319 return ENOTSUP; 320 } 321 322 static int 323 npf_dev_read(dev_t dev, struct uio *uio, int flag) 324 { 325 return ENOTSUP; 326 } 327 328 bool 329 npf_autounload_p(void) 330 { 331 if (npf_active_p()) 332 return false; 333 334 npf_t *npf = npf_getkernctx(); 335 336 npf_config_enter(npf); 337 bool pass = npf_default_pass(npf); 338 npf_config_exit(npf); 339 340 return pass; 341 } 342 343 /* 344 * Interface operations. 345 */ 346 347 static const char * 348 npf_ifop_getname(npf_t *npf __unused, ifnet_t *ifp) 349 { 350 return ifp->if_xname; 351 } 352 353 static ifnet_t * 354 npf_ifop_lookup(npf_t *npf __unused, const char *name) 355 { 356 return ifunit(name); 357 } 358 359 static void 360 npf_ifop_flush(npf_t *npf __unused, void *arg) 361 { 362 ifnet_t *ifp; 363 364 KERNEL_LOCK(1, NULL); 365 IFNET_GLOBAL_LOCK(); 366 IFNET_WRITER_FOREACH(ifp) { 367 ifp->if_npf_private = arg; 368 } 369 IFNET_GLOBAL_UNLOCK(); 370 KERNEL_UNLOCK_ONE(NULL); 371 } 372 373 static void * 374 npf_ifop_getmeta(npf_t *npf __unused, const ifnet_t *ifp) 375 { 376 return ifp->if_npf_private; 377 } 378 379 static void 380 npf_ifop_setmeta(npf_t *npf __unused, ifnet_t *ifp, void *arg) 381 { 382 ifp->if_npf_private = arg; 383 } 384 385 #ifdef _KERNEL 386 387 /* 388 * Wrapper of the main packet handler to pass the kernel NPF context. 389 */ 390 static int 391 npfos_packet_handler(void *arg, struct mbuf **mp, ifnet_t *ifp, int di) 392 { 393 npf_t *npf = npf_getkernctx(); 394 return npfk_packet_handler(npf, mp, ifp, di); 395 } 396 397 static int 398 npfos_layer2_handler(void *arg, struct mbuf **mp, ifnet_t *ifp, int di) 399 { 400 npf_t *npf = npf_getkernctx(); 401 return npfk_layer2_handler(npf, mp, ifp, di); 402 } 403 404 /* 405 * npf_ifhook: hook handling interface changes. 406 */ 407 static void 408 npf_ifhook(void *arg, unsigned long cmd, void *arg2) 409 { 410 npf_t *npf = npf_getkernctx(); 411 ifnet_t *ifp = arg2; 412 413 switch (cmd) { 414 case PFIL_IFNET_ATTACH: 415 npfk_ifmap_attach(npf, ifp); 416 npf_ifaddr_sync(npf, ifp); 417 break; 418 case PFIL_IFNET_DETACH: 419 npfk_ifmap_detach(npf, ifp); 420 npf_ifaddr_flush(npf, ifp); 421 break; 422 } 423 } 424 425 static void 426 npf_ifaddrhook(void *arg, u_long cmd, void *arg2) 427 { 428 npf_t *npf = npf_getkernctx(); 429 struct ifaddr *ifa = arg2; 430 431 switch (cmd) { 432 case SIOCSIFADDR: 433 case SIOCAIFADDR: 434 case SIOCDIFADDR: 435 #ifdef INET6 436 case SIOCSIFADDR_IN6: 437 case SIOCAIFADDR_IN6: 438 case SIOCDIFADDR_IN6: 439 #endif 440 KASSERT(ifa != NULL); 441 break; 442 default: 443 return; 444 } 445 npf_ifaddr_sync(npf, ifa->ifa_ifp); 446 } 447 448 static int 449 register_etherpfil_hook(npf_t *npf, ifnet_t *ifp, int i) 450 { 451 int error = 0; 452 static pfil_head_t *npf_ph_ether; 453 /* Capture points of activity at link layer */ 454 if ((npf_ph_ether = pfil_head_get(PFIL_TYPE_IFNET, ifp)) == NULL) { 455 error = ENOENT; 456 return error; 457 } 458 459 if (npf_ph_ether) { 460 error = pfil_add_hook(npfos_layer2_handler, npf, 461 PFIL_ALL, npf_ph_ether); 462 KASSERT(error == 0); 463 } 464 npf_ph_etherlist[i] = npf_ph_ether; 465 466 return error; 467 } 468 469 static int 470 get_etherpfil_head(npf_t *npf) 471 { 472 int error = 0, i = 0; 473 ifnet_t *ifp; 474 475 KERNEL_LOCK(1, NULL); 476 IFNET_GLOBAL_LOCK(); 477 IFNET_WRITER_FOREACH(ifp) { 478 error = register_etherpfil_hook(npf, ifp, i); 479 if (!error) 480 break; 481 i++; 482 } 483 IFNET_GLOBAL_UNLOCK(); 484 KERNEL_UNLOCK_ONE(NULL); 485 return error; 486 } 487 488 static void 489 destroy_pfilether_hook(npf_t *npf) 490 { 491 int i = 0; 492 while (npf_ph_etherlist[i]) { 493 pfil_head_t *npf_ph_ether = npf_ph_etherlist[i]; 494 495 if (npf_ph_ether) { 496 (void)pfil_remove_hook(npfos_layer2_handler, npf, 497 PFIL_ALL, npf_ph_ether); 498 } 499 i++; 500 } 501 } 502 503 /* 504 * npf_pfil_register: register pfil(9) hooks. 505 */ 506 static int 507 npf_pfil_register(bool init) 508 { 509 npf_t *npf = npf_getkernctx(); 510 int error = 0; 511 512 SOFTNET_KERNEL_LOCK_UNLESS_NET_MPSAFE(); 513 514 /* Init: interface re-config and attach/detach hook. */ 515 if (!npf_ph_if) { 516 npf_ph_if = pfil_head_get(PFIL_TYPE_IFNET, 0); 517 if (!npf_ph_if) { 518 error = ENOENT; 519 goto out; 520 } 521 522 error = pfil_add_ihook(npf_ifhook, NULL, 523 PFIL_IFNET, npf_ph_if); 524 KASSERT(error == 0); 525 526 error = pfil_add_ihook(npf_ifaddrhook, NULL, 527 PFIL_IFADDR, npf_ph_if); 528 KASSERT(error == 0); 529 } 530 if (init) { 531 goto out; 532 } 533 534 /* Check if pfil hooks are not already registered. */ 535 if (pfil_registered) { 536 error = EEXIST; 537 goto out; 538 } 539 540 /* Capture points of the activity in the IP layer. */ 541 npf_ph_inet = pfil_head_get(PFIL_TYPE_AF, (void *)AF_INET); 542 npf_ph_inet6 = pfil_head_get(PFIL_TYPE_AF, (void *)AF_INET6); 543 if (!npf_ph_inet && !npf_ph_inet6) { 544 error = ENOENT; 545 goto out; 546 } 547 548 /* Packet IN/OUT handlers for IP layer. */ 549 if (npf_ph_inet) { 550 error = pfil_add_hook(npfos_packet_handler, npf, 551 PFIL_ALL, npf_ph_inet); 552 KASSERT(error == 0); 553 } 554 if (npf_ph_inet6) { 555 error = pfil_add_hook(npfos_packet_handler, npf, 556 PFIL_ALL, npf_ph_inet6); 557 KASSERT(error == 0); 558 } 559 560 get_etherpfil_head(npf); 561 562 /* 563 * It is necessary to re-sync all/any interface address tables, 564 * since we did not listen for any changes. 565 */ 566 npf_ifaddr_syncall(npf); 567 pfil_registered = true; 568 out: 569 SOFTNET_KERNEL_UNLOCK_UNLESS_NET_MPSAFE(); 570 571 return error; 572 } 573 574 /* 575 * npf_pfil_unregister: unregister pfil(9) hooks. 576 */ 577 static void 578 npf_pfil_unregister(bool fini) 579 { 580 npf_t *npf = npf_getkernctx(); 581 582 SOFTNET_KERNEL_LOCK_UNLESS_NET_MPSAFE(); 583 584 if (fini && npf_ph_if) { 585 (void)pfil_remove_ihook(npf_ifhook, NULL, 586 PFIL_IFNET, npf_ph_if); 587 (void)pfil_remove_ihook(npf_ifaddrhook, NULL, 588 PFIL_IFADDR, npf_ph_if); 589 } 590 if (npf_ph_inet) { 591 (void)pfil_remove_hook(npfos_packet_handler, npf, 592 PFIL_ALL, npf_ph_inet); 593 } 594 if (npf_ph_inet6) { 595 (void)pfil_remove_hook(npfos_packet_handler, npf, 596 PFIL_ALL, npf_ph_inet6); 597 } 598 destroy_pfilether_hook(npf); 599 pfil_registered = false; 600 601 SOFTNET_KERNEL_UNLOCK_UNLESS_NET_MPSAFE(); 602 } 603 604 bool 605 npf_active_p(void) 606 { 607 return pfil_registered; 608 } 609 610 #endif 611 612 #ifdef __NetBSD__ 613 614 /* 615 * Epoch-Based Reclamation (EBR) wrappers: in NetBSD, we rely on the 616 * passive serialization mechanism (see pserialize(9) manual page), 617 * which provides sufficient guarantees for NPF. 618 */ 619 620 ebr_t * 621 npf_ebr_create(void) 622 { 623 return pserialize_create(); 624 } 625 626 void 627 npf_ebr_destroy(ebr_t *ebr) 628 { 629 pserialize_destroy(ebr); 630 } 631 632 void 633 npf_ebr_register(ebr_t *ebr) 634 { 635 KASSERT(ebr != NULL); (void)ebr; 636 } 637 638 void 639 npf_ebr_unregister(ebr_t *ebr) 640 { 641 KASSERT(ebr != NULL); (void)ebr; 642 } 643 644 int 645 npf_ebr_enter(ebr_t *ebr) 646 { 647 KASSERT(ebr != NULL); (void)ebr; 648 return pserialize_read_enter(); 649 } 650 651 void 652 npf_ebr_exit(ebr_t *ebr, int s) 653 { 654 KASSERT(ebr != NULL); (void)ebr; 655 pserialize_read_exit(s); 656 } 657 658 void 659 npf_ebr_full_sync(ebr_t *ebr) 660 { 661 pserialize_perform(ebr); 662 } 663 664 bool 665 npf_ebr_incrit_p(ebr_t *ebr) 666 { 667 KASSERT(ebr != NULL); (void)ebr; 668 return pserialize_in_read_section(); 669 } 670 671 #endif 672