Author: kp
Date: Wed Apr 11 11:43:12 2018
New Revision: 332404
URL: https://svnweb.freebsd.org/changeset/base/332404

Log:
  pf: limit ioctl to a reasonable and tuneable number of elements
  
  pf ioctls frequently take a variable number of elements as argument. This can
  potentially allow users to request very large allocations.  These will fail,
  but even a failing M_NOWAIT might tie up resources and result in concurrent
  M_WAITOK allocations entering vm_wait and inducing reclamation of caches.
  
  Limit these ioctls to what should be a reasonable value, but allow users to
  tune it should they need to.
  
  Differential Revision:        https://reviews.freebsd.org/D15018

Modified:
  head/sys/netpfil/pf/pf.c
  head/sys/netpfil/pf/pf_ioctl.c

Modified: head/sys/netpfil/pf/pf.c
==============================================================================
--- head/sys/netpfil/pf/pf.c    Wed Apr 11 11:17:57 2018        (r332403)
+++ head/sys/netpfil/pf/pf.c    Wed Apr 11 11:43:12 2018        (r332404)
@@ -369,11 +369,14 @@ u_long    pf_hashmask;
 u_long pf_srchashmask;
 static u_long  pf_hashsize;
 static u_long  pf_srchashsize;
+u_long pf_ioctl_maxcount = 65535;
 
 SYSCTL_ULONG(_net_pf, OID_AUTO, states_hashsize, CTLFLAG_RDTUN,
     &pf_hashsize, 0, "Size of pf(4) states hashtable");
 SYSCTL_ULONG(_net_pf, OID_AUTO, source_nodes_hashsize, CTLFLAG_RDTUN,
     &pf_srchashsize, 0, "Size of pf(4) source nodes hashtable");
