diff mbox series

[RFC,v2,22/25] kmsan: unpoisoning buffers from devices etc.

Message ID 20191030142237.249532-23-glider@google.com (mailing list archive)
State New, archived
Headers show
Series Add KernelMemorySanitizer infrastructure | expand

Commit Message

Alexander Potapenko Oct. 30, 2019, 2:22 p.m. UTC
When data is copied to memory from a device KMSAN should treat it as
initialized. In most cases it's enough to just unpoison the buffer that
is known to come from a device.
In the case with __do_page_cache_readahead() and bio_copy_user_iov() we
have to mark the whole pages as ignored by KMSAN, as it's not obvious
where these pages are read again.

Signed-off-by: Alexander Potapenko <glider@google.com>
To: Alexander Potapenko <glider@google.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Jens Axboe <axboe@kernel.dk>
Cc: "Theodore Ts'o" <tytso@mit.edu>
Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Cc: Martin K. Petersen <martin.petersen@oracle.com>
Cc: "Michael S. Tsirkin" <mst@redhat.com>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Eric Dumazet <edumazet@google.com>
Cc: Eric Van Hensbergen <ericvh@gmail.com>
Cc: Takashi Iwai <tiwai@suse.com>
Cc: Vegard Nossum <vegard.nossum@oracle.com>
Cc: Dmitry Vyukov <dvyukov@google.com>
Cc: Matthew Wilcox <willy@infradead.org>
Cc: linux-mm@kvack.org

---
Suggestions on how to avoid scattering too many annotations over the
code are welcome. Perhaps annotating DMA reads/writes is enough to get
rid of most of these annotations.

v2:
 - dropped a call to kmsan_unpoison_shadow() in do_read_cache_page()

Change-Id: Id460e7a86ce564f1357469f53d0c7410ca08f0e9
---
 block/bio.c                  | 20 ++++++++++++++++++++
 block/partition-generic.c    |  9 ++++++++-
 drivers/char/random.c        |  2 ++
 drivers/input/serio/libps2.c |  6 +++++-
 drivers/scsi/scsi_lib.c      |  4 ++++
 drivers/usb/core/message.c   |  6 +++++-
 drivers/virtio/virtio_ring.c | 14 ++++++++++++++
 fs/buffer.c                  |  7 ++++++-
 include/linux/dma-mapping.h  |  2 ++
 include/linux/skbuff.h       |  5 ++++-
 mm/filemap.c                 |  1 +
 mm/readahead.c               |  6 ++++++
 net/9p/protocol.c            |  2 ++
 sound/core/oss/pcm_oss.c     |  7 +++++++
 14 files changed, 86 insertions(+), 5 deletions(-)

Comments

Christoph Hellwig Oct. 30, 2019, 2:38 p.m. UTC | #1
On Wed, Oct 30, 2019 at 03:22:34PM +0100, glider@google.com wrote:
> When data is copied to memory from a device KMSAN should treat it as
> initialized. In most cases it's enough to just unpoison the buffer that
> is known to come from a device.
> In the case with __do_page_cache_readahead() and bio_copy_user_iov() we
> have to mark the whole pages as ignored by KMSAN, as it's not obvious
> where these pages are read again.

A lot of this looks pretty strange.  Why don't you instrument
the dma_map / dma_sync infrastucture?  That should avoid most of the
driver hooks.
Alexander Potapenko Nov. 5, 2019, 3:02 p.m. UTC | #2
On Wed, Oct 30, 2019 at 3:38 PM Christoph Hellwig <hch@lst.de> wrote:
>
> On Wed, Oct 30, 2019 at 03:22:34PM +0100, glider@google.com wrote:
> > When data is copied to memory from a device KMSAN should treat it as
> > initialized. In most cases it's enough to just unpoison the buffer that
> > is known to come from a device.
> > In the case with __do_page_cache_readahead() and bio_copy_user_iov() we
> > have to mark the whole pages as ignored by KMSAN, as it's not obvious
> > where these pages are read again.
>
> A lot of this looks pretty strange.  Why don't you instrument
> the dma_map / dma_sync infrastucture?  That should avoid most of the
> driver hooks.

That's the exact reason I'm sending these patches: I simply don't know
the kernel code good enough.
May I ask you for some pointers?
My goal is to mark data copied from the device as initialized (by
calling kmsan_unpoison_shadow(ptr, size)), and, if possible, check
data that's about to be copied to device (by calling
kmsan_check_memory(ptr, size)).
My understanding is that:
 1. calls to dma_map_* and dma_sync_* with direction=DMA_FROM_DEVICE
