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.18 2020/05/30 14:16:56 rmind 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 126 static const npf_ifops_t kern_ifops = { 127 .getname = npf_ifop_getname, 128 .lookup = npf_ifop_lookup, 129 .flush = npf_ifop_flush, 130 .getmeta = npf_ifop_getmeta, 131 .setmeta = npf_ifop_setmeta, 132 }; 133 134 static int 135 npf_fini(void) 136 { 137 npf_t *npf = npf_getkernctx(); 138 139 /* At first, detach device and remove pfil hooks. */ 140 #ifdef _MODULE 141 devsw_detach(NULL, &npf_cdevsw); 142 #endif 143 npf_pfil_unregister(true); 144 npfk_destroy(npf); 145 npfk_sysfini(); 146 return 0; 147 } 148 149 static int 150 npf_init(void) 151 { 152 npf_t *npf; 153 int error = 0; 154 155 error = npfk_sysinit(nworkers); 156 if (error) 157 return error; 158 npf = npfk_create(0, NULL, &kern_ifops, NULL); 159 npf_setkernctx(npf); 160 npf_pfil_register(true); 161 162 #ifdef _MODULE 163 devmajor_t bmajor = NODEVMAJOR, cmajor = NODEVMAJOR; 164 165 /* Attach /dev/npf device. */ 166 error = devsw_attach("npf", NULL, &bmajor, &npf_cdevsw, &cmajor); 167 if (error) { 168 /* It will call devsw_detach(), which is safe. */ 169 (void)npf_fini(); 170 } 171 #endif 172 return error; 173 } 174 175 176 /* 177 * Module interface. 178 */ 179 static int 180 npf_modcmd(modcmd_t cmd, void *arg) 181 { 182 switch (cmd) { 183 case MODULE_CMD_INIT: 184 return npf_init(); 185 case MODULE_CMD_FINI: 186 return npf_fini(); 187 case MODULE_CMD_AUTOUNLOAD: 188 if (npf_autounload_p()) { 189 return EBUSY; 190 } 191 break; 192 default: 193 return ENOTTY; 194 } 195 return 0; 196 } 197 198 void 199 npfattach(int nunits) 200 { 201 /* Nothing */ 202 } 203 204 static int 205 npf_dev_open(dev_t dev, int flag, int mode, lwp_t *l) 206 { 207 /* Available only for super-user. */ 208 if (kauth_authorize_network(l->l_cred, KAUTH_NETWORK_FIREWALL, 209 KAUTH_REQ_NETWORK_FIREWALL_FW, NULL, NULL, NULL)) { 210 return EPERM; 211 } 212 return 0; 213 } 214 215 static int 216 npf_dev_close(dev_t dev, int flag, int mode, lwp_t *l) 217 { 218 return 0; 219 } 220 221 static int 222 npf_stats_export(npf_t *npf, void *data) 223 { 224 uint64_t *fullst, *uptr = *(uint64_t **)data; 225 int error; 226 227 fullst = kmem_alloc(NPF_STATS_SIZE, KM_SLEEP); 228 npfk_stats(npf, fullst); /* will zero the buffer */ 229 error = copyout(fullst, uptr, NPF_STATS_SIZE); 230 kmem_free(fullst, NPF_STATS_SIZE); 231 return error; 232 } 233 234 /* 235 * npfctl_switch: enable or disable packet inspection. 236 */ 237 static int 238 npfctl_switch(void *data) 239 { 240 const bool onoff = *(int *)data ? true : false; 241 int error; 242 243 if (onoff) { 244 /* Enable: add pfil hooks. */ 245 error = npf_pfil_register(false); 246 } else { 247 /* Disable: remove pfil hooks. */ 248 npf_pfil_unregister(false); 249 error = 0; 250 } 251 return error; 252 } 253 254 static int 255 npf_dev_ioctl(dev_t dev, u_long cmd, void *data, int flag, lwp_t *l) 256 { 257 npf_t *npf = npf_getkernctx(); 258 nvlist_t *req, *resp; 259 int error; 260 261 /* Available only for super-user. */ 262 if (kauth_authorize_network(l->l_cred, KAUTH_NETWORK_FIREWALL, 263 KAUTH_REQ_NETWORK_FIREWALL_FW, NULL, NULL, NULL)) { 264 return EPERM; 265 } 266 267 switch (cmd) { 268 case IOC_NPF_VERSION: 269 *(int *)data = NPF_VERSION; 270 return 0; 271 272 case IOC_NPF_SWITCH: 273 return npfctl_switch(data); 274 275 case IOC_NPF_TABLE: 276 return npfctl_table(npf, data); 277 278 case IOC_NPF_STATS: 279 return npf_stats_export(npf, data); 280 } 281 282 error = nvlist_copyin(data, &req, NPF_IOCTL_DATA_LIMIT); 283 if (__predict_false(error)) { 284 #ifdef __NetBSD__ 285 /* Until the version bump. */ 286 if (cmd != IOC_NPF_SAVE) { 287 return error; 288 } 289 req = nvlist_create(0); 290 #else 291 return error; 292 #endif 293 } 294 resp = nvlist_create(0); 295 npfctl_run_op(npf, cmd, req, resp); 296 error = nvlist_copyout(data, resp); 297 nvlist_destroy(resp); 298 nvlist_destroy(req); 299 300 return error; 301 } 302 303 static int 304 npf_dev_poll(dev_t dev, int events, lwp_t *l) 305 { 306 return ENOTSUP; 307 } 308 309 static int 310 npf_dev_read(dev_t dev, struct uio *uio, int flag) 311 { 312 return ENOTSUP; 313 } 314 315 bool 316 npf_autounload_p(void) 317 { 318 npf_t *npf = npf_getkernctx(); 319 return !npf_active_p() && npf_default_pass(npf); 320 } 321 322 /* 323 * Interface operations. 324 */ 325 326 static const char * 327 npf_ifop_getname(npf_t *npf __unused, ifnet_t *ifp) 328 { 329 return ifp->if_xname; 330 } 331 332 static ifnet_t * 333 npf_ifop_lookup(npf_t *npf __unused, const char *name) 334 { 335 return ifunit(name); 336 } 337 338 static void 339 npf_ifop_flush(npf_t *npf __unused, void *arg) 340 { 341 ifnet_t *ifp; 342 343 KERNEL_LOCK(1, NULL); 344 IFNET_GLOBAL_LOCK(); 345 IFNET_WRITER_FOREACH(ifp) { 346 ifp->if_npf_private = arg; 347 } 348 IFNET_GLOBAL_UNLOCK(); 349 KERNEL_UNLOCK_ONE(NULL); 350 } 351 352 static void * 353 npf_ifop_getmeta(npf_t *npf __unused, const ifnet_t *ifp) 354 { 355 return ifp->if_npf_private; 356 } 357 358 static void 359 npf_ifop_setmeta(npf_t *npf __unused, ifnet_t *ifp, void *arg) 360 { 361 ifp->if_npf_private = arg; 362 } 363 364 #ifdef _KERNEL 365 366 /* 367 * Wrapper of the main packet handler to pass the kernel NPF context. 368 */ 369 static int 370 npfos_packet_handler(void *arg, struct mbuf **mp, ifnet_t *ifp, int di) 371 { 372 npf_t *npf = npf_getkernctx(); 373 return npfk_packet_handler(npf, mp, ifp, di); 374 } 375 376 /* 377 * npf_ifhook: hook handling interface changes. 378 */ 379 static void 380 npf_ifhook(void *arg, unsigned long cmd, void *arg2) 381 { 382 npf_t *npf = npf_getkernctx(); 383 ifnet_t *ifp = arg2; 384 385 switch (cmd) { 386 case PFIL_IFNET_ATTACH: 387 npfk_ifmap_attach(npf, ifp); 388 npf_ifaddr_sync(npf, ifp); 389 break; 390 case PFIL_IFNET_DETACH: 391 npfk_ifmap_detach(npf, ifp); 392 npf_ifaddr_flush(npf, ifp); 393 break; 394 } 395 } 396 397 static void 398 npf_ifaddrhook(void *arg, u_long cmd, void *arg2) 399 { 400 npf_t *npf = npf_getkernctx(); 401 struct ifaddr *ifa = arg2; 402 403 switch (cmd) { 404 case SIOCSIFADDR: 405 case SIOCAIFADDR: 406 case SIOCDIFADDR: 407 #ifdef INET6 408 case SIOCSIFADDR_IN6: 409 case SIOCAIFADDR_IN6: 410 case SIOCDIFADDR_IN6: 411 #endif 412 KASSERT(ifa != NULL); 413 break; 414 default: 415 return; 416 } 417 npf_ifaddr_sync(npf, ifa->ifa_ifp); 418 } 419 420 /* 421 * npf_pfil_register: register pfil(9) hooks. 422 */ 423 static int 424 npf_pfil_register(bool init) 425 { 426 npf_t *npf = npf_getkernctx(); 427 int error = 0; 428 429 SOFTNET_KERNEL_LOCK_UNLESS_NET_MPSAFE(); 430 431 /* Init: interface re-config and attach/detach hook. */ 432 if (!npf_ph_if) { 433 npf_ph_if = pfil_head_get(PFIL_TYPE_IFNET, 0); 434 if (!npf_ph_if) { 435 error = ENOENT; 436 goto out; 437 } 438 439 error = pfil_add_ihook(npf_ifhook, NULL, 440 PFIL_IFNET, npf_ph_if); 441 KASSERT(error == 0); 442 443 error = pfil_add_ihook(npf_ifaddrhook, NULL, 444 PFIL_IFADDR, npf_ph_if); 445 KASSERT(error == 0); 446 } 447 if (init) { 448 goto out; 449 } 450 451 /* Check if pfil hooks are not already registered. */ 452 if (pfil_registered) { 453 error = EEXIST; 454 goto out; 455 } 456 457 /* Capture points of the activity in the IP layer. */ 458 npf_ph_inet = pfil_head_get(PFIL_TYPE_AF, (void *)AF_INET); 459 npf_ph_inet6 = pfil_head_get(PFIL_TYPE_AF, (void *)AF_INET6); 460 if (!npf_ph_inet && !npf_ph_inet6) { 461 error = ENOENT; 462 goto out; 463 } 464 465 /* Packet IN/OUT handlers for IP layer. */ 466 if (npf_ph_inet) { 467 error = pfil_add_hook(npfos_packet_handler, npf, 468 PFIL_ALL, npf_ph_inet); 469 KASSERT(error == 0); 470 } 471 if (npf_ph_inet6) { 472 error = pfil_add_hook(npfos_packet_handler, npf, 473 PFIL_ALL, npf_ph_inet6); 474 KASSERT(error == 0); 475 } 476 477 /* 478 * It is necessary to re-sync all/any interface address tables, 479 * since we did not listen for any changes. 480 */ 481 npf_ifaddr_syncall(npf); 482 pfil_registered = true; 483 out: 484 SOFTNET_KERNEL_UNLOCK_UNLESS_NET_MPSAFE(); 485 486 return error; 487 } 488 489 /* 490 * npf_pfil_unregister: unregister pfil(9) hooks. 491 */ 492 static void 493 npf_pfil_unregister(bool fini) 494 { 495 npf_t *npf = npf_getkernctx(); 496 497 SOFTNET_KERNEL_LOCK_UNLESS_NET_MPSAFE(); 498 499 if (fini && npf_ph_if) { 500 (void)pfil_remove_ihook(npf_ifhook, NULL, 501 PFIL_IFNET, npf_ph_if); 502 (void)pfil_remove_ihook(npf_ifaddrhook, NULL, 503 PFIL_IFADDR, npf_ph_if); 504 } 505 if (npf_ph_inet) { 506 (void)pfil_remove_hook(npfos_packet_handler, npf, 507 PFIL_ALL, npf_ph_inet); 508 } 509 if (npf_ph_inet6) { 510 (void)pfil_remove_hook(npfos_packet_handler, npf, 511 PFIL_ALL, npf_ph_inet6); 512 } 513 pfil_registered = false; 514 515 SOFTNET_KERNEL_UNLOCK_UNLESS_NET_MPSAFE(); 516 } 517 518 bool 519 npf_active_p(void) 520 { 521 return pfil_registered; 522 } 523 524 #endif 525 526 #ifdef __NetBSD__ 527 528 /* 529 * Epoch-Based Reclamation (EBR) wrappers: in NetBSD, we rely on the 530 * passive serialization mechanism (see pserialize(9) manual page), 531 * which provides sufficient guarantees for NPF. 532 */ 533 534 ebr_t * 535 npf_ebr_create(void) 536 { 537 return pserialize_create(); 538 } 539 540 void 541 npf_ebr_destroy(ebr_t *ebr) 542 { 543 pserialize_destroy(ebr); 544 } 545 546 void 547 npf_ebr_register(ebr_t *ebr) 548 { 549 KASSERT(ebr != NULL); (void)ebr; 550 } 551 552 void 553 npf_ebr_unregister(ebr_t *ebr) 554 { 555 KASSERT(ebr != NULL); (void)ebr; 556 } 557 558 int 559 npf_ebr_enter(ebr_t *ebr) 560 { 561 KASSERT(ebr != NULL); (void)ebr; 562 return pserialize_read_enter(); 563 } 564 565 void 566 npf_ebr_exit(ebr_t *ebr, int s) 567 { 568 KASSERT(ebr != NULL); (void)ebr; 569 pserialize_read_exit(s); 570 } 571 572 void 573 npf_ebr_full_sync(ebr_t *ebr) 574 { 575 pserialize_perform(ebr); 576 } 577 578 bool 579 npf_ebr_incrit_p(ebr_t *ebr) 580 { 581 KASSERT(ebr != NULL); (void)ebr; 582 return pserialize_in_read_section(); 583 } 584 585 #endif 586