Print this page
OS-7667 IPFilter needs to keep and report state for cloud firewall logging
Portions contributed by: Mike Gerdts <mike.gerdts@joyent.com>

@@ -3,11 +3,11 @@
  *
  * See the IPFILTER.LICENCE file for details on licencing.
  *
  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
  *
- * Copyright 2018 Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
  */
 
 #if !defined(lint)
 static const char sccsid[] = "@(#)ip_fil_solaris.c      1.7 07/22/06 (C) 1993-2000 Darren Reed";
 static const char rcsid[] = "@(#)$Id: ip_fil_solaris.c,v 2.62.2.19 2005/07/13 21:40:46 darrenr Exp $";

@@ -905,10 +905,13 @@
         isp = ddi_get_soft_state(ipf_state, unit);
         if (isp == NULL)
                 return ENXIO;
         unit = isp->ipfs_minor;
 
+        if (unit == IPL_LOGEV)
+                return (ipf_cfwlog_ioctl(dev, cmd, data, mode, cp, rp));
+
         zid = crgetzoneid(cp);
         if (cmd == SIOCIPFZONESET) {
                 if (zid == GLOBAL_ZONEID)
                         return fr_setzoneid(isp, (caddr_t) data);
                 return EACCES;

@@ -1245,15 +1248,33 @@
                 return ENXIO;
 
         if (IPL_LOGMAX < min)
                 return ENXIO;
 
+        /* Special-case ipfev: global-zone-open only. */
+        if (min == IPL_LOGEV) {
+                if (crgetzoneid(cred) != GLOBAL_ZONEID)
+                        return (ENXIO);
+                /*
+                 * Else enable the CFW logging of events.
+                 * NOTE: For now, we only allow one open at a time.
+                 * Use atomic_add to confirm/deny. And also for now,
+                 * assume sizeof (boolean_t) == sizeof (int).
+                 */
+                if (atomic_inc_uint_nv(&ipf_cfwlog_enabled) > 1) {
+                        atomic_dec_uint(&ipf_cfwlog_enabled);
+                        return (EBUSY);
+                }
+        }
+
         minor = (minor_t)(uintptr_t)vmem_alloc(ipf_minor, 1,
             VM_BESTFIT | VM_SLEEP);
 
         if (ddi_soft_state_zalloc(ipf_state, minor) != 0) {
                 vmem_free(ipf_minor, (void *)(uintptr_t)minor, 1);
+                if (min == IPL_LOGEV)
+                        atomic_dec_uint(&ipf_cfwlog_enabled);
                 return ENXIO;
         }
 
         *devp = makedevice(getmajor(*devp), minor);
         isp = ddi_get_soft_state(ipf_state, minor);

@@ -1271,18 +1292,26 @@
 dev_t dev;
 int flags, otype;
 cred_t *cred;
 {
         minor_t min = getminor(dev);
+        ipf_devstate_t *isp;
 
 #ifdef  IPFDEBUG
         cmn_err(CE_CONT, "iplclose(%x,%x,%x,%x)\n", dev, flags, otype, cred);
 #endif
 
         if (IPL_LOGMAX < min)
                 return ENXIO;
 
+        isp = ddi_get_soft_state(ipf_state, min);
+        if (isp != NULL && isp->ipfs_minor == IPL_LOGEV) {
+                /* Disable CFW logging. */
+                membar_exit();
+                atomic_dec_uint(&ipf_cfwlog_enabled);
+        }
+
         ddi_soft_state_free(ipf_state, min);
         vmem_free(ipf_minor, (void *)(uintptr_t)min, 1);
 
         return 0;
 }

@@ -1309,10 +1338,13 @@
         isp = ddi_get_soft_state(ipf_state, unit);
         if (isp == NULL)
                 return ENXIO;
         unit = isp->ipfs_minor;
 
+        if (unit == IPL_LOGEV)
+                return (ipf_cfwlog_read(dev, uio, cp));
+
         /*
          * ipf_find_stack returns with a read lock on ifs_ipf_global
          */
         ifs = ipf_find_stack(crgetzoneid(cp), isp);
         if (ifs == NULL)

@@ -1360,10 +1392,13 @@
         isp = ddi_get_soft_state(ipf_state, unit);
         if (isp == NULL)
                 return ENXIO;
         unit = isp->ipfs_minor;
 
+        if (unit == IPL_LOGEV)
+                return (EIO);   /* ipfev doesn't support write yet. */
+
         /*
          * ipf_find_stack returns with a read lock on ifs_ipf_global
          */
         ifs = ipf_find_stack(crgetzoneid(cp), isp);
         if (ifs == NULL)