denote that the corresponding kernel buffer can be marked as
initialized
 2. calls to dma_unmap_* and dma_sync_* with direction=DMA_TO_DEVICE
denote that the buffer will be copied to device (and must be checked
for being initialized)
 3. I need some translation table to find out the virtual address for
a given dma_addr_t
Does this sound reasonable?
I still don't understand how to handle DMA_BIDIRECTIONAL. Will it be
sane to assume that at each dma_{map,sync,unmap}_* call must always
check the memory range and then unpoison it?

Thanks in advance
Alexander Potapenko Nov. 7, 2019, 1 p.m. UTC | #3
On Tue, Nov 5, 2019 at 4:02 PM Alexander Potapenko <glider@google.com> wrote:
>
> On Wed, Oct 30, 2019 at 3:38 PM Christoph Hellwig <hch@lst.de> wrote:
> >
> > On Wed, Oct 30, 2019 at 03:22:34PM +0100, glider@google.com wrote:
> > > When data is copied to memory from a device KMSAN should treat it as
> > > initialized. In most cases it's enough to just unpoison the buffer that
> > > is known to come from a device.
> > > In the case with __do_page_cache_readahead() and bio_copy_user_iov() we
> > > have to mark the whole pages as ignored by KMSAN, as it's not obvious
> > > where these pages are read again.
> >
> > A lot of this looks pretty strange.  Why don't you instrument
> > the dma_map / dma_sync infrastucture?  That should avoid most of the
> > driver hooks.
>
> That's the exact reason I'm sending these patches: I simply don't know
> the kernel code good enough.
> May I ask you for some pointers?
> My goal is to mark data copied from the device as initialized (by
> calling kmsan_unpoison_shadow(ptr, size)), and, if possible, check
> data that's about to be copied to device (by calling
> kmsan_check_memory(ptr, size)).
> My understanding is that:
>  1. calls to dma_map_* and dma_sync_* with direction=DMA_FROM_DEVICE
> denote that the corresponding kernel buffer can be marked as
> initialized
>  2. calls to dma_unmap_* and dma_sync_* with direction=DMA_TO_DEVICE
> denote that the buffer will be copied to device (and must be checked
> for being initialized)
>  3. I need some translation table to find out the virtual address for
> a given dma_addr_t
> Does this sound reasonable?
Initializing memory in dma_map_ still leaves out the reports as the one below.
There seems to be a DMA access somewhere in blk_execute_rq(), but I
fail to see why it's not covered.

=============================================
BUG: KMSAN: uninit-value in[<      none      >]
sr_check_events+0x1091/0x1190 drivers/scsi/sr.c:246
 CPU: 0 PID: 5 Comm: kworker/0:0 Not tainted 5.4.0-rc5+ #3266
 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.12.0-1 04/01/2014
 Workqueue: events_freezable_power_ disk_events_workfn
 Call Trace:
 [<     inline     >] __dump_stack lib/dump_stack.c:77
 [<      none      >] dump_stack+0x196/0x1f0 lib/dump_stack.c:113
 [<      none      >] kmsan_report+0x127/0x220 mm/kmsan/kmsan_report.c:108
 [<      none      >] __msan_warning+0x73/0xe0 mm/kmsan/kmsan_instr.c:245
 [<     inline     >] sr_get_events drivers/scsi/sr.c:213
 [<      none      >] sr_check_events+0x1091/0x1190 drivers/scsi/sr.c:246
 [<     inline     >] cdrom_update_events drivers/cdrom/cdrom.c:1476
 [<      none      >] cdrom_check_events+0xc3/0x260 drivers/cdrom/cdrom.c:1486
 [<      none      >] sr_block_check_events+0x3c4/0x670 drivers/scsi/sr.c:614
 [<      none      >] disk_check_events+0x154/0x8b0 block/genhd.c:1855
 [<      none      >] disk_events_workfn+0x47/0x50 block/genhd.c:1841
 [<      none      >] process_one_work+0x1556/0x1ef0 kernel/workqueue.c:2269
...
 Uninit was stored to memory at:
 [<     inline     >] kmsan_save_stack_with_flags mm/kmsan/kmsan.c:151
 [<      none      >] kmsan_internal_chain_origin+0xa3/0x160
mm/kmsan/kmsan.c:319
 [<      none      >] kmsan_memcpy_memmove_metadata+0x271/0x2e0
