Module Name: src Committed By: maxv Date: Fri Aug 2 05:22:14 UTC 2019
Modified Files: src/sys/kern: subr_pool.c Log Message: Kernel Heap Hardening: perform certain sanity checks on the pool caches directly, to immediately detect certain bugs that would otherwise have been detected only later on the pool layer, if the buffer ever reached the pool layer. To generate a diff of this commit: cvs rdiff -u -r1.252 -r1.253 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.252 src/sys/kern/subr_pool.c:1.253 --- src/sys/kern/subr_pool.c:1.252 Sat Jun 29 11:13:23 2019 +++ src/sys/kern/subr_pool.c Fri Aug 2 05:22:14 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: subr_pool.c,v 1.252 2019/06/29 11:13:23 maxv Exp $ */ +/* $NetBSD: subr_pool.c,v 1.253 2019/08/02 05:22:14 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.252 2019/06/29 11:13:23 maxv Exp $"); +__KERNEL_RCSID(0, "$NetBSD: subr_pool.c,v 1.253 2019/08/02 05:22:14 maxv Exp $"); #ifdef _KERNEL_OPT #include "opt_ddb.h" @@ -216,6 +216,8 @@ struct pool_item { #define POOL_NEEDS_CATCHUP(pp) \ ((pp)->pr_nitems < (pp)->pr_minitems) +#define POOL_OBJ_TO_PAGE(pp, v) \ + (void *)((uintptr_t)v & pp->pr_alloc->pa_pagemask) /* * Pool cache management. @@ -408,6 +410,40 @@ pr_item_linkedlist_get(struct pool *pp, /* -------------------------------------------------------------------------- */ +static inline void +pr_phinpage_check(struct pool *pp, struct pool_item_header *ph, void *page, + void *object) +{ + if (__predict_false((void *)ph->ph_page != page)) { + panic("%s: [%s] item %p not part of pool", __func__, + pp->pr_wchan, object); + } + if (__predict_false((char *)object < (char *)page + ph->ph_off)) { + panic("%s: [%s] item %p below item space", __func__, + pp->pr_wchan, object); + } + if (__predict_false(ph->ph_poolid != pp->pr_poolid)) { + panic("%s: [%s] item %p poolid %u != %u", __func__, + pp->pr_wchan, object, ph->ph_poolid, pp->pr_poolid); + } +} + +static inline void +pc_phinpage_check(pool_cache_t pc, void *object) +{ + struct pool_item_header *ph; + struct pool *pp; + void *page; + + pp = &pc->pc_pool; + page = POOL_OBJ_TO_PAGE(pp, object); + ph = (struct pool_item_header *)page; + + pr_phinpage_check(pp, ph, page, object); +} + +/* -------------------------------------------------------------------------- */ + static inline int phtree_compare(struct pool_item_header *a, struct pool_item_header *b) { @@ -456,25 +492,10 @@ pr_find_pagehead(struct pool *pp, void * if ((pp->pr_roflags & PR_NOALIGN) != 0) { ph = pr_find_pagehead_noalign(pp, v); } else { - void *page = - (void *)((uintptr_t)v & pp->pr_alloc->pa_pagemask); - + void *page = POOL_OBJ_TO_PAGE(pp, v); if ((pp->pr_roflags & PR_PHINPAGE) != 0) { ph = (struct pool_item_header *)page; - if (__predict_false((void *)ph->ph_page != page)) { - panic("%s: [%s] item %p not part of pool", - __func__, pp->pr_wchan, v); - } - if (__predict_false((char *)v < (char *)page + - ph->ph_off)) { - panic("%s: [%s] item %p below item space", - __func__, pp->pr_wchan, v); - } - if (__predict_false(ph->ph_poolid != pp->pr_poolid)) { - panic("%s: [%s] item %p poolid %u != %u", - __func__, pp->pr_wchan, v, ph->ph_poolid, - pp->pr_poolid); - } + pr_phinpage_check(pp, ph, page, v); } else { tmp.ph_page = page; ph = SPLAY_FIND(phtree, &pp->pr_phtree, &tmp); @@ -1832,7 +1853,7 @@ pool_chk_page(struct pool *pp, const cha int n; if ((pp->pr_roflags & PR_NOALIGN) == 0) { - page = (void *)((uintptr_t)ph & pp->pr_alloc->pa_pagemask); + page = POOL_OBJ_TO_PAGE(pp, ph); if (page != ph->ph_page && (pp->pr_roflags & PR_PHINPAGE) != 0) { if (label != NULL) @@ -1866,7 +1887,7 @@ pool_chk_page(struct pool *pp, const cha if ((pp->pr_roflags & PR_NOALIGN) != 0) { continue; } - page = (void *)((uintptr_t)pi & pp->pr_alloc->pa_pagemask); + page = POOL_OBJ_TO_PAGE(pp, pi); if (page == ph->ph_page) continue; @@ -2616,6 +2637,10 @@ pool_cache_put_paddr(pool_cache_t pc, vo pool_cache_redzone_check(pc, object); FREECHECK_IN(&pc->pc_freecheck, object); + if (pc->pc_pool.pr_roflags & PR_PHINPAGE) { + pc_phinpage_check(pc, object); + } + if (pool_cache_put_quarantine(pc, object, pa)) { return; }