Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys Add DMA instrumentation in KASAN. We note the original b...



details:   https://anonhg.NetBSD.org/src/rev/90ee36dc899c
branches:  trunk
changeset: 459999:90ee36dc899c
user:      maxv <maxv%NetBSD.org@localhost>
date:      Fri Oct 04 06:27:42 2019 +0000

description:
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.

diffstat:

 sys/arch/amd64/include/types.h  |    3 +-
 sys/arch/x86/include/bus_defs.h |   11 +++-
 sys/arch/x86/x86/bus_dma.c      |   15 +++++-
 sys/kern/subr_asan.c            |  103 ++++++++++++++++++++++++++++++++++++++-
 sys/sys/asan.h                  |   22 ++++++-
 5 files changed, 142 insertions(+), 12 deletions(-)

diffs (300 lines):

diff -r 15add780f85e -r 90ee36dc899c sys/arch/amd64/include/types.h
--- a/sys/arch/amd64/include/types.h    Fri Oct 04 05:48:11 2019 +0000
+++ b/sys/arch/amd64/include/types.h    Fri Oct 04 06:27:42 2019 +0000
@@ -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 @@
 #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)
diff -r 15add780f85e -r 90ee36dc899c sys/arch/x86/include/bus_defs.h
--- a/sys/arch/x86/include/bus_defs.h   Fri Oct 04 05:48:11 2019 +0000
+++ b/sys/arch/x86/include/bus_defs.h   Fri Oct 04 06:27:42 2019 +0000
@@ -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 @@
        /*
         * 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 */
diff -r 15add780f85e -r 90ee36dc899c sys/arch/x86/x86/bus_dma.c
--- a/sys/arch/x86/x86/bus_dma.c        Fri Oct 04 05:48:11 2019 +0000
+++ b/sys/arch/x86/x86/bus_dma.c        Fri Oct 04 06:27:42 2019 +0000
@@ -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 @@
 #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_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_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_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_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_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) {
diff -r 15add780f85e -r 90ee36dc899c sys/kern/subr_asan.c
--- a/sys/kern/subr_asan.c      Fri Oct 04 05:48:11 2019 +0000
+++ b/sys/kern/subr_asan.c      Fri Oct 04 06:27:42 2019 +0000
@@ -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 @@
 
 /* -------------------------------------------------------------------------- */
 
+#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);
 
diff -r 15add780f85e -r 90ee36dc899c sys/sys/asan.h
--- a/sys/sys/asan.h    Fri Oct 04 05:48:11 2019 +0000
+++ b/sys/sys/asan.h    Fri Oct 04 06:27:42 2019 +0000
@@ -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_ */



Home | Main Index | Thread Index | Old Index