mm/kmsan/kmsan.c:254
 [<      none      >] kmsan_memcpy_metadata+0xb/0x10 mm/kmsan/kmsan.c:274
 [<      none      >] __msan_memcpy+0x55/0x70 mm/kmsan/kmsan_instr.c:129
 [<      none      >] bio_copy_kern_endio_read+0x467/0x990 block/bio.c:1543
 [<      none      >] bio_endio+0xa36/0xbb0 block/bio.c:1850
 [<     inline     >] req_bio_endio block/blk-core.c:242
 [<      none      >] blk_update_request+0xd3c/0x20a0 block/blk-core.c:1462
 [<      none      >] scsi_end_request+0x10b/0xeb0 drivers/scsi/scsi_lib.c:579
 [<      none      >] scsi_io_completion+0x279/0x2660
drivers/scsi/scsi_lib.c:963
 [<      none      >] scsi_finish_command+0x6f9/0x720 drivers/scsi/scsi.c:228
 [<      none      >] scsi_softirq_done+0x772/0x980 drivers/scsi/scsi_lib.c:1477
 [<      none      >] blk_done_softirq+0x300/0x4f0 block/blk-softirq.c:37
 [<      none      >] __do_softirq+0x311/0x83d kernel/softirq.c:293
...
 Uninit was created at:
 [<      none      >] kmsan_save_stack_with_flags+0x3f/0x90 mm/kmsan/kmsan.c:151
 [<     inline     >] kmsan_internal_alloc_meta_for_pages
mm/kmsan/kmsan_shadow.c:362
 [<      none      >] kmsan_alloc_page+0x14e/0x360 mm/kmsan/kmsan_shadow.c:391
 [<      none      >] __alloc_pages_nodemask+0x594e/0x6050 mm/page_alloc.c:4796
 [<      none      >] alloc_pages_current+0x682/0x990 mm/mempolicy.c:2188
 [<     inline     >] alloc_pages ./include/linux/gfp.h:511
 [<      none      >] bio_copy_kern+0x4c5/0xed0 block/bio.c:1590
 [<      none      >] blk_rq_map_kern+0x458/0x7e0 block/blk-map.c:237
 [<      none      >] __scsi_execute+0x2cf/0xaf0 drivers/scsi/scsi_lib.c:265
 [<     inline     >] scsi_execute_req ./include/scsi/scsi_device.h:451
 [<     inline     >] sr_get_events drivers/scsi/sr.c:207
 [<      none      >] sr_check_events+0x2ff/0x1190 drivers/scsi/sr.c:246
 [<     inline     >] cdrom_update_events drivers/cdrom/cdrom.c:1476
 [<      none      >] cdrom_check_events+0xc3/0x260 drivers/cdrom/cdrom.c:1486
 [<      none      >] sr_block_check_events+0x3c4/0x670 drivers/scsi/sr.c:614
 [<      none      >] disk_check_events+0x154/0x8b0 block/genhd.c:1855
 [<      none      >] disk_events_workfn+0x47/0x50 block/genhd.c:1841
=============================================

