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_ */