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;
}