Hi,

I am running machines with a very large number of mbuf.  netstat
-m output looks strange, I suspect integer overflow in kernel and
userland.

So I would like to convert kernel variables and calculations for
mbuf memory to long.  The problem does not affect 32 bit machines,
they do not support so much memory.  I put a range check into the
kernel sysctl.  In netstat I cast all multiplications to unsigned
long, to hold the product of two unsigned int.

The sysctl kern.maxclusters can stay an int until we support 4 TB
of RAM.

ok?

bluhm

Index: sys/conf/param.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/conf/param.c,v
retrieving revision 1.41
diff -u -p -r1.41 param.c
--- sys/conf/param.c    8 Jul 2019 23:59:32 -0000       1.41
+++ sys/conf/param.c    12 Jul 2019 20:31:45 -0000
@@ -89,7 +89,7 @@ int   initialvnodes = NVNODE;
 int    maxprocess = NPROCESS;
 int    maxthread = NPROCESS + 8 * MAXUSERS;
 int    maxfiles = 5 * (NPROCESS + MAXUSERS) + 80;
-int    nmbclust = NMBCLUSTERS;
+long   nmbclust = NMBCLUSTERS;

 #ifndef MBLOWAT
 #define MBLOWAT                16
Index: sys/kern/kern_sysctl.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/kern/kern_sysctl.c,v
retrieving revision 1.363
diff -u -p -r1.363 kern_sysctl.c
--- sys/kern/kern_sysctl.c      12 Jul 2019 13:56:27 -0000      1.363
+++ sys/kern/kern_sysctl.c      12 Jul 2019 21:50:48 -0000
@@ -129,8 +129,6 @@ extern int audio_record_enable;

 int allowkmem;

-extern void nmbclust_update(void);
-
 int sysctl_diskinit(int, struct proc *);
 int sysctl_proc_args(int *, u_int, void *, size_t *, struct proc *);
 int sysctl_proc_cwd(int *, u_int, void *, size_t *, struct proc *);
