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