Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys Add support for detecting use-after-frees in KASAN. We p...
details: https://anonhg.NetBSD.org/src/rev/00d189b03aba
branches: trunk
changeset: 995347:00d189b03aba
user: maxv <maxv%NetBSD.org@localhost>
date: Sun Dec 16 21:03:35 2018 +0000
description:
Add support for detecting use-after-frees in KASAN. We poison each freed
buffer, any subsequent read or write will be detected as illegal.
* Add POOL_CHECK_MAGIC, which is disabled under KASAN, because the same
detection is done in a better way.
* Register the size+redzone in the pool structure, to reduce the overhead.
* Fix the CTOR/DTOR check in KLEAK, the fields are never NULL.
diffstat:
sys/kern/subr_pool.c | 86 ++++++++++++++++++++++++++++++++++++++-------------
sys/sys/pool.h | 3 +-
2 files changed, 66 insertions(+), 23 deletions(-)
diffs (253 lines):
diff -r 6a0ce2827d42 -r 00d189b03aba sys/kern/subr_pool.c
--- a/sys/kern/subr_pool.c Sun Dec 16 20:58:00 2018 +0000
+++ b/sys/kern/subr_pool.c Sun Dec 16 21:03:35 2018 +0000
@@ -1,7 +1,7 @@
-/* $NetBSD: subr_pool.c,v 1.228 2018/12/02 21:00:13 maxv Exp $ */
-
-/*-
- * Copyright (c) 1997, 1999, 2000, 2002, 2007, 2008, 2010, 2014, 2015
+/* $NetBSD: subr_pool.c,v 1.229 2018/12/16 21:03:35 maxv Exp $ */
+
+/*
+ * Copyright (c) 1997, 1999, 2000, 2002, 2007, 2008, 2010, 2014, 2015, 2018
* The NetBSD Foundation, Inc.
* All rights reserved.
*
@@ -33,7 +33,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: subr_pool.c,v 1.228 2018/12/02 21:00:13 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: subr_pool.c,v 1.229 2018/12/16 21:03:35 maxv Exp $");
#ifdef _KERNEL_OPT
#include "opt_ddb.h"
@@ -100,10 +100,12 @@
static void pool_redzone_init(struct pool *, size_t);
static void pool_redzone_fill(struct pool *, void *);
static void pool_redzone_check(struct pool *, void *);
+static void pool_cache_redzone_check(pool_cache_t, void *);
#else
-# define pool_redzone_init(pp, sz) /* NOTHING */
-# define pool_redzone_fill(pp, ptr) /* NOTHING */
-# define pool_redzone_check(pp, ptr) /* NOTHING */
+# define pool_redzone_init(pp, sz) __nothing
+# define pool_redzone_fill(pp, ptr) __nothing
+# define pool_redzone_check(pp, ptr) __nothing
+# define pool_cache_redzone_check(pc, ptr) __nothing
#endif
#ifdef KLEAK
@@ -114,6 +116,11 @@
#define pool_cache_kleak_fill(pc, ptr) __nothing
#endif
+#define pc_has_ctor(pc) \
+ (pc->pc_ctor != (int (*)(void *, void *, int))nullop)
+#define pc_has_dtor(pc) \
+ (pc->pc_dtor != (void (*)(void *, void *))nullop)
+
static void *pool_page_alloc_meta(struct pool *, int);
static void pool_page_free_meta(struct pool *, void *);
@@ -170,8 +177,12 @@
#define ph_itemlist ph_u.phu_normal.phu_itemlist
#define ph_bitmap ph_u.phu_notouch.phu_bitmap
+#if defined(DIAGNOSTIC) && !defined(KASAN)
+#define POOL_CHECK_MAGIC
+#endif
+
struct pool_item {
-#ifdef DIAGNOSTIC
+#ifdef POOL_CHECK_MAGIC
u_int pi_magic;
#endif
#define PI_MAGIC 0xdeaddeadU
@@ -890,10 +901,12 @@
KASSERTMSG((pp->pr_nitems > 0),
"%s: [%s] nitems %u inconsistent on itemlist",
__func__, pp->pr_wchan, pp->pr_nitems);
+#ifdef POOL_CHECK_MAGIC
KASSERTMSG((pi->pi_magic == PI_MAGIC),
"%s: [%s] free list modified: "
"magic=%x; page %p; item addr %p", __func__,
pp->pr_wchan, pi->pi_magic, ph->ph_page, pi);
+#endif
/*
* Remove from item list.
@@ -977,7 +990,7 @@
if (pp->pr_roflags & PR_NOTOUCH) {
pr_item_notouch_put(pp, ph, v);
} else {
-#ifdef DIAGNOSTIC
+#ifdef POOL_CHECK_MAGIC
pi->pi_magic = PI_MAGIC;
#endif
#ifdef DEBUG
@@ -989,6 +1002,13 @@
}
}
#endif
+ if (pp->pr_redzone) {
+ /*
+ * Mark the pool_item as valid. The rest is already
+ * invalid.
+ */
+ kasan_alloc(pi, sizeof(*pi), sizeof(*pi));
+ }
LIST_INSERT_HEAD(&ph->ph_itemlist, pi, pi_list);
}
@@ -1237,7 +1257,7 @@
/* Insert on page list */
LIST_INSERT_HEAD(&ph->ph_itemlist, pi, pi_list);
-#ifdef DIAGNOSTIC
+#ifdef POOL_CHECK_MAGIC
pi->pi_magic = PI_MAGIC;
#endif
cp = (char *)cp + pp->pr_size;
@@ -1540,12 +1560,12 @@
void (*pr)(const char *, ...))
{
struct pool_item_header *ph;
- struct pool_item *pi __diagused;
LIST_FOREACH(ph, pl, ph_pagelist) {
(*pr)("\t\tpage %p, nmissing %d, time %" PRIu32 "\n",
ph->ph_page, ph->ph_nmissing, ph->ph_time);
-#ifdef DIAGNOSTIC
+#ifdef POOL_CHECK_MAGIC
+ struct pool_item *pi;
if (!(pp->pr_roflags & PR_NOTOUCH)) {
LIST_FOREACH(pi, &ph->ph_itemlist, pi_list) {
if (pi->pi_magic != PI_MAGIC) {
@@ -1700,7 +1720,7 @@
pi != NULL;
pi = LIST_NEXT(pi,pi_list), n++) {
-#ifdef DIAGNOSTIC
+#ifdef POOL_CHECK_MAGIC
if (pi->pi_magic != PI_MAGIC) {
if (label != NULL)
printf("%s: ", label);
@@ -2006,6 +2026,15 @@
static void
pool_cache_destruct_object1(pool_cache_t pc, void *object)
{
+ if (pc->pc_pool.pr_redzone) {
+ /*
+ * The object is marked as invalid. Temporarily mark it as
+ * valid for the destructor. pool_put below will re-mark it
+ * as invalid.
+ */
+ kasan_alloc(object, pc->pc_pool.pr_reqsize,
+ pc->pc_pool.pr_reqsize_with_redzone);
+ }
(*pc->pc_dtor)(pc->pc_arg, object);
pool_put(&pc->pc_pool, object);
@@ -2463,7 +2492,7 @@
int s;
KASSERT(object != NULL);
- pool_redzone_check(&pc->pc_pool, object);
+ pool_cache_redzone_check(pc, object);
FREECHECK_IN(&pc->pc_freecheck, object);
/* Lock out interrupts and disable preemption. */
@@ -2697,6 +2726,9 @@
{
struct pool_allocator *pa = pp->pr_alloc;
+ if (pp->pr_redzone) {
+ kasan_alloc(v, pa->pa_pagesz, pa->pa_pagesz);
+ }
(*pa->pa_free)(pp, v);
}
@@ -2753,7 +2785,7 @@
static void
pool_cache_kleak_fill(pool_cache_t pc, void *p)
{
- if (__predict_false(pc->pc_ctor != NULL || pc->pc_dtor != NULL)) {
+ if (__predict_false(pc_has_ctor(pc) || pc_has_dtor(pc))) {
return;
}
pool_kleak_fill(&pc->pc_pool, p);
@@ -2804,6 +2836,7 @@
*/
if (pp->pr_size - requested_size >= redzsz) {
pp->pr_reqsize = requested_size;
+ pp->pr_reqsize_with_redzone = requested_size + redzsz;
pp->pr_redzone = true;
return;
}
@@ -2817,6 +2850,7 @@
/* Ok, we can */
pp->pr_size = nsz;
pp->pr_reqsize = requested_size;
+ pp->pr_reqsize_with_redzone = requested_size + redzsz;
pp->pr_redzone = true;
} else {
/* No space for a red zone... snif :'( */
@@ -2832,9 +2866,7 @@
if (!pp->pr_redzone)
return;
#ifdef KASAN
- size_t size_with_redzone = pp->pr_reqsize;
- kasan_add_redzone(&size_with_redzone);
- kasan_alloc(p, pp->pr_reqsize, size_with_redzone);
+ kasan_alloc(p, pp->pr_reqsize, pp->pr_reqsize_with_redzone);
#else
uint8_t *cp, pat;
const uint8_t *ep;
@@ -2863,9 +2895,7 @@
if (!pp->pr_redzone)
return;
#ifdef KASAN
- size_t size_with_redzone = pp->pr_reqsize;
- kasan_add_redzone(&size_with_redzone);
- kasan_free(p, size_with_redzone);
+ kasan_alloc(p, 0, pp->pr_reqsize_with_redzone);
#else
uint8_t *cp, pat, expected;
const uint8_t *ep;
@@ -2892,6 +2922,18 @@
#endif
}
+static void
+pool_cache_redzone_check(pool_cache_t pc, void *p)
+{
+#ifdef KASAN
+ /* If there is a ctor/dtor, leave the data as valid. */
+ if (__predict_false(pc_has_ctor(pc) || pc_has_dtor(pc))) {
+ return;
+ }
+#endif
+ pool_redzone_check(&pc->pc_pool, p);
+}
+
#endif /* POOL_REDZONE */
diff -r 6a0ce2827d42 -r 00d189b03aba sys/sys/pool.h
--- a/sys/sys/pool.h Sun Dec 16 20:58:00 2018 +0000
+++ b/sys/sys/pool.h Sun Dec 16 21:03:35 2018 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: pool.h,v 1.82 2017/12/16 03:13:29 mrg Exp $ */
+/* $NetBSD: pool.h,v 1.83 2018/12/16 21:03:35 maxv Exp $ */
/*-
* Copyright (c) 1997, 1998, 1999, 2000, 2007 The NetBSD Foundation, Inc.
@@ -195,6 +195,7 @@
void *pr_qcache;
bool pr_redzone;
size_t pr_reqsize;
+ size_t pr_reqsize_with_redzone;
};
/*
Home |
Main Index |
Thread Index |
Old Index