@@ -590,11 +588,13 @@ kern_sysctl(int *name, u_int namelen, vo
                return (sysctl_wdog(name + 1, namelen - 1, oldp, oldlenp,
                    newp, newlen));
 #endif
-       case KERN_MAXCLUSTERS:
-               error = sysctl_int(oldp, oldlenp, newp, newlen, &nmbclust);
-               if (!error)
-                       nmbclust_update();
+       case KERN_MAXCLUSTERS: {
+               int val = nmbclust;
+               error = sysctl_int(oldp, oldlenp, newp, newlen, &val);
+               if (error == 0 && val != nmbclust)
+                       error = nmbclust_update(val);
                return (error);
+       }
 #ifndef SMALL_KERNEL
        case KERN_EVCOUNT:
                return (evcount_sysctl(name + 1, namelen - 1, oldp, oldlenp,
Index: sys/kern/uipc_mbuf.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/kern/uipc_mbuf.c,v
retrieving revision 1.269
diff -u -p -r1.269 uipc_mbuf.c
--- sys/kern/uipc_mbuf.c        10 Jun 2019 23:45:19 -0000      1.269
+++ sys/kern/uipc_mbuf.c        12 Jul 2019 21:50:06 -0000
@@ -131,12 +131,11 @@ int max_hdr;                      /* largest link+protocol
 struct mutex m_extref_mtx = MUTEX_INITIALIZER(IPL_NET);

 void   m_extfree(struct mbuf *);
-void   nmbclust_update(void);
 void   m_zero(struct mbuf *);

 struct mutex m_pool_mtx = MUTEX_INITIALIZER(IPL_NET);
-unsigned int mbuf_mem_limit; /* how much memory can be allocated */
-unsigned int mbuf_mem_alloc; /* how much memory has been allocated */
+unsigned long mbuf_mem_limit;  /* how much memory can be allocated */
+unsigned long mbuf_mem_alloc;  /* how much memory has been allocated */

 void   *m_pool_alloc(struct pool *, int, int *);
 void   m_pool_free(struct pool *, void *);
@@ -161,14 +160,15 @@ static u_int num_extfree_fns;
 void
 mbinit(void)
 {
-       int i;
+       int i, error;
        unsigned int lowbits;

        CTASSERT(MSIZE == sizeof(struct mbuf));

        m_pool_allocator.pa_pagesz = pool_allocator_multi.pa_pagesz;

-       nmbclust_update();
+       error = nmbclust_update(nmbclust);
+       KASSERT(error == 0);
        mbuf_mem_alloc = 0;

 #if DIAGNOSTIC
@@ -214,11 +214,15 @@ mbcpuinit()
                pool_cache_init(&mclpools[i]);
 }

-void
-nmbclust_update(void)
+int
+nmbclust_update(long newval)
 {
+       if (newval > LONG_MAX / MCLBYTES)
+               return ERANGE;
        /* update the global mbuf memory limit */
+       nmbclust = newval;
        mbuf_mem_limit = nmbclust * MCLBYTES;
+       return 0;
 }

 /*
Index: sys/sys/mbuf.h
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/sys/mbuf.h,v
retrieving revision 1.244
diff -u -p -r1.244 mbuf.h
--- sys/sys/mbuf.h      10 Jun 2019 23:45:19 -0000      1.244
+++ sys/sys/mbuf.h      12 Jul 2019 21:10:06 -0000
@@ -402,7 +402,7 @@ struct mbuf_queue {
 #ifdef _KERNEL
 struct pool;

-extern int nmbclust;                   /* limit on the # of clusters */
+extern long nmbclust;                  /* limit on the # of clusters */
 extern int mblowat;                    /* mbuf low water mark */
 extern int mcllowat;                   /* mbuf cluster low water mark */
 extern int max_linkhdr;                /* largest link-level header */
@@ -411,6 +411,7 @@ extern      int max_hdr;                    /* largest 
link+pr

 void   mbinit(void);
 void   mbcpuinit(void);
+int    nmbclust_update(long);
 struct mbuf *m_copym(struct mbuf *, int, int, int);
 struct mbuf *m_free(struct mbuf *);
 struct mbuf *m_get(int, int);
Index: usr.bin/netstat/mbuf.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/usr.bin/netstat/mbuf.c,v
retrieving revision 1.42
diff -u -p -r1.42 mbuf.c
--- usr.bin/netstat/mbuf.c      28 Jun 2019 13:35:02 -0000      1.42
+++ usr.bin/netstat/mbuf.c      12 Jul 2019 21:20:10 -0000
@@ -184,17 +184,19 @@ mbpr(void)
                            mbstat.m_mtypes[i],
                            plural(mbstat.m_mtypes[i]), i);
                }
-       totmem = (mbpool.pr_npages * mbpool.pr_pgsize);
-       totpeak = mbpool.pr_hiwat * mbpool.pr_pgsize;
+       totmem = (unsigned long)mbpool.pr_npages * mbpool.pr_pgsize;
+       totpeak = (unsigned long)mbpool.pr_hiwat * mbpool.pr_pgsize;
        for (i = 0; i < mclp; i++) {
                printf("%u/%lu mbuf %d byte clusters in use"
                    " (current/peak)\n",
                    mclpools[i].pr_nout,
                    (unsigned long)
-                       (mclpools[i].pr_hiwat * mclpools[i].pr_itemsperpage),
+                   mclpools[i].pr_hiwat * mclpools[i].pr_itemsperpage,
                    mclpools[i].pr_size);
-               totmem += (mclpools[i].pr_npages * mclpools[i].pr_pgsize);
-               totpeak += mclpools[i].pr_hiwat * mclpools[i].pr_pgsize;
+               totmem += (unsigned long)
+                   mclpools[i].pr_npages * mclpools[i].pr_pgsize;
+               totpeak += (unsigned long)
+                   mclpools[i].pr_hiwat * mclpools[i].pr_pgsize;
        }

        printf("%lu/%lu/%lu Kbytes allocated to network "

Reply via email to