Module Name:    src
Committed By:   maxv
Date:           Fri Oct  4 06:27:42 UTC 2019

Modified Files:
        src/sys/arch/amd64/include: types.h
        src/sys/arch/x86/include: bus_defs.h
        src/sys/arch/x86/x86: bus_dma.c
        src/sys/kern: subr_asan.c
        src/sys/sys: asan.h

Log Message:
Add DMA instrumentation in KASAN. We note the original buffer and length in
the map, and check the buffer on each bus_dmamap_sync. This allows us to
find DMA buffer overflows and UAFs, which couldn't be found before because
the device accesses to memory are outside of KASAN's control.


To generate a diff of this commit:
cvs rdiff -u -r1.62 -r1.63 src/sys/arch/amd64/include/types.h
cvs rdiff -u -r1.3 -r1.4 src/sys/arch/x86/include/bus_defs.h
cvs rdiff -u -r1.79 -r1.80 src/sys/arch/x86/x86/bus_dma.c
cvs rdiff -u -r1.14 -r1.15 src/sys/kern/subr_asan.c
cvs rdiff -u -r1.10 -r1.11 src/sys/sys/asan.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/amd64/include/types.h
diff -u src/sys/arch/amd64/include/types.h:1.62 src/sys/arch/amd64/include/types.h:1.63
--- src/sys/arch/amd64/include/types.h:1.62	Mon Sep 23 23:06:26 2019
+++ src/sys/arch/amd64/include/types.h	Fri Oct  4 06:27:42 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: types.h,v 1.62 2019/09/23 23:06:26 kamil Exp $	*/
+/*	$NetBSD: types.h,v 1.63 2019/10/04 06:27:42 maxv Exp $	*/
 
 /*-
  * Copyright (c) 1990 The Regents of the University of California.
@@ -108,6 +108,7 @@ typedef	unsigned char		__cpu_simple_lock
 #include "opt_kasan.h"
 #ifdef KASAN
 #define __HAVE_KASAN_INSTR_BUS
+#define __HAVE_KASAN_INSTR_DMA
 #endif
 #if defined(__x86_64__) && !defined(XENPV)
 #if !defined(KASAN)

Index: src/sys/arch/x86/include/bus_defs.h
diff -u src/sys/arch/x86/include/bus_defs.h:1.3 src/sys/arch/x86/include/bus_defs.h:1.4
--- src/sys/arch/x86/include/bus_defs.h:1.3	Mon Sep 23 16:17:58 2019
+++ src/sys/arch/x86/include/bus_defs.h	Fri Oct  4 06:27:42 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: bus_defs.h,v 1.3 2019/09/23 16:17:58 skrll Exp $	*/
+/*	$NetBSD: bus_defs.h,v 1.4 2019/10/04 06:27:42 maxv Exp $	*/
 
 /*-
  * Copyright (c) 1996, 1997, 1998, 2001 The NetBSD Foundation, Inc.
@@ -64,6 +64,10 @@
 #ifndef _X86_BUS_H_
 #define _X86_BUS_H_
 
+#ifdef _KERNEL_OPT
+#include "opt_kasan.h"
+#endif
+
 #include <x86/busdefs.h>
 
 #ifdef BUS_SPACE_DEBUG 
@@ -141,6 +145,11 @@ struct x86_bus_dmamap {
 	/*
 	 * PUBLIC MEMBERS: these are used by machine-independent code.
 	 */
+#if defined(KASAN)
+	void		*dm_buf;
+	bus_size_t	dm_buflen;
+	int		dm_buftype;
+#endif
 	bus_size_t	dm_maxsegsz;	/* largest possible segment */
 	bus_size_t	dm_mapsize;	/* size of the mapping */
 	int		dm_nsegs;	/* # valid segments in mapping */