> I still don't understand how to handle DMA_BIDIRECTIONAL. Will it be
> sane to assume that at each dma_{map,sync,unmap}_* call must always
> check the memory range and then unpoison it?
>
> Thanks in advance
>
> --
> Alexander Potapenko
> Software Engineer
>
> Google Germany GmbH
> Erika-Mann-Straße, 33
> 80636 München
>
> Geschäftsführer: Paul Manicle, Halimah DeLaine Prado
> Registergericht und -nummer: Hamburg, HRB 86891
> Sitz der Gesellschaft: Hamburg
Alexander Potapenko Nov. 13, 2019, 11:07 a.m. UTC | #4
On Thu, Nov 7, 2019 at 2:00 PM Alexander Potapenko <glider@google.com> wrote:
>
> On Tue, Nov 5, 2019 at 4:02 PM Alexander Potapenko <glider@google.com> wrote:
> >
> > On Wed, Oct 30, 2019 at 3:38 PM Christoph Hellwig <hch@lst.de> wrote:
> > >
> > > On Wed, Oct 30, 2019 at 03:22:34PM +0100, glider@google.com wrote:
> > > > When data is copied to memory from a device KMSAN should treat it as
> > > > initialized. In most cases it's enough to just unpoison the buffer that
> > > > is known to come from a device.
> > > > In the case with __do_page_cache_readahead() and bio_copy_user_iov() we
> > > > have to mark the whole pages as ignored by KMSAN, as it's not obvious
> > > > where these pages are read again.
> > >
> > > A lot of this looks pretty strange.  Why don't you instrument
> > > the dma_map / dma_sync infrastucture?  That should avoid most of the
> > > driver hooks.
> >
> > That's the exact reason I'm sending these patches: I simply don't know
> > the kernel code good enough.
> > May I ask you for some pointers?
> > My goal is to mark data copied from the device as initialized (by
> > calling kmsan_unpoison_shadow(ptr, size)), and, if possible, check
> > data that's about to be copied to device (by calling
> > kmsan_check_memory(ptr, size)).
> > My understanding is that:
> >  1. calls to dma_map_* and dma_sync_* with direction=DMA_FROM_DEVICE
> > denote that the corresponding kernel buffer can be marked as
> > initialized
> >  2. calls to dma_unmap_* and dma_sync_* with direction=DMA_TO_DEVICE
> > denote that the buffer will be copied to device (and must be checked
> > for being initialized)
> >  3. I need some translation table to find out the virtual address for
> > a given dma_addr_t
> > Does this sound reasonable?
> Initializing memory in dma_map_ still leaves out the reports as the one below.
> There seems to be a DMA access somewhere in blk_execute_rq(), but I
> fail to see why it's not covered.
>
> =============================================
> BUG: KMSAN: uninit-value in[<      none      >]
> sr_check_events+0x1091/0x1190 drivers/scsi/sr.c:246
>  CPU: 0 PID: 5 Comm: kworker/0:0 Not tainted 5.4.0-rc5+ #3266
>  Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.12.0-1 04/01/2014
>  Workqueue: events_freezable_power_ disk_events_workfn
>  Call Trace:
>  [<     inline     >] __dump_stack lib/dump_stack.c:77
>  [<      none      >] dump_stack+0x196/0x1f0 lib/dump_stack.c:113
>  [<      none      >] kmsan_report+0x127/0x220 mm/kmsan/kmsan_report.c:108
>  [<      none      >] __msan_warning+0x73/0xe0 mm/kmsan/kmsan_instr.c:245
>  [<     inline     >] sr_get_events drivers/scsi/sr.c:213
>  [<      none      >] sr_check_events+0x1091/0x1190 drivers/scsi/sr.c:246
>  [<     inline     >] cdrom_update_events drivers/cdrom/cdrom.c:1476
>  [<      none      >] cdrom_check_events+0xc3/0x260 drivers/cdrom/cdrom.c:1486
>  [<      none      >] sr_block_check_events+0x3c4/0x670 drivers/scsi/sr.c:614
>  [<      none      >] disk_check_events+0x154/0x8b0 block/genhd.c:1855
>  [<      none      >] disk_events_workfn+0x47/0x50 block/genhd.c:1841
>  [<      none      >] process_one_work+0x1556/0x1ef0 kernel/workqueue.c:2269
> ...
>  Uninit was stored to memory at:
>  [<     inline     >] kmsan_save_stack_with_flags mm/kmsan/kmsan.c:151
>  [<      none      >] kmsan_internal_chain_origin+0xa3/0x160
> mm/kmsan/kmsan.c:319
>  [<      none      >] kmsan_memcpy_memmove_metadata+0x271/0x2e0
> mm/kmsan/kmsan.c:254
>  [<      none      >] kmsan_memcpy_metadata+0xb/0x10 mm/kmsan/kmsan.c:274
>  [<      none      >] __msan_memcpy+0x55/0x70 mm/kmsan/kmsan_instr.c:129
>  [<      none      >] bio_copy_kern_endio_read+0x467/0x990 block/bio.c:1543
>  [<      none      >] bio_endio+0xa36/0xbb0 block/bio.c:1850
>  [<     inline     >] req_bio_endio block/blk-core.c:242
>  [<      none      >] blk_update_request+0xd3c/0x20a0 block/blk-core.c:1462
>  [<      none      >] scsi_end_request+0x10b/0xeb0 drivers/scsi/scsi_lib.c:579
>  [<      none      >] scsi_io_completion+0x279/0x2660
> drivers/scsi/scsi_lib.c:963
>  [<      none      >] scsi_finish_command+0x6f9/0x720 drivers/scsi/scsi.c:228
>  [<      none      >] scsi_softirq_done+0x772/0x980 drivers/scsi/scsi_lib.c:1477
>  [<      none      >] blk_done_softirq+0x300/0x4f0 block/blk-softirq.c:37
>  [<      none      >] __do_softirq+0x311/0x83d kernel/softirq.c:293
> ...
>  Uninit was created at:
>  [<      none      >] kmsan_save_stack_with_flags+0x3f/0x90 mm/kmsan/kmsan.c:151
>  [<     inline     >] kmsan_internal_alloc_meta_for_pages
> mm/kmsan/kmsan_shadow.c:362
>  [<      none      >] kmsan_alloc_page+0x14e/0x360 mm/kmsan/kmsan_shadow.c:391
>  [<      none      >] __alloc_pages_nodemask+0x594e/0x6050 mm/page_alloc.c:4796
>  [<      none      >] alloc_pages_current+0x682/0x990 mm/mempolicy.c:2188
>  [<     inline     >] alloc_pages ./include/linux/gfp.h:511
>  [<      none      >] bio_copy_kern+0x4c5/0xed0 block/bio.c:1590
>  [<      none      >] blk_rq_map_kern+0x458/0x7e0 block/blk-map.c:237
>  [<      none      >] __scsi_execute+0x2cf/0xaf0 drivers/scsi/scsi_lib.c:265
>  [<     inline     >] scsi_execute_req ./include/scsi/scsi_device.h:451
>  [<     inline     >] sr_get_events drivers/scsi/sr.c:207
>  [<      none      >] sr_check_events+0x2ff/0x1190 drivers/scsi/sr.c:246
>  [<     inline     >] cdrom_update_events drivers/cdrom/cdrom.c:1476
>  [<      none      >] cdrom_check_events+0xc3/0x260 drivers/cdrom/cdrom.c:1486
>  [<      none      >] sr_block_check_events+0x3c4/0x670 drivers/scsi/sr.c:614
>  [<      none      >] disk_check_events+0x154/0x8b0 block/genhd.c:1855
>  [<      none      >] disk_events_workfn+0x47/0x50 block/genhd.c:1841
> =============================================

