Pools are generally (thought) safe from use after free bugs because
the poison renders the object useless. Unfortunately, in some cases
pool will very quickly recycle an object, meaning the newly allocated
object may be reinitialzed and then appear sensible to the code
holding on to the "old" pointer.

pool allocations are deterministic, which we'd prefer to avoid. Any
deterministic pattern is bad, but some are worse. In particular, when
the first object from a page is returned, that page is immediately
made the curpage, meaning we bounce the same object in and out many
times over a series of allocations.

1. Swizzle the curpage from time to time. We don't crawl too far into
the lists, but allocating from the front two pages introduces a little
variety into the process.

2. Don't force LIFO semantics on the first object back for a page.


Index: subr_pool.c
===================================================================
RCS file: /cvs/src/sys/kern/subr_pool.c,v
retrieving revision 1.126
diff -u -p -r1.126 subr_pool.c
--- subr_pool.c 3 Apr 2014 21:36:59 -0000       1.126
+++ subr_pool.c 14 Apr 2014 02:57:49 -0000
@@ -101,6 +101,7 @@ unsigned int pool_serial;
 int     pool_catchup(struct pool *);
 void    pool_prime_page(struct pool *, caddr_t, struct pool_item_header *);
 void    pool_update_curpage(struct pool *);
+void    pool_swizzle_curpage(struct pool *);
 void   *pool_do_get(struct pool *, int);
 void    pool_do_put(struct pool *, void *);
 void    pr_rmpage(struct pool *, struct pool_item_header *,
@@ -568,6 +569,7 @@ startover:
                return (NULL);
        }
 
+       pool_swizzle_curpage(pp);
        /*
         * The convention we use is that if `curpage' is not NULL, then
         * it points at a non-empty bucket. In particular, `curpage'
@@ -813,17 +815,13 @@ pool_do_put(struct pool *pp, void *v)
                        pool_update_curpage(pp);
                }
        }
-
        /*
         * If the page was previously completely full, move it to the
-        * partially-full list and make it the current page.  The next
-        * allocation will get the item from this page, instead of
-        * further fragmenting the pool.
+        * partially-full list.
         */
        else if (ph->ph_nmissing == (pp->pr_itemsperpage - 1)) {
                LIST_REMOVE(ph, ph_pagelist);
                LIST_INSERT_HEAD(&pp->pr_partpages, ph, ph_pagelist);
-               pp->pr_curpage = ph;
        }
 }
 
@@ -979,6 +977,27 @@ pool_update_curpage(struct pool *pp)
        if (pp->pr_curpage == NULL) {
                pp->pr_curpage = LIST_FIRST(&pp->pr_emptypages);
        }
+}
+
+void
+pool_swizzle_curpage(struct pool *pp)
+{
+       struct pool_item_header *ph, *next;
+
+       if ((ph = pp->pr_curpage) == NULL)
+               return;
+       if (arc4random_uniform(16) != 0)
+               return;
+       next = LIST_FIRST(&pp->pr_partpages);
+       if (next == ph)
+               next = LIST_NEXT(next, ph_pagelist);
+       if (next == NULL) {
+               next = LIST_FIRST(&pp->pr_emptypages);
+               if (next == ph)
+                       next = LIST_NEXT(next, ph_pagelist);
+       }
+       if (next != NULL)
+               pp->pr_curpage = next;
 }
 
 void


Reply via email to