Index: src/sys/arch/x86/x86/bus_dma.c
diff -u src/sys/arch/x86/x86/bus_dma.c:1.79 src/sys/arch/x86/x86/bus_dma.c:1.80
--- src/sys/arch/x86/x86/bus_dma.c:1.79	Fri Jun 14 03:35:31 2019
+++ src/sys/arch/x86/x86/bus_dma.c	Fri Oct  4 06:27:42 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: bus_dma.c,v 1.79 2019/06/14 03:35:31 mrg Exp $	*/
+/*	$NetBSD: bus_dma.c,v 1.80 2019/10/04 06:27:42 maxv Exp $	*/
 
 /*-
  * Copyright (c) 1996, 1997, 1998, 2007 The NetBSD Foundation, Inc.
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: bus_dma.c,v 1.79 2019/06/14 03:35:31 mrg Exp $");
+__KERNEL_RCSID(0, "$NetBSD: bus_dma.c,v 1.80 2019/10/04 06:27:42 maxv Exp $");
 
 /*
  * The following is included because _bus_dma_uiomove is derived from
@@ -95,6 +95,7 @@ __KERNEL_RCSID(0, "$NetBSD: bus_dma.c,v 
 #include <sys/malloc.h>
 #include <sys/mbuf.h>
 #include <sys/proc.h>
+#include <sys/asan.h>
 
 #include <sys/bus.h>
 #include <machine/bus_private.h>
@@ -1327,6 +1328,8 @@ bus_dmamap_sync(bus_dma_tag_t t, bus_dma
 {
 	bus_dma_tag_t it;
 
+	kasan_dma_sync(p, o, l, ops);
+
 	if ((t->bdt_exists & BUS_DMAMAP_OVERRIDE_SYNC) == 0)
 		;	/* skip override */
 	else for (it = t; it != NULL; it = it->bdt_super) {
@@ -1386,6 +1389,8 @@ bus_dmamap_load(bus_dma_tag_t t, bus_dma
 {
 	bus_dma_tag_t it;
 
+	kasan_dma_load(dmam, buf, buflen, KASAN_DMA_LINEAR);
+
 	if ((t->bdt_exists & BUS_DMAMAP_OVERRIDE_LOAD) == 0)
 		;	/* skip override */
 	else for (it = t; it != NULL; it = it->bdt_super) {
@@ -1404,6 +1409,8 @@ bus_dmamap_load_mbuf(bus_dma_tag_t t, bu
 {
 	bus_dma_tag_t it;
 
+	kasan_dma_load(dmam, chain, 0, KASAN_DMA_MBUF);
+
 	if ((t->bdt_exists & BUS_DMAMAP_OVERRIDE_LOAD_MBUF) == 0)
 		;	/* skip override */
 	else for (it = t; it != NULL; it = it->bdt_super) {
@@ -1422,6 +1429,8 @@ bus_dmamap_load_uio(bus_dma_tag_t t, bus
 {
 	bus_dma_tag_t it;
 
+	kasan_dma_load(dmam, uio, 0, KASAN_DMA_UIO);
+
 	if ((t->bdt_exists & BUS_DMAMAP_OVERRIDE_LOAD_UIO) == 0)
 		;	/* skip override */
 	else for (it = t; it != NULL; it = it->bdt_super) {
@@ -1441,6 +1450,8 @@ bus_dmamap_load_raw(bus_dma_tag_t t, bus
 {
 	bus_dma_tag_t it;
 
+	kasan_dma_load(dmam, NULL, 0, KASAN_DMA_RAW);
+
 	if ((t->bdt_exists & BUS_DMAMAP_OVERRIDE_LOAD_RAW) == 0)
 		;	/* skip override */
 	else for (it = t; it != NULL; it = it->bdt_super) {

Index: src/sys/kern/subr_asan.c
diff -u src/sys/kern/subr_asan.c:1.14 src/sys/kern/subr_asan.c:1.15
--- src/sys/kern/subr_asan.c:1.14	Sun Sep 22 10:35:12 2019
+++ src/sys/kern/subr_asan.c	Fri Oct  4 06:27:42 2019
@@ -1,7 +1,7 @@
-/*	$NetBSD: subr_asan.c,v 1.14 2019/09/22 10:35:12 maxv Exp $	*/
+/*	$NetBSD: subr_asan.c,v 1.15 2019/10/04 06:27:42 maxv Exp $	*/
 
 /*
- * Copyright (c) 2018 The NetBSD Foundation, Inc.
+ * Copyright (c) 2018-2019 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This code is derived from software contributed to The NetBSD Foundation
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: subr_asan.c,v 1.14 2019/09/22 10:35:12 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: subr_asan.c,v 1.15 2019/10/04 06:27:42 maxv Exp $");
 
 #include <sys/param.h>
 #include <sys/device.h>
@@ -932,6 +932,103 @@ ASAN_BUS_WRITE_FUNC(8, 64)
 
 /* -------------------------------------------------------------------------- */
 
+#ifdef __HAVE_KASAN_INSTR_DMA
+
+#include <sys/mbuf.h>
+
+static void
+kasan_dma_sync_linear(uint8_t *buf, bus_addr_t offset, bus_size_t len,
+    bool write, uintptr_t pc)
+{
+	kasan_shadow_check((uintptr_t)(buf + offset), len, write, pc);
+}
+
+static void
+kasan_dma_sync_mbuf(struct mbuf *m, bus_addr_t offset, bus_size_t len,
+    bool write, uintptr_t pc)
+{
+	bus_addr_t minlen;
+
+	for (; m != NULL && len != 0; m = m->m_next) {
+		kasan_shadow_check((uintptr_t)m, sizeof(*m), false, pc);
+
+		if (offset >= m->m_len) {
+			offset -= m->m_len;
+			continue;
+		}
+
+		minlen = MIN(len, m->m_len - offset);
+		kasan_shadow_check((uintptr_t)(mtod(m, char *) + offset),
+		    minlen, write, pc);
+
+		offset = 0;
+		len -= minlen;
+	}
+}
+
+static void
+kasan_dma_sync_uio(struct uio *uio, bus_addr_t offset, bus_size_t len,
+    bool write, uintptr_t pc)
+{
+	bus_size_t minlen, resid;
+	struct iovec *iov;
+	int i;
+
+	if (uio->uio_vmspace != NULL)
+		return;
+
+	kasan_shadow_check((uintptr_t)uio, sizeof(struct uio), false, pc);
+
+	resid = uio->uio_resid;
+	iov = uio->uio_iov;
+
+	for (i = 0; i < uio->uio_iovcnt && resid != 0; i++) {
+		kasan_shadow_check((uintptr_t)&iov[i], sizeof(iov[i]),
+		    false, pc);
+		minlen = MIN(resid, iov[i].iov_len);
+		kasan_shadow_check((uintptr_t)iov[i].iov_base, minlen,
+		    write, pc);
+		resid -= minlen;
+	}
+}
+
+void
+kasan_dma_sync(bus_dmamap_t map, bus_addr_t offset, bus_size_t len, int ops)
+{
+	bool write = (ops & (BUS_DMASYNC_PREWRITE|BUS_DMASYNC_POSTWRITE)) != 0;
+
+	switch (map->dm_buftype) {
+	case KASAN_DMA_LINEAR:
+		kasan_dma_sync_linear(map->dm_buf, offset, len, write,
+		    __RET_ADDR);
+		break;
+	case KASAN_DMA_MBUF:
+		kasan_dma_sync_mbuf(map->dm_buf, offset, len, write,
+		    __RET_ADDR);
+		break;
+	case KASAN_DMA_UIO:
+		kasan_dma_sync_uio(map->dm_buf, offset, len, write,
+		    __RET_ADDR);
+		break;
+	case KASAN_DMA_RAW:
+		break;
+	default:
+		panic("%s: impossible", __func__);
+	}
+}
+
+void
+kasan_dma_load(bus_dmamap_t map, void *buf, bus_size_t buflen, int type)
+{
+	map->dm_buf = buf;
+	map->dm_buflen = buflen;
+	map->dm_buftype = type;
+}
+
+#endif /* __HAVE_KASAN_INSTR_DMA */
+
+/* -------------------------------------------------------------------------- */
+
 void __asan_register_globals(struct __asan_global *, size_t);
 void __asan_unregister_globals(struct __asan_global *, size_t);
 

Index: src/sys/sys/asan.h
diff -u src/sys/sys/asan.h:1.10 src/sys/sys/asan.h:1.11
--- src/sys/sys/asan.h:1.10	Sun Apr  7 09:20:04 2019
+++ src/sys/sys/asan.h	Fri Oct  4 06:27:42 2019
@@ -1,7 +1,7 @@
-/*	$NetBSD: asan.h,v 1.10 2019/04/07 09:20:04 maxv Exp $	*/
+/*	$NetBSD: asan.h,v 1.11 2019/10/04 06:27:42 maxv Exp $	*/
 
 /*
- * Copyright (c) 2018 The NetBSD Foundation, Inc.
+ * Copyright (c) 2018-2019 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This code is derived from software contributed to The NetBSD Foundation
@@ -36,7 +36,9 @@
 #include "opt_kasan.h"
 #endif
 
+#ifdef KASAN
 #include <sys/types.h>
+#include <sys/bus.h>
 
 /* Stack redzone values. Part of the compiler ABI. */
 #define KASAN_STACK_LEFT	0xF1
@@ -52,17 +54,27 @@
 #define KASAN_POOL_REDZONE	0xFD
 #define KASAN_POOL_FREED	0xFE
 
-#ifdef KASAN
+/* DMA types. */
+#define KASAN_DMA_LINEAR	1
+#define KASAN_DMA_MBUF		2
+#define KASAN_DMA_UIO		3
+#define KASAN_DMA_RAW		4
+
 void kasan_shadow_map(void *, size_t);
 void kasan_early_init(void *);
 void kasan_init(void);
 void kasan_softint(struct lwp *);
 
+void kasan_dma_sync(bus_dmamap_t, bus_addr_t, bus_size_t, int);
+void kasan_dma_load(bus_dmamap_t, void *, bus_size_t, int);
+
 void kasan_add_redzone(size_t *);
 void kasan_mark(const void *, size_t, size_t, uint8_t);
 #else
-#define kasan_add_redzone(s)	__nothing
-#define kasan_mark(p, s, l, c)	__nothing
+#define kasan_dma_sync(m, a, s, o)	__nothing
+#define kasan_dma_load(m, b, s, o)	__nothing
+#define kasan_add_redzone(s)		__nothing
+#define kasan_mark(p, s, l, c)		__nothing
 #endif
 
 #endif /* !_SYS_ASAN_H_ */

Reply via email to