Author: kp
Date: Fri Apr  6 19:36:35 2018
New Revision: 332142
URL: https://svnweb.freebsd.org/changeset/base/332142

Log:
  pf: Improve ioctl validation
  
  Ensure that multiplications for memory allocations cannot overflow, and
  that we'll not try to allocate M_WAITOK for potentially overly large
  allocations.
  
  MFC after:    1 week

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

Modified: head/sys/netpfil/pf/pf_ioctl.c
==============================================================================
--- head/sys/netpfil/pf/pf_ioctl.c      Fri Apr  6 19:34:21 2018        
(r332141)
+++ head/sys/netpfil/pf/pf_ioctl.c      Fri Apr  6 19:36:35 2018        
(r332142)
@@ -2740,9 +2740,14 @@ DIOCCHANGEADDR_error:
                        error = ENODEV;
                        break;
                }
+               if (io->pfrio_size < 0 ||
+                   WOULD_OVERFLOW(io->pfrio_size, sizeof(struct pfr_addr))) {
+                       error = EINVAL;
+                       break;
+               }
                totlen = io->pfrio_size * sizeof(struct pfr_addr);
                pfras = mallocarray(io->pfrio_size, sizeof(struct pfr_addr),
-                   M_TEMP, M_WAITOK);
+                   M_TEMP, M_NOWAIT);
                if (! pfras) {
                        error = ENOMEM;
                        break;
@@ -2772,9 +2777,14 @@ DIOCCHANGEADDR_error:
                        error = ENODEV;
                        break;
                }
+               if (io->pfrio_size < 0 ||
+                   WOULD_OVERFLOW(io->pfrio_size, sizeof(struct pfr_addr))) {
+                       error = EINVAL;
+                       break;
+               }
                totlen = io->pfrio_size * sizeof(struct pfr_addr);
                pfras = mallocarray(io->pfrio_size, sizeof(struct pfr_addr),
-                   M_TEMP, M_WAITOK);
+                   M_TEMP, M_NOWAIT);
                if (! pfras) {
                        error = ENOMEM;
                        break;
@@ -2804,10 +2814,18 @@ DIOCCHANGEADDR_error:
                        error = ENODEV;
                        break;
                }
+               if (io->pfrio_size < 0 || io->pfrio_size2 < 0) {
+                       error = EINVAL;
+                       break;
+               }
                count = max(io->pfrio_size, io->pfrio_size2);
+               if (WOULD_OVERFLOW(count, sizeof(struct pfr_addr))) {
+                       error = EINVAL;
+                       break;
+               }
                totlen = count * sizeof(struct pfr_addr);
                pfras = mallocarray(count, sizeof(struct pfr_addr), M_TEMP,
-                   M_WAITOK);
+                   M_NOWAIT);
                if (! pfras) {
                        error = ENOMEM;
                        break;
@@ -2838,9 +2856,14 @@ DIOCCHANGEADDR_error:
                        error = ENODEV;
                        break;
                }
+               if (io->pfrio_size < 0 ||
+                   WOULD_OVERFLOW(io->pfrio_size, sizeof(struct pfr_addr))) {
+                       error = EINVAL;
+                       break;
+               }
                totlen = io->pfrio_size * sizeof(struct pfr_addr);
                pfras = mallocarray(io->pfrio_size, sizeof(struct pfr_addr),
-                   M_TEMP, M_WAITOK);
+                   M_TEMP, M_NOWAIT);
                if (! pfras) {
                        error = ENOMEM;
                        break;
@@ -2864,9 +2887,14 @@ DIOCCHANGEADDR_error:
                        error = ENODEV;
                        break;
                }
+               if (io->pfrio_size < 0 ||
+                   WOULD_OVERFLOW(io->pfrio_size, sizeof(struct pfr_astats))) {
+                       error = EINVAL;
+                       break;
+               }
                totlen = io->pfrio_size * sizeof(struct pfr_astats);
                pfrastats = mallocarray(io->pfrio_size,
-                   sizeof(struct pfr_astats), M_TEMP, M_WAITOK);
+                   sizeof(struct pfr_astats), M_TEMP, M_NOWAIT);
                if (! pfrastats) {
                        error = ENOMEM;
                        break;
@@ -2890,9 +2918,14 @@ DIOCCHANGEADDR_error:
                        error = ENODEV;
                        break;
                }
+               if (io->pfrio_size < 0 ||
+                   WOULD_OVERFLOW(io->pfrio_size, sizeof(struct pfr_addr))) {
+                       error = EINVAL;
+                       break;
+               }
                totlen = io->pfrio_size * sizeof(struct pfr_addr);
                pfras = mallocarray(io->pfrio_size, sizeof(struct pfr_addr),
-                   M_TEMP, M_WAITOK);
+                   M_TEMP, M_NOWAIT);
                if (! pfras) {
                        error = ENOMEM;
                        break;
@@ -2922,9 +2955,14 @@ DIOCCHANGEADDR_error:
                        error = ENODEV;
                        break;
                }
+               if (io->pfrio_size < 0 ||
+                   WOULD_OVERFLOW(io->pfrio_size, sizeof(struct pfr_addr))) {
+                       error = EINVAL;
+                       break;
+               }
                totlen = io->pfrio_size * sizeof(struct pfr_addr);
                pfras = mallocarray(io->pfrio_size, sizeof(struct pfr_addr),
-                   M_TEMP, M_WAITOK);
+                   M_TEMP, M_NOWAIT);
                if (! pfras) {
                        error = ENOMEM;
                        break;
@@ -2954,9 +2992,14 @@ DIOCCHANGEADDR_error:
                        error = ENODEV;
                        break;
                }
+               if (io->pfrio_size < 0 ||
+                   WOULD_OVERFLOW(io->pfrio_size, sizeof(struct pfr_addr))) {
+                       error = EINVAL;
+                       break;
+               }
                totlen = io->pfrio_size * sizeof(struct pfr_addr);
                pfras = mallocarray(io->pfrio_size, sizeof(struct pfr_addr),
-                   M_TEMP, M_WAITOK);
+                   M_TEMP, M_NOWAIT);
                if (! pfras) {
                        error = ENOMEM;
                        break;
@@ -3001,9 +3044,14 @@ DIOCCHANGEADDR_error:
                        error = ENODEV;
                        break;
                }
+               if (io->size < 0 ||
+                   WOULD_OVERFLOW(io->size, sizeof(struct pfioc_trans_e))) {
+                       error = EINVAL;
+                       break;
+               }
                totlen = sizeof(struct pfioc_trans_e) * io->size;
                ioes = mallocarray(io->size, sizeof(struct pfioc_trans_e),
-                   M_TEMP, M_WAITOK);
+                   M_TEMP, M_NOWAIT);
                if (! ioes) {
                        error = ENOMEM;
                        break;
@@ -3072,9 +3120,14 @@ DIOCCHANGEADDR_error:
                        error = ENODEV;
                        break;
                }
+               if (io->size < 0 ||
+                   WOULD_OVERFLOW(io->size, sizeof(struct pfioc_trans_e))) {
+                       error = EINVAL;
+                       break;
+               }
                totlen = sizeof(struct pfioc_trans_e) * io->size;
                ioes = mallocarray(io->size, sizeof(struct pfioc_trans_e),
-                   M_TEMP, M_WAITOK);
+                   M_TEMP, M_NOWAIT);
                if (! ioes) {
                        error = ENOMEM;
                        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