git: b261bb4057f4 - main - vfs: Add KASAN state transitions for vnodes
Mark Johnston
markj at FreeBSD.org
Tue Apr 13 21:42:40 UTC 2021
The branch main has been updated by markj:
URL: https://cgit.FreeBSD.org/src/commit/?id=b261bb4057f4abbc1366e4af8e9e4081d039be4a
commit b261bb4057f4abbc1366e4af8e9e4081d039be4a
Author: Mark Johnston <markj at FreeBSD.org>
AuthorDate: 2021-04-13 21:40:11 +0000
Commit: Mark Johnston <markj at FreeBSD.org>
CommitDate: 2021-04-13 21:42:21 +0000
vfs: Add KASAN state transitions for vnodes
vnodes are a bit special in that they may exist on per-CPU lists even
while free. Add a KASAN-only destructor that poisons regions of each
vnode that are not expected to be accessed after a free.
MFC after: 2 weeks
Sponsored by: The FreeBSD Foundation
Differential Revision: https://reviews.freebsd.org/D29459
---
sys/kern/vfs_subr.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 64 insertions(+), 2 deletions(-)
diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c
index af12252e8a88..2be3a81ad799 100644
--- a/sys/kern/vfs_subr.c
+++ b/sys/kern/vfs_subr.c
@@ -48,6 +48,7 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/asan.h>
#include <sys/bio.h>
#include <sys/buf.h>
#include <sys/capsicum.h>
@@ -527,6 +528,54 @@ vn_free_marker(struct vnode *vp)
free(vp, M_VNODE_MARKER);
}
+#ifdef KASAN
+static int
+vnode_ctor(void *mem, int size, void *arg __unused, int flags __unused)
+{
+ kasan_mark(mem, size, roundup2(size, UMA_ALIGN_PTR + 1), 0);
+ return (0);
+}
+
+static void
+vnode_dtor(void *mem, int size, void *arg __unused)
+{
+ size_t end1, end2, off1, off2;
+
+ _Static_assert(offsetof(struct vnode, v_vnodelist) <
+ offsetof(struct vnode, v_dbatchcpu),
+ "KASAN marks require updating");
+
+ off1 = offsetof(struct vnode, v_vnodelist);
+ off2 = offsetof(struct vnode, v_dbatchcpu);
+ end1 = off1 + sizeof(((struct vnode *)NULL)->v_vnodelist);
+ end2 = off2 + sizeof(((struct vnode *)NULL)->v_dbatchcpu);
+
+ /*
+ * Access to the v_vnodelist and v_dbatchcpu fields are permitted even
+ * after the vnode has been freed. Try to get some KASAN coverage by
+ * marking everything except those two fields as invalid. Because
+ * KASAN's tracking is not byte-granular, any preceding fields sharing
+ * the same 8-byte aligned word must also be marked valid.
+ */
+
+ /* Handle the area from the start until v_vnodelist... */
+ off1 = rounddown2(off1, KASAN_SHADOW_SCALE);
+ kasan_mark(mem, off1, off1, KASAN_UMA_FREED);
+
+ /* ... then the area between v_vnodelist and v_dbatchcpu ... */
+ off1 = roundup2(end1, KASAN_SHADOW_SCALE);
+ off2 = rounddown2(off2, KASAN_SHADOW_SCALE);
+ if (off2 > off1)
+ kasan_mark((void *)((char *)mem + off1), off2 - off1,
+ off2 - off1, KASAN_UMA_FREED);
+
+ /* ... and finally the area from v_dbatchcpu to the end. */
+ off2 = roundup2(end2, KASAN_SHADOW_SCALE);
+ kasan_mark((void *)((char *)mem + off2), size - off2, size - off2,
+ KASAN_UMA_FREED);
+}
+#endif /* KASAN */
+
/*
* Initialize a vnode as it first enters the zone.
*/
@@ -592,6 +641,8 @@ vnode_fini(void *mem, int size)
mtx_destroy(&vp->v_interlock);
bo = &vp->v_bufobj;
rw_destroy(BO_LOCKPTR(bo));
+
+ kasan_mark(mem, size, size, 0);
}
/*
@@ -619,6 +670,8 @@ static void
vntblinit(void *dummy __unused)
{
struct vdbatch *vd;
+ uma_ctor ctor;
+ uma_dtor dtor;
int cpu, physvnodes, virtvnodes;
u_int i;
@@ -658,9 +711,18 @@ vntblinit(void *dummy __unused)
TAILQ_INSERT_HEAD(&vnode_list, vnode_list_free_marker, v_vnodelist);
vnode_list_reclaim_marker = vn_alloc_marker(NULL);
TAILQ_INSERT_HEAD(&vnode_list, vnode_list_reclaim_marker, v_vnodelist);
- vnode_zone = uma_zcreate("VNODE", sizeof (struct vnode), NULL, NULL,
- vnode_init, vnode_fini, UMA_ALIGN_PTR, 0);
+
+#ifdef KASAN
+ ctor = vnode_ctor;
+ dtor = vnode_dtor;
+#else
+ ctor = NULL;
+ dtor = NULL;
+#endif
+ vnode_zone = uma_zcreate("VNODE", sizeof(struct vnode), ctor, dtor,
+ vnode_init, vnode_fini, UMA_ALIGN_PTR, UMA_ZONE_NOKASAN);
uma_zone_set_smr(vnode_zone, vfs_smr);
+
/*
* Preallocate enough nodes to support one-per buf so that
* we can not fail an insert. reassignbuf() callers can not
More information about the dev-commits-src-main
mailing list