solaris.c revision 94bdecd9e84ae1042607002db3e64a6849da5874
ab25eeb551a4be927a4b6ae2cf8aff7ed17decb4yz * Copyright (C) 1993-2001, 2003 by Darren Reed.
ab25eeb551a4be927a4b6ae2cf8aff7ed17decb4yz * See the IPFILTER.LICENCE file for details on licencing.
14d3298ea5ac04e3c29e86a4769ff92a49e9f4afAlexandr Nedvedicky * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
ab25eeb551a4be927a4b6ae2cf8aff7ed17decb4yz * Use is subject to license terms.
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * Copyright (c) 2014, Joyent, Inc. All rights reserved.
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * ipfilter kernel module mutexes and locking:
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * Enabling ipfilter creates a per-netstack ipf_stack_t object that is
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * stored in the ipf_stacks list, which is protected by ipf_stack_lock.
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * ipf_stack_t objects are accessed in three contexts:
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * 1) administering that filter (eg: ioctls handled with iplioctl())
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * 2) reading log data (eg: iplread() / iplwrite())
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * 3) filtering packets (eg: ipf_hook4_* and ipf_hook6_* pfhooks
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * functions)
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * Each ipf_stack_t has a RW lock, ifs_ipf_global, protecting access to the
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * whole structure. The structure also has locks protecting the various
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * data structures used for filtering. The following guidelines should be
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * followed for ipf_stack_t locks:
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * - ipf_stack_lock must be held when accessing the ipf_stacks list
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * - ipf_stack_lock should be held before acquiring ifs_ipf_global for
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * a stack (the exception to this is ipf_stack_destroy(), which removes
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * the ipf_stack_t from the list, then drops ipf_stack_lock before
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * acquiring ifs_ipf_global)
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * - ifs_ipf_global must be held when accessing an ipf_stack_t in that list:
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * - The write lock is held only during stack creation / destruction
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * - The read lock should be held for all other accesses
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * - To alter the filtering data in the administrative context, one must:
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * - acquire the read lock for ifs_ipf_global
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * - then acquire the write lock for the data in question
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * - In the filtering path, the read lock needs to be held for each type of
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * filtering data used
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * - ifs_ipf_global does not need to be held in the filtering path:
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * - The filtering hooks don't need to modify the stack itself
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * - The ipf_stack_t will not be destroyed until the hooks are unregistered.
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * This requires a write lock on the hook, ensuring that no active hooks
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * (eg: the filtering path) are running, and that the hooks won't be run
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * afterward.
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * Note that there is a deadlock possible when calling net_hook_register()
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * or net_hook_unregister() with ifs_ipf_global held: see the comments in
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * iplattach() and ipldetach() for details.
193974072f41a843678abf5f61979c748687e66bSherry Moore void *, void **));
ab25eeb551a4be927a4b6ae2cf8aff7ed17decb4yzstatic int ipf_attach __P((dev_info_t *, ddi_attach_cmd_t));
ab25eeb551a4be927a4b6ae2cf8aff7ed17decb4yzstatic int ipf_detach __P((dev_info_t *, ddi_detach_cmd_t));
7ddc9b1afd18f260b9fb78ec7732facd91769131Darren Reedstatic void *ipf_stack_create __P((const netid_t));
7ddc9b1afd18f260b9fb78ec7732facd91769131Darren Reedstatic void ipf_stack_destroy __P((const netid_t, void *));
8ad7418892268f9f0ba29518ab332f6a26f69fc5Darren Reedstatic void ipf_stack_shutdown __P((const netid_t, void *));
ab25eeb551a4be927a4b6ae2cf8aff7ed17decb4yzstatic char *ipf_devfiles[] = { IPL_NAME, IPNAT_NAME, IPSTATE_NAME,
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewichextern vmem_t *ipf_minor; /* minor number arena */
ab25eeb551a4be927a4b6ae2cf8aff7ed17decb4yzstatic struct modlinkage modlink1 = { MODREV_1, &iplmod, NULL };
ab25eeb551a4be927a4b6ae2cf8aff7ed17decb4yz#endif /* SOLARIS2 >= 6 */
ab25eeb551a4be927a4b6ae2cf8aff7ed17decb4yzstatic void
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewichipf_kstat_init(ipf_stack_t *ifs, boolean_t from_gz)
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich ifs->ifs_kstatp[0] = net_kstat_create(ifs->ifs_netid,
7ddc9b1afd18f260b9fb78ec7732facd91769131Darren Reed sizeof (filter_kstats_t) / sizeof (kstat_named_t), 0);
7ddc9b1afd18f260b9fb78ec7732facd91769131Darren Reed bcopy(&ipf_kstat_tmp, ifs->ifs_kstatp[0]->ks_data,
7ddc9b1afd18f260b9fb78ec7732facd91769131Darren Reed ifs->ifs_kstatp[0]->ks_update = ipf_kstat_update;
7ddc9b1afd18f260b9fb78ec7732facd91769131Darren Reed ifs->ifs_kstatp[0]->ks_private = &ifs->ifs_frstats[0];
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich ifs->ifs_kstatp[1] = net_kstat_create(ifs->ifs_netid,
7ddc9b1afd18f260b9fb78ec7732facd91769131Darren Reed sizeof (filter_kstats_t) / sizeof (kstat_named_t), 0);
7ddc9b1afd18f260b9fb78ec7732facd91769131Darren Reed bcopy(&ipf_kstat_tmp, ifs->ifs_kstatp[1]->ks_data,
7ddc9b1afd18f260b9fb78ec7732facd91769131Darren Reed ifs->ifs_kstatp[1]->ks_update = ipf_kstat_update;
7ddc9b1afd18f260b9fb78ec7732facd91769131Darren Reed ifs->ifs_kstatp[1]->ks_private = &ifs->ifs_frstats[1];
7ddc9b1afd18f260b9fb78ec7732facd91769131Darren Reed cmn_err(CE_NOTE, "IP Filter: ipf_kstat_init(%p) installed %p, %p",
ab25eeb551a4be927a4b6ae2cf8aff7ed17decb4yzstatic void
ab25eeb551a4be927a4b6ae2cf8aff7ed17decb4yz for (i = 0; i < 2; i++) {
7ddc9b1afd18f260b9fb78ec7732facd91769131Darren Reed net_kstat_delete(ifs->ifs_netid, ifs->ifs_kstatp[i]);
ab25eeb551a4be927a4b6ae2cf8aff7ed17decb4yz return (0);
7ddc9b1afd18f260b9fb78ec7732facd91769131Darren Reed mutex_init(&ipf_stack_lock, NULL, MUTEX_DRIVER, NULL);
7ddc9b1afd18f260b9fb78ec7732facd91769131Darren Reed cmn_err(CE_NOTE, "IP Filter: _info(%p) = %d", modinfop, ipfinst);
7ddc9b1afd18f260b9fb78ec7732facd91769131Darren Reed cmn_err(CE_NOTE, "IP Filter: ipf_identify(%p)", dip);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Initialize things for IPF for each stack instance
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhstatic void *
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewichipf_stack_create_one(const netid_t id, const zoneid_t zid, boolean_t from_gz,
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich cmn_err(CE_NOTE, "IP Filter:stack_create_one id=%d global=%d", id,
7ddc9b1afd18f260b9fb78ec7732facd91769131Darren Reed ifs = (ipf_stack_t *)kmem_alloc(sizeof (*ifs), KM_SLEEP);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Initialize mutex's
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh RWLOCK_INIT(&ifs->ifs_ipf_global, "ipf filter load/unload mutex");
14d3298ea5ac04e3c29e86a4769ff92a49e9f4afAlexandr Nedvedicky RWLOCK_INIT(&ifs->ifs_ipf_frcache, "ipf cache rwlock");
7ddc9b1afd18f260b9fb78ec7732facd91769131Darren Reed cmn_err(CE_CONT, "IP Filter:stack_create zone=%d", ifs->ifs_zone);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Lock people out while we set things up.
23f4867fdff96a11dd674de6259a5a0d0a13251cnordmark /* Limit to global stack */
23f4867fdff96a11dd674de6259a5a0d0a13251cnordmark cmn_err(CE_CONT, "!%s, running.\n", ipfilter_version);
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewichstatic void *
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * Create two ipfilter stacks for a zone - the first can only be
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * controlled from the global zone, and the second is owned by
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * the zone itself. There is no need to create a GZ-controlled
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * stack for the global zone, since we're already in the global
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * zone. See the "GZ-controlled and per-zone stacks" comment block in
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich ifs = ipf_stack_create_one(id, zid, B_TRUE, NULL);
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich return (ipf_stack_create_one(id, zid, B_FALSE, ifs));
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * Find an ipfilter stack for the given zone. Return the GZ-controlled or
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * per-zone stack if set by an earlier SIOCIPFZONESET ioctl call. See the
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * "GZ-controlled and per-zone stacks" comment block in ip_fil_solaris.c for
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * This function returns with the ipf_stack_t's ifs_ipf_global
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * read lock held (if the stack is found). See the "ipfilter kernel module
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * mutexes and locking" comment block at the top of this file.
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewichipf_find_stack(const zoneid_t orig_zone, ipf_devstate_t *isp)
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * If we're in the GZ, determine if we're acting on a zone's stack,
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * and whether or not that stack is the GZ-controlled or in-zone
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * one. See the "GZ and per-zone stacks" note at the top of this
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich /* Global zone, and we've set the zoneid for this fd already */
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich /* There's only a per-zone stack for the GZ */
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * Non-global zone or GZ without having set a zoneid: act on
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * the per-zone stack of the zone that this ioctl originated
7ddc9b1afd18f260b9fb78ec7732facd91769131Darren Reed for (ifs = ipf_stacks; ifs != NULL; ifs = ifs->ifs_next) {
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich if (ifs->ifs_zone == zone && ifs->ifs_gz_controlled == gz_stack)
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Make sure we're the only one's modifying things. With
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * this lock others should just fall out of the loop.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh return (-1);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Make sure there is no active filter rule.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh return (-1);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh return (0);
7ddc9b1afd18f260b9fb78ec7732facd91769131Darren Reed for (ifs = ipf_stacks; ifs != NULL; ifs = ifs->ifs_next)
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * Remove ipf kstats for both the per-zone ipf stack and the
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * GZ-controlled stack for the same zone, if it exists.
8ad7418892268f9f0ba29518ab332f6a26f69fc5Darren Reed/* ARGSUSED */
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * The GZ-controlled stack
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * The per-zone stack
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Destroy things for ipf for one stack.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh/* ARGSUSED */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhstatic void
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewichipf_stack_destroy_one(const netid_t id, ipf_stack_t *ifs)
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich (void) printf("ipf_stack_destroy_one(%p)\n", (void *)ifs);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Make sure we're the only one's modifying things. With
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * this lock others should just fall out of the loop.
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich printf("ipf_stack_destroy_one: ipldetach failed\n");
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * Destroy things for ipf for both the per-zone ipf stack and the
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * GZ-controlled stack for the same zone, if it exists. See the "GZ-controlled
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * and per-zone stacks" comment block in ip_fil_solaris.c for details.
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich/* ARGSUSED */
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * The GZ-controlled stack
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich ipf_stack_destroy_one(id, ifs->ifs_gz_cont_ifs);
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich * The per-zone stack
7ddc9b1afd18f260b9fb78ec7732facd91769131Darren Reed cmn_err(CE_NOTE, "IP Filter: ipf_attach(%p,%x)", dip, cmd);
ab25eeb551a4be927a4b6ae2cf8aff7ed17decb4yz /* Only one instance of ipf (instance 0) can be attached. */
7ddc9b1afd18f260b9fb78ec7732facd91769131Darren Reed cmn_err(CE_CONT, "IP Filter: attach ipf instance %d", instance);
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich if (ddi_soft_state_init(&ipf_state, sizeof (ipf_devstate_t), 1)
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich if (net_instance_register(ipfncb) == DDI_FAILURE) {
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich ipf_minor = vmem_create("ipf_minor", (void *)1, UINT32_MAX - 1,
94bdecd9e84ae1042607002db3e64a6849da5874Rob Gulewich 1, NULL, NULL, NULL, 0, VM_SLEEP | VMC_IDENTIFIER);
7ddc9b1afd18f260b9fb78ec7732facd91769131Darren Reed cmn_err(CE_CONT, "IP Filter:stack_create callback_reg=%d", i);
ab25eeb551a4be927a4b6ae2cf8aff7ed17decb4yz /* NOTREACHED */
7ddc9b1afd18f260b9fb78ec7732facd91769131Darren Reed cmn_err(CE_NOTE, "IP Filter: ipf_detach(%p,%x)", dip, cmd);
ab25eeb551a4be927a4b6ae2cf8aff7ed17decb4yz switch (cmd) {
193974072f41a843678abf5f61979c748687e66bSherry Moore * Undo what we did in ipf_attach, freeing resources
ab25eeb551a4be927a4b6ae2cf8aff7ed17decb4yz * and removing things we installed. The system
ab25eeb551a4be927a4b6ae2cf8aff7ed17decb4yz * framework guarantees we are not active with this devinfo
ab25eeb551a4be927a4b6ae2cf8aff7ed17decb4yz * node in any other entry points at this time.
ab25eeb551a4be927a4b6ae2cf8aff7ed17decb4yz if (i > 0) {
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /* NOTREACHED */
ab25eeb551a4be927a4b6ae2cf8aff7ed17decb4yz/*ARGSUSED*/
7ddc9b1afd18f260b9fb78ec7732facd91769131Darren Reed cmn_err(CE_NOTE, "IP Filter: ipf_getinfo(%p,%x,%p)", dip, infocmd, arg);
ab25eeb551a4be927a4b6ae2cf8aff7ed17decb4yz *result = (void *)0;
ab25eeb551a4be927a4b6ae2cf8aff7ed17decb4yz * Fetch configuration file values that have been entered into the ipf.conf
ab25eeb551a4be927a4b6ae2cf8aff7ed17decb4yz * driver file.
40cdc2e8babc6bb3ab847f6a129fc9eb76c5f4d5Alexandr Nedvedicky (name = ipft->ipft_name) != NULL; ipft++) {
40cdc2e8babc6bb3ab847f6a129fc9eb76c5f4d5Alexandr Nedvedicky err = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
40cdc2e8babc6bb3ab847f6a129fc9eb76c5f4d5Alexandr Nedvedicky cmn_err(CE_CONT, "IP Filter: lookup_int(%s) = %d\n",
40cdc2e8babc6bb3ab847f6a129fc9eb76c5f4d5Alexandr Nedvedicky if (ipft->ipft_sz == sizeof (uint32_t)) {
40cdc2e8babc6bb3ab847f6a129fc9eb76c5f4d5Alexandr Nedvedicky } else if (ipft->ipft_sz == sizeof (uint64_t)) {