+SYSCTL_ULONG(_net_pf, OID_AUTO, request_maxcount, CTLFLAG_RDTUN,
+    &pf_ioctl_maxcount, 0, "Maximum number of tables, addresses, ... in a 
single ioctl() call");
 
 VNET_DEFINE(void *, pf_swi_cookie);
 

Modified: head/sys/netpfil/pf/pf_ioctl.c
==============================================================================
--- head/sys/netpfil/pf/pf_ioctl.c      Wed Apr 11 11:17:57 2018        
(r332403)
+++ head/sys/netpfil/pf/pf_ioctl.c      Wed Apr 11 11:43:12 2018        
(r332404)
@@ -89,8 +89,6 @@ __FBSDID("$FreeBSD$");
 #include <net/altq/altq.h>
 #endif
 
-#define PF_TABLES_MAX_REQUEST   65535 /* Maximum tables per request. */
-
 static struct pf_pool  *pf_get_pool(char *, u_int32_t, u_int8_t, u_int32_t,
                            u_int8_t, u_int8_t, u_int8_t);
 
@@ -218,6 +216,8 @@ pfsync_defer_t                      *pfsync_defer_ptr = 
NULL;
 /* pflog */
 pflog_packet_t                 *pflog_packet_ptr = NULL;
 
+extern u_long  pf_ioctl_maxcount;
+
 static void
 pfattach_vnet(void)
 {
@@ -2533,7 +2533,8 @@ DIOCCHANGEADDR_error:
                        break;
                }
 
-               if (io->pfrio_size < 0 || io->pfrio_size > 
PF_TABLES_MAX_REQUEST) {
+               if (io->pfrio_size < 0 || io->pfrio_size > pf_ioctl_maxcount ||
+                   WOULD_OVERFLOW(io->pfrio_size, sizeof(struct pfr_table))) {
                        error = ENOMEM;
                        break;
                }
@@ -2564,7 +2565,8 @@ DIOCCHANGEADDR_error:
                        break;
                }
 
-               if (io->pfrio_size < 0 || io->pfrio_size > 
PF_TABLES_MAX_REQUEST) {
+               if (io->pfrio_size < 0 || io->pfrio_size > pf_ioctl_maxcount ||
+                   WOULD_OVERFLOW(io->pfrio_size, sizeof(struct pfr_table))) {
                        error = ENOMEM;
                        break;
                }
@@ -2741,6 +2743,7 @@ DIOCCHANGEADDR_error:
                        break;
                }
                if (io->pfrio_size < 0 ||
+                   io->pfrio_size > pf_ioctl_maxcount ||
                    WOULD_OVERFLOW(io->pfrio_size, sizeof(struct pfr_addr))) {
                        error = EINVAL;
                        break;
@@ -2778,6 +2781,7 @@ DIOCCHANGEADDR_error:
                        break;
                }
                if (io->pfrio_size < 0 ||
+                   io->pfrio_size > pf_ioctl_maxcount ||
                    WOULD_OVERFLOW(io->pfrio_size, sizeof(struct pfr_addr))) {
                        error = EINVAL;
                        break;
@@ -2819,7 +2823,8 @@ DIOCCHANGEADDR_error:
                        break;
                }
                count = max(io->pfrio_size, io->pfrio_size2);
-               if (WOULD_OVERFLOW(count, sizeof(struct pfr_addr))) {
+               if (count > pf_ioctl_maxcount ||
+                   WOULD_OVERFLOW(count, sizeof(struct pfr_addr))) {
                        error = EINVAL;
                        break;
                }
@@ -2857,6 +2862,7 @@ DIOCCHANGEADDR_error:
                        break;
                }
                if (io->pfrio_size < 0 ||
+                   io->pfrio_size > pf_ioctl_maxcount ||
                    WOULD_OVERFLOW(io->pfrio_size, sizeof(struct pfr_addr))) {
                        error = EINVAL;
                        break;
@@ -2888,6 +2894,7 @@ DIOCCHANGEADDR_error:
                        break;
                }
                if (io->pfrio_size < 0 ||
+                   io->pfrio_size > pf_ioctl_maxcount ||
                    WOULD_OVERFLOW(io->pfrio_size, sizeof(struct pfr_astats))) {
                        error = EINVAL;
                        break;
@@ -2919,6 +2926,7 @@ DIOCCHANGEADDR_error:
                        break;
                }
                if (io->pfrio_size < 0 ||
+                   io->pfrio_size > pf_ioctl_maxcount ||
                    WOULD_OVERFLOW(io->pfrio_size, sizeof(struct pfr_addr))) {
                        error = EINVAL;
                        break;
@@ -2956,6 +2964,7 @@ DIOCCHANGEADDR_error:
                        break;
                }
                if (io->pfrio_size < 0 ||
+                   io->pfrio_size > pf_ioctl_maxcount ||
                    WOULD_OVERFLOW(io->pfrio_size, sizeof(struct pfr_addr))) {
                        error = EINVAL;
                        break;
@@ -2993,6 +3002,7 @@ DIOCCHANGEADDR_error:
                        break;
                }
                if (io->pfrio_size < 0 ||
+                   io->pfrio_size > pf_ioctl_maxcount ||
                    WOULD_OVERFLOW(io->pfrio_size, sizeof(struct pfr_addr))) {
                        error = EINVAL;
                        break;
@@ -3045,6 +3055,7 @@ DIOCCHANGEADDR_error:
                        break;
                }
                if (io->size < 0 ||
+                   io->size > pf_ioctl_maxcount ||
                    WOULD_OVERFLOW(io->size, sizeof(struct pfioc_trans_e))) {
                        error = EINVAL;
                        break;
@@ -3121,6 +3132,7 @@ DIOCCHANGEADDR_error:
                        break;
                }
                if (io->size < 0 ||
+                   io->size > pf_ioctl_maxcount ||
                    WOULD_OVERFLOW(io->size, sizeof(struct pfioc_trans_e))) {
                        error = EINVAL;
                        break;
@@ -3198,6 +3210,7 @@ DIOCCHANGEADDR_error:
                }
 
                if (io->size < 0 ||
+                   io->size > pf_ioctl_maxcount ||
                    WOULD_OVERFLOW(io->size, sizeof(struct pfioc_trans_e))) {
                        error = EINVAL;
                        break;
@@ -3410,6 +3423,7 @@ DIOCCHANGEADDR_error:
                }
 
                if (io->pfiio_size < 0 ||
+                   io->pfiio_size > pf_ioctl_maxcount ||
                    WOULD_OVERFLOW(io->pfiio_size, sizeof(struct pfi_kif))) {
                        error = EINVAL;
                        break;
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to