Turned out these reports were coming from reads from iomapped memory.
Unpoisoning those (in lib/iomap.c) in addition to DMA reads will
probably eliminate the need of ad-hoc annotations in device drivers.

> > I still don't understand how to handle DMA_BIDIRECTIONAL. Will it be
> > sane to assume that at each dma_{map,sync,unmap}_* call must always
> > check the memory range and then unpoison it?
> >
> > Thanks in advance
> >
> > --
> > Alexander Potapenko
> > Software Engineer
> >
> > Google Germany GmbH
> > Erika-Mann-Straße, 33
> > 80636 München
> >
> > Geschäftsführer: Paul Manicle, Halimah DeLaine Prado
> > Registergericht und -nummer: Hamburg, HRB 86891
> > Sitz der Gesellschaft: Hamburg
>
>
>
> --
> Alexander Potapenko
> Software Engineer
>
> Google Germany GmbH
> Erika-Mann-Straße, 33
> 80636 München
>
> Geschäftsführer: Paul Manicle, Halimah DeLaine Prado
> Registergericht und -nummer: Hamburg, HRB 86891
> Sitz der Gesellschaft: Hamburg
diff mbox series

Patch

diff --git a/block/bio.c b/block/bio.c
index 8f0ed6228fc5..40773cf4b50c 100644
--- a/block/bio.c
+++ b/block/bio.c
@@ -11,6 +11,7 @@ 
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
+#include <linux/kmsan-checks.h>
 #include <linux/export.h>
 #include <linux/mempool.h>
 #include <linux/workqueue.h>
@@ -900,6 +901,13 @@  static int __bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter)
 			__bio_add_page(bio, page, len, offset);
 		}
 		offset = 0;
+		/*
+		 * TODO(glider): these pages will be soon passed to block
+		 * device for reading, so consider them initialized.
+		 */
+		if (iov_iter_rw(iter) == READ)
+			kmsan_unpoison_shadow(page_address(page),
+						PAGE_SIZE);
 	}
 
 	iov_iter_advance(iter, size);
