Module Name:    src
Committed By:   maxv
Date:           Sat Aug 17 12:37:49 UTC 2019

Modified Files:
        src/sys/kern: subr_pool.c

Log Message:
Kernel Heap Hardening: use bitmaps on all off-page pools. This migrates 29
MI pools on amd64 from linked lists to bitmaps, which have higher security
properties.

Then, change the computation of the size of the PH pools: take into account
the bitmap area available by default in the ph_u2 union, and don't go with
&phpool[>0] if &phpool[0] already has enough space to embed a bitmap.

The pools that are migrated in this change all use bitmaps small enough to
fit in &phpool[0], therefore there is no increase in memory consumption.


To generate a diff of this commit:
cvs rdiff -u -r1.255 -r1.256 src/sys/kern/subr_pool.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/kern/subr_pool.c
diff -u src/sys/kern/subr_pool.c:1.255 src/sys/kern/subr_pool.c:1.256
--- src/sys/kern/subr_pool.c:1.255	Fri Aug 16 10:41:35 2019
+++ src/sys/kern/subr_pool.c	Sat Aug 17 12:37:49 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: subr_pool.c,v 1.255 2019/08/16 10:41:35 maxv Exp $	*/
+/*	$NetBSD: subr_pool.c,v 1.256 2019/08/17 12:37:49 maxv Exp $	*/
 
 /*
  * Copyright (c) 1997, 1999, 2000, 2002, 2007, 2008, 2010, 2014, 2015, 2018
@@ -33,7 +33,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: subr_pool.c,v 1.255 2019/08/16 10:41:35 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: subr_pool.c,v 1.256 2019/08/17 12:37:49 maxv Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_ddb.h"
@@ -81,7 +81,7 @@ TAILQ_HEAD(, pool) pool_head = TAILQ_HEA
 #define	PHPOOL_MAX	8
 static struct pool phpool[PHPOOL_MAX];
 #define	PHPOOL_FREELIST_NELEM(idx) \
-	(((idx) == 0) ? 0 : BITMAP_SIZE * (1 << (idx)))
+	(((idx) == 0) ? BITMAP_MIN_SIZE : BITMAP_SIZE * (1 << (idx)))
 
 #if defined(KASAN)
 #define POOL_REDZONE
@@ -162,6 +162,7 @@ static unsigned int poolid_counter = 0;
 typedef uint32_t pool_item_bitmap_t;
 #define	BITMAP_SIZE	(CHAR_BIT * sizeof(pool_item_bitmap_t))
 #define	BITMAP_MASK	(BITMAP_SIZE - 1)
+#define	BITMAP_MIN_SIZE	(CHAR_BIT * sizeof(((struct pool_item_header *)NULL)->ph_u2))
 
 struct pool_item_header {
 	/* Page headers */
@@ -201,6 +202,9 @@ struct pool_item_header {
 
 #define PHSIZE	ALIGN(sizeof(struct pool_item_header))
 
+CTASSERT(offsetof(struct pool_item_header, ph_u2) +
+    BITMAP_MIN_SIZE / CHAR_BIT == sizeof(struct pool_item_header));
+
 #if defined(DIAGNOSTIC) && !defined(KASAN)
 #define POOL_CHECK_MAGIC
 #endif
@@ -588,13 +592,11 @@ pool_subsystem_init(void)
 		size_t sz;
 
 		nelem = PHPOOL_FREELIST_NELEM(idx);
+		KASSERT(nelem != 0);
 		snprintf(phpool_names[idx], sizeof(phpool_names[idx]),
 		    "phpool-%d", nelem);
-		sz = sizeof(struct pool_item_header);
-		if (nelem) {
-			sz = offsetof(struct pool_item_header,
-			    ph_bitmap[howmany(nelem, BITMAP_SIZE)]);
-		}
+		sz = offsetof(struct pool_item_header,
+		    ph_bitmap[howmany(nelem, BITMAP_SIZE)]);
 		pool_init(&phpool[idx], sz, 0, 0, 0,
 		    phpool_names[idx], &pool_allocator_meta, IPL_VM);
 	}
@@ -657,12 +659,16 @@ pool_init_is_usebmap(const struct pool *
 	}
 
 	/*
-	 * If we're on-page, and the page header can already contain a bitmap
-	 * big enough to cover all the items of the page, go with a bitmap.
+	 * If we're off-page, go with a bitmap.
 	 */
 	if (!(pp->pr_roflags & PR_PHINPAGE)) {
-		return false;
+		return true;
 	}
+
+	/*
+	 * If we're on-page, and the page header can already contain a bitmap
+	 * big enough to cover all the items of the page, go with a bitmap.
+	 */
 	bmapsize = roundup(PHSIZE, pp->pr_align) -
 	    offsetof(struct pool_item_header, ph_bitmap[0]);
 	KASSERT(bmapsize % sizeof(pool_item_bitmap_t) == 0);
@@ -801,14 +807,15 @@ pool_init(struct pool *pp, size_t size, 
 	}
 
 	/*
-	 * If we're off-page and use a bitmap, choose the appropriate pool to
-	 * allocate page headers, whose size varies depending on the bitmap. If
-	 * we're just off-page, take the first pool, no extra size. If we're
-	 * on-page, nothing to do.
+	 * If we're off-page, then we're using a bitmap; choose the appropriate
+	 * pool to allocate page headers, whose size varies depending on the
+	 * bitmap. If we're on-page, nothing to do.
 	 */
-	if (!(pp->pr_roflags & PR_PHINPAGE) && (pp->pr_roflags & PR_USEBMAP)) {
+	if (!(pp->pr_roflags & PR_PHINPAGE)) {
 		int idx;
 
+		KASSERT(pp->pr_roflags & PR_USEBMAP);
+
 		for (idx = 0; pp->pr_itemsperpage > PHPOOL_FREELIST_NELEM(idx);
 		    idx++) {
 			/* nothing */
@@ -823,8 +830,6 @@ pool_init(struct pool *pp, size_t size, 
 			    pp->pr_wchan, pp->pr_itemsperpage);
 		}
 		pp->pr_phpool = &phpool[idx];
-	} else if (!(pp->pr_roflags & PR_PHINPAGE)) {
-		pp->pr_phpool = &phpool[0];
 	} else {
 		pp->pr_phpool = NULL;
 	}

Reply via email to