Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys Introduce POOL_QUARANTINE, a feature that creates a wind...
details: https://anonhg.NetBSD.org/src/rev/2b4306142e42
branches: trunk
changeset: 450413:2b4306142e42
user: maxv <maxv%NetBSD.org@localhost>
date: Sat Apr 13 08:41:36 2019 +0000
description:
Introduce POOL_QUARANTINE, a feature that creates a window during which a
freed buffer cannot be reallocated. This greatly helps detecting
use-after-frees, because they are not short-lived anymore.
We maintain a per-pool fifo of 128 buffers. On each pool_put, we do a real
free of the oldest buffer, and insert the new buffer. Before insertion, we
mark the buffer as invalid with KASAN. On each pool_cache_put, we destruct
the object, so it lands in pool_put, and the quarantine is handled there.
POOL_QUARANTINE can be used in conjunction with KASAN to detect more
use-after-free bugs.
diffstat:
sys/arch/amd64/conf/GENERIC | 6 ++-
sys/conf/files | 3 +-
sys/kern/subr_pool.c | 87 +++++++++++++++++++++++++++++++++++++++++++-
sys/sys/pool.h | 15 +++++++-
4 files changed, 104 insertions(+), 7 deletions(-)
diffs (237 lines):
diff -r b4ba57fa0a3e -r 2b4306142e42 sys/arch/amd64/conf/GENERIC
--- a/sys/arch/amd64/conf/GENERIC Sat Apr 13 08:26:14 2019 +0000
+++ b/sys/arch/amd64/conf/GENERIC Sat Apr 13 08:41:36 2019 +0000
@@ -1,4 +1,4 @@
-# $NetBSD: GENERIC,v 1.521 2019/03/28 19:00:40 maxv Exp $
+# $NetBSD: GENERIC,v 1.522 2019/04/13 08:41:37 maxv Exp $
#
# GENERIC machine description file
#
@@ -22,7 +22,7 @@
options INCLUDE_CONFIG_FILE # embed config file in kernel binary
-#ident "GENERIC-$Revision: 1.521 $"
+#ident "GENERIC-$Revision: 1.522 $"
maxusers 64 # estimated number of users
@@ -122,9 +122,11 @@
options KDTRACE_HOOKS # kernel DTrace hooks
# Kernel Address Sanitizer (kASan). You need to disable SVS to use it.
+# The quarantine is optional and can help KASAN find more use-after-frees.
#makeoptions KASAN=1 # Kernel Address Sanitizer
#options KASAN
#no options SVS
+#options POOL_QUARANTINE
# Kernel Info Leak Detector.
#makeoptions KLEAK=1
diff -r b4ba57fa0a3e -r 2b4306142e42 sys/conf/files
--- a/sys/conf/files Sat Apr 13 08:26:14 2019 +0000
+++ b/sys/conf/files Sat Apr 13 08:41:36 2019 +0000
@@ -1,4 +1,4 @@
-# $NetBSD: files,v 1.1233 2019/04/09 22:05:27 pgoyette Exp $
+# $NetBSD: files,v 1.1234 2019/04/13 08:41:36 maxv Exp $
# @(#)files.newconf 7.5 (Berkeley) 5/10/93
version 20171118
@@ -32,6 +32,7 @@
defflag KASAN
defflag KLEAK
defflag KCOV
+defflag opt_pool.h POOL_QUARANTINE
defparam opt_copy_symtab.h makeoptions_COPY_SYMTAB
diff -r b4ba57fa0a3e -r 2b4306142e42 sys/kern/subr_pool.c
--- a/sys/kern/subr_pool.c Sat Apr 13 08:26:14 2019 +0000
+++ b/sys/kern/subr_pool.c Sat Apr 13 08:41:36 2019 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: subr_pool.c,v 1.248 2019/04/07 09:20:04 maxv Exp $ */
+/* $NetBSD: subr_pool.c,v 1.249 2019/04/13 08:41:36 maxv Exp $ */
/*
* Copyright (c) 1997, 1999, 2000, 2002, 2007, 2008, 2010, 2014, 2015, 2018
@@ -33,11 +33,12 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: subr_pool.c,v 1.248 2019/04/07 09:20:04 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: subr_pool.c,v 1.249 2019/04/13 08:41:36 maxv Exp $");
#ifdef _KERNEL_OPT
#include "opt_ddb.h"
#include "opt_lockdebug.h"
+#include "opt_pool.h"
#include "opt_kleak.h"
#endif
@@ -111,6 +112,19 @@
#define pool_cache_kleak_fill(pc, ptr) __nothing
#endif
+#ifdef POOL_QUARANTINE
+static void pool_quarantine_init(struct pool *);
+static void pool_quarantine_flush(struct pool *);
+static bool pool_put_quarantine(struct pool *, void *,
+ struct pool_pagelist *);
+static bool pool_cache_put_quarantine(pool_cache_t, void *, paddr_t);
+#else
+#define pool_quarantine_init(a) __nothing
+#define pool_quarantine_flush(a) __nothing
+#define pool_put_quarantine(a, b, c) false
+#define pool_cache_put_quarantine(a, b, c) false
+#endif
+
#define pc_has_ctor(pc) \
(pc->pc_ctor != (int (*)(void *, void *, int))nullop)
#define pc_has_dtor(pc) \
@@ -733,6 +747,7 @@
pp->pr_drain_hook_arg = NULL;
pp->pr_freecheck = NULL;
pool_redzone_init(pp, size);
+ pool_quarantine_init(pp);
/*
* Decide whether to put the page header off-page to avoid wasting too
@@ -844,6 +859,8 @@
struct pool_pagelist pq;
struct pool_item_header *ph;
+ pool_quarantine_flush(pp);
+
/* Remove from global pool list */
mutex_enter(&pool_head_lock);
while (pp->pr_refcnt != 0)
@@ -1184,7 +1201,9 @@
LIST_INIT(&pq);
mutex_enter(&pp->pr_lock);
- pool_do_put(pp, v, &pq);
+ if (!pool_put_quarantine(pp, v, &pq)) {
+ pool_do_put(pp, v, &pq);
+ }
mutex_exit(&pp->pr_lock);
pr_pagelist_free(pp, &pq);
@@ -2586,6 +2605,10 @@
pool_cache_redzone_check(pc, object);
FREECHECK_IN(&pc->pc_freecheck, object);
+ if (pool_cache_put_quarantine(pc, object, pa)) {
+ return;
+ }
+
/* Lock out interrupts and disable preemption. */
s = splvm();
while (/* CONSTCOND */ true) {
@@ -2850,6 +2873,64 @@
}
#endif
+#ifdef POOL_QUARANTINE
+static void
+pool_quarantine_init(struct pool *pp)
+{
+ pp->pr_quar.rotor = 0;
+ memset(&pp->pr_quar, 0, sizeof(pp->pr_quar));
+}
+
+static void
+pool_quarantine_flush(struct pool *pp)
+{
+ pool_quar_t *quar = &pp->pr_quar;
+ struct pool_pagelist pq;
+ size_t i;
+
+ LIST_INIT(&pq);
+
+ mutex_enter(&pp->pr_lock);
+ for (i = 0; i < POOL_QUARANTINE_DEPTH; i++) {
+ if (quar->list[i] == 0)
+ continue;
+ pool_do_put(pp, (void *)quar->list[i], &pq);
+ }
+ mutex_exit(&pp->pr_lock);
+
+ pr_pagelist_free(pp, &pq);
+}
+
+static bool
+pool_put_quarantine(struct pool *pp, void *v, struct pool_pagelist *pq)
+{
+ pool_quar_t *quar = &pp->pr_quar;
+ uintptr_t old;
+
+ if (pp->pr_roflags & PR_NOTOUCH) {
+ return false;
+ }
+
+ pool_redzone_check(pp, v);
+
+ old = quar->list[quar->rotor];
+ quar->list[quar->rotor] = (uintptr_t)v;
+ quar->rotor = (quar->rotor + 1) % POOL_QUARANTINE_DEPTH;
+ if (old != 0) {
+ pool_do_put(pp, (void *)old, pq);
+ }
+
+ return true;
+}
+
+static bool
+pool_cache_put_quarantine(pool_cache_t pc, void *p, paddr_t pa)
+{
+ pool_cache_destruct_object(pc, p);
+ return true;
+}
+#endif
+
#ifdef POOL_REDZONE
#if defined(_LP64)
# define PRIME 0x9e37fffffffc0000UL
diff -r b4ba57fa0a3e -r 2b4306142e42 sys/sys/pool.h
--- a/sys/sys/pool.h Sat Apr 13 08:26:14 2019 +0000
+++ b/sys/sys/pool.h Sat Apr 13 08:41:36 2019 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: pool.h,v 1.87 2019/03/27 18:27:47 maxv Exp $ */
+/* $NetBSD: pool.h,v 1.88 2019/04/13 08:41:37 maxv Exp $ */
/*-
* Copyright (c) 1997, 1998, 1999, 2000, 2007 The NetBSD Foundation, Inc.
@@ -81,6 +81,10 @@
#include <sys/tree.h>
#include <sys/callback.h>
+#ifdef _KERNEL_OPT
+#include "opt_pool.h"
+#endif
+
#define POOL_PADDR_INVALID ((paddr_t) -1)
struct pool;
@@ -101,6 +105,12 @@
LIST_HEAD(pool_pagelist,pool_item_header);
SPLAY_HEAD(phtree, pool_item_header);
+#define POOL_QUARANTINE_DEPTH 128
+typedef struct {
+ size_t rotor;
+ intptr_t list[POOL_QUARANTINE_DEPTH];
+} pool_quar_t;
+
struct pool {
TAILQ_ENTRY(pool)
pr_poollist;
@@ -198,6 +208,9 @@
bool pr_redzone;
size_t pr_reqsize;
size_t pr_reqsize_with_redzone;
+#ifdef POOL_QUARANTINE
+ pool_quar_t pr_quar;
+#endif
};
/*
Home |
Main Index |
Thread Index |
Old Index