@@ -1274,11 +1282,16 @@  struct bio *bio_copy_user_iov(struct request_queue *q,
 
 			i++;
 		} else {
+			/*
+			 * TODO(glider): KMSAN doesn't track the pages
+			 * allocated for bio here.
+			 */
 			page = alloc_page(q->bounce_gfp | gfp_mask);
 			if (!page) {
 				ret = -ENOMEM;
 				break;
 			}
+			kmsan_ignore_page(page, /*order*/0);
 		}
 
 		if (bio_add_pc_page(q, bio, page, bytes, offset) < bytes) {
@@ -1574,6 +1587,13 @@  struct bio *bio_copy_kern(struct request_queue *q, void *data, unsigned int len,
 		if (!page)
 			goto cleanup;
 
+		/*
+		 * TODO(glider): if we're about to read data from a SCSI device,
+		 * assume the page allocated for that is already initialized.
+		 */
+		if (reading)
+			kmsan_unpoison_shadow(page_address(page), PAGE_SIZE);
+
 		if (!reading)
 			memcpy(page_address(page), p, bytes);
 
diff --git a/block/partition-generic.c b/block/partition-generic.c
index aee643ce13d1..87b3ae9e7727 100644
--- a/block/partition-generic.c
+++ b/block/partition-generic.c
@@ -663,13 +663,20 @@  unsigned char *read_dev_sector(struct block_device *bdev, sector_t n, Sector *p)
 {
 	struct address_space *mapping = bdev->bd_inode->i_mapping;
 	struct page *page;
+	unsigned char *retval;
 
 	page = read_mapping_page(mapping, (pgoff_t)(n >> (PAGE_SHIFT-9)), NULL);
 	if (!IS_ERR(page)) {
 		if (PageError(page))
 			goto fail;
 		p->v = page;
-		return (unsigned char *)page_address(page) +  ((n & ((1 << (PAGE_SHIFT - 9)) - 1)) << 9);
+		retval = (unsigned char *)page_address(page) +
+			 ((n & ((1 << (PAGE_SHIFT - 9)) - 1)) << 9);
+		/*
+		 * Unpoison sector-sized chunk of memory coming from the device.
+		 */
+		kmsan_unpoison_shadow(retval, SECTOR_SIZE);
+		return retval;
 fail:
 		put_page(page);
 	}
diff --git a/drivers/char/random.c b/drivers/char/random.c
index de434feb873a..cc4afc0f1039 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -320,6 +320,7 @@ 
 #include <linux/fs.h>
 #include <linux/genhd.h>
 #include <linux/interrupt.h>
+#include <linux/kmsan-checks.h>
 #include <linux/mm.h>
 #include <linux/nodemask.h>
 #include <linux/spinlock.h>
@@ -1061,6 +1062,7 @@  static void _extract_crng(struct crng_state *crng,
 	spin_lock_irqsave(&crng->lock, flags);
 	if (arch_get_random_long(&v))
 		crng->state[14] ^= v;
+	kmsan_unpoison_shadow(crng->state, sizeof(crng->state));
 	chacha20_block(&crng->state[0], out);
 	if (crng->state[12] == 0)
 		crng->state[13]++;
diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c
index a8c94a940a79..80a9e0a9d3c3 100644
--- a/drivers/input/serio/libps2.c
+++ b/drivers/input/serio/libps2.c
@@ -8,6 +8,7 @@ 
 
 
 #include <linux/delay.h>
+#include <linux/kmsan-checks.h>
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
@@ -30,6 +31,7 @@  static int ps2_do_sendbyte(struct ps2dev *ps2dev, u8 byte,
 	int error;
 
 	lockdep_assert_held(&ps2dev->serio->lock);
+	kmsan_check_memory(&byte, 1);
 
 	do {
 		ps2dev->nak = 1;
@@ -294,9 +296,11 @@  int __ps2_command(struct ps2dev *ps2dev, u8 *param, unsigned int command)
 
 	serio_pause_rx(ps2dev->serio);
 
-	if (param)
+	if (param) {
 		for (i = 0; i < receive; i++)
 			param[i] = ps2dev->cmdbuf[(receive - 1) - i];
+		kmsan_unpoison_shadow(param, receive);
+	}
 
 	if (ps2dev->cmdcnt &&
 	    (command != PS2_CMD_RESET_BAT || ps2dev->cmdcnt != 1)) {
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 5447738906ac..a6d6a0eed8ec 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -14,6 +14,7 @@ 
 #include <linux/blkdev.h>
 #include <linux/completion.h>
 #include <linux/kernel.h>
+#include <linux/kmsan-checks.h>
 #include <linux/export.h>
 #include <linux/init.h>
 #include <linux/pci.h>
@@ -296,6 +297,9 @@  int __scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
 	ret = rq->result;
  out:
 	blk_put_request(req);
+	/* TODO(glider): this is a bit rough. */
+	if (data_direction == DMA_FROM_DEVICE)
+		kmsan_unpoison_shadow(buffer, bufflen);
 
 	return ret;
 }
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index 5adf489428aa..f1c3f8b3cfae 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -9,6 +9,7 @@ 
 #include <linux/usb.h>
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/kmsan-checks.h>
 #include <linux/mm.h>
 #include <linux/timer.h>
 #include <linux/ctype.h>
@@ -101,8 +102,11 @@  static int usb_internal_control_msg(struct usb_device *usb_dev,
 	retv = usb_start_wait_urb(urb, timeout, &length);
 	if (retv < 0)
 		return retv;
-	else
+	else {
+		/* TODO(glider): USB initializes |length| bytes? */
+		kmsan_unpoison_shadow(data, length);
 		return length;
+	}
 }
 
 /**
diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index a8041e451e9e..19d35744e3e1 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -11,6 +11,7 @@ 
 #include <linux/module.h>
 #include <linux/hrtimer.h>
 #include <linux/dma-mapping.h>
+#include <linux/kmsan-checks.h>
 #include <xen/xen.h>
 
 #ifdef DEBUG
@@ -387,6 +388,12 @@  static void vring_unmap_one_split(const struct vring_virtqueue *vq,
 			       (flags & VRING_DESC_F_WRITE) ?
 			       DMA_FROM_DEVICE : DMA_TO_DEVICE);
 	}
+	/*
+	 * Unmapping DMA memory after a transfer from device requires this
+	 * memory to be unpoisoned.
+	 */
+	if (flags & VRING_DESC_F_WRITE)
+		kmsan_unpoison_shadow((const void *)desc->addr, desc->len);
 }
 
 static struct vring_desc *alloc_indirect_split(struct virtqueue *_vq,
@@ -500,6 +507,13 @@  static inline int virtqueue_add_split(struct virtqueue *_vq,
 			desc[i].flags = cpu_to_virtio16(_vq->vdev, VRING_DESC_F_NEXT | VRING_DESC_F_WRITE);
 			desc[i].addr = cpu_to_virtio64(_vq->vdev, addr);
 			desc[i].len = cpu_to_virtio32(_vq->vdev, sg->length);
+			/*
+			 * It's hard to figure out the buffer's address upon
+			 * receive. Instead we unpoison it once, when exposing
+			 * it to the device, and hope nobody else will write to
+			 * it.
+			 */
+			kmsan_unpoison_shadow(sg_virt(sg), sg->length);
 			prev = i;
 			i = virtio16_to_cpu(_vq->vdev, desc[i].next);
 		}
diff --git a/fs/buffer.c b/fs/buffer.c
index 86a38b979323..c08fb1a77fa1 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -1170,14 +1170,17 @@  static struct buffer_head *__bread_slow(struct buffer_head *bh)
 	lock_buffer(bh);
 	if (buffer_uptodate(bh)) {
 		unlock_buffer(bh);
+		kmsan_unpoison_shadow(bh->b_data, bh->b_size);
 		return bh;
 	} else {
 		get_bh(bh);
 		bh->b_end_io = end_buffer_read_sync;
 		submit_bh(REQ_OP_READ, 0, bh);
 		wait_on_buffer(bh);
-		if (buffer_uptodate(bh))
+		if (buffer_uptodate(bh)) {
+			kmsan_unpoison_shadow(bh->b_data, bh->b_size);
 			return bh;
+		}
 	}
 	brelse(bh);
 	return NULL;
@@ -1320,6 +1323,8 @@  __getblk_gfp(struct block_device *bdev, sector_t block,
 	might_sleep();
 	if (bh == NULL)
 		bh = __getblk_slow(bdev, block, size, gfp);
+	if (bh)
+		kmsan_unpoison_shadow(bh->b_data, bh->b_size);
 	return bh;
 }
 EXPORT_SYMBOL(__getblk_gfp);
diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h
index 4a1c4fca475a..cc7b05eb024f 100644
--- a/include/linux/dma-mapping.h
+++ b/include/linux/dma-mapping.h
@@ -8,6 +8,7 @@ 
 #include <linux/err.h>
 #include <linux/dma-debug.h>
 #include <linux/dma-direction.h>
+#include <linux/kmsan-checks.h>
 #include <linux/scatterlist.h>
 #include <linux/bug.h>
 #include <linux/mem_encrypt.h>
@@ -281,6 +282,7 @@  static inline dma_addr_t dma_map_page_attrs(struct device *dev,
 	const struct dma_map_ops *ops = get_dma_ops(dev);
 	dma_addr_t addr;
 
+	kmsan_unpoison_shadow(page_address(page), size);
 	BUG_ON(!valid_dma_direction(dir));
 	if (dma_is_direct(ops))
 		addr = dma_direct_map_page(dev, page, offset, size, dir, attrs);
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 7914fdaf4226..1efe136250c9 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -11,6 +11,7 @@ 
 #define _LINUX_SKBUFF_H
 
 #include <linux/kernel.h>
+#include <linux/kmsan-checks.h>
 #include <linux/compiler.h>
 #include <linux/time.h>
 #include <linux/bug.h>
@@ -2214,6 +2215,8 @@  static inline void *skb_put_data(struct sk_buff *skb, const void *data,
 {
 	void *tmp = skb_put(skb, len);
 
+	/* Unpoison the data received from the network device. */
+	kmsan_unpoison_shadow(data, len);
 	memcpy(tmp, data, len);
 
 	return tmp;
@@ -2221,7 +2224,7 @@  static inline void *skb_put_data(struct sk_buff *skb, const void *data,
 
 static inline void skb_put_u8(struct sk_buff *skb, u8 val)
 {
-	*(u8 *)skb_put(skb, 1) = val;
+	*(u8 *)skb_put(skb, 1) = KMSAN_INIT_VALUE(val);
 }
 
 void *skb_push(struct sk_buff *skb, unsigned int len);
diff --git a/mm/filemap.c b/mm/filemap.c
index 85b7d087eb45..05b930e9f484 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -18,6 +18,7 @@ 
 #include <linux/uaccess.h>
 #include <linux/capability.h>
 #include <linux/kernel_stat.h>
+#include <linux/kmsan-checks.h>
 #include <linux/gfp.h>
 #include <linux/mm.h>
 #include <linux/swap.h>
diff --git a/mm/readahead.c b/mm/readahead.c
index 2fe72cd29b47..1fe61128095b 100644
--- a/mm/readahead.c
+++ b/mm/readahead.c
@@ -193,7 +193,13 @@  unsigned int __do_page_cache_readahead(struct address_space *mapping,
 			continue;
 		}
 
+		/*
+		 * The easiest way to handle these pages is to mark them
+		 * untracked by KMSAN, assuming they're never used by anything
+		 * else.
+		 */
 		page = __page_cache_alloc(gfp_mask);
+		kmsan_ignore_page(page, /*order*/0);
 		if (!page)
 			break;
 		page->index = page_offset;
diff --git a/net/9p/protocol.c b/net/9p/protocol.c
index 03593eb240d8..5d88ed181422 100644
--- a/net/9p/protocol.c
+++ b/net/9p/protocol.c
@@ -13,6 +13,7 @@ 
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
+#include <linux/kmsan-checks.h>
 #include <linux/uaccess.h>
 #include <linux/slab.h>
 #include <linux/sched.h>
@@ -46,6 +47,7 @@  EXPORT_SYMBOL(p9stat_free);
 size_t pdu_read(struct p9_fcall *pdu, void *data, size_t size)
 {
 	size_t len = min(pdu->size - pdu->offset, size);
+	kmsan_unpoison_shadow(&pdu->sdata[pdu->offset], len);
 	memcpy(data, &pdu->sdata[pdu->offset], len);
 	pdu->offset += len;
 	return size - len;
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
index f57c610d7523..c3795e495196 100644
--- a/sound/core/oss/pcm_oss.c
+++ b/sound/core/oss/pcm_oss.c
@@ -12,6 +12,7 @@ 
 #endif
 
 #include <linux/init.h>
+#include <linux/kmsan-checks.h>	/* for kmsan_unpoison_shadow() */
 #include <linux/slab.h>
 #include <linux/sched/signal.h>
 #include <linux/time.h>
@@ -1054,6 +1055,12 @@  static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream)
 		err = -ENOMEM;
 		goto failure;
 	}
+	/*
+	 * Unpoison the freshly created buffer to prevent KMSAN from reporting
+	 * uninit errors.
+	 * TODO(glider): unpoison it only when it's actually initialized.
+	 */
+	kmsan_unpoison_shadow(runtime->oss.buffer, runtime->oss.period_bytes);
 
 	runtime->oss.params = 0;
 	runtime->oss.prepare = 1;