diff mbox series

[RFC,v1,23/26] kmsan: unpoisoning buffers from devices etc.

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

Commit Message

Alexander Potapenko Oct. 18, 2019, 9:43 a.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: 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.

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                 |  3 +++
 mm/readahead.c               |  6 ++++++
 net/9p/protocol.c            |  2 ++
 sound/core/oss/pcm_oss.c     |  7 +++++++
 14 files changed, 88 insertions(+), 5 deletions(-)

Comments

Christoph Hellwig Oct. 18, 2019, 3:27 p.m. UTC | #1
On Fri, Oct 18, 2019 at 11:43:01AM +0200, 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.

I'm not sure how your annotations work because you only Cced me on this
one patch.  Don't do that.
Matthew Wilcox (Oracle) Oct. 18, 2019, 4:22 p.m. UTC | #2
On Fri, Oct 18, 2019 at 11:43:01AM +0200, 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.

...

> +++ 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>
> @@ -2810,6 +2811,8 @@ static struct page *do_read_cache_page(struct address_space *mapping,
>  		page = wait_on_page_read(page);
>  		if (IS_ERR(page))
>  			return page;
> +		/* Assume all pages in page cache are initialized. */
> +		kmsan_unpoison_shadow(page_address(page), PAGE_SIZE);

Why would you do that?  The page cache already keeps track of which
pages are initialised -- the PageUptodate flag is set on them.  Indeed,
just adding a kmsan call to SetPageUptodate and __SetPageUptodate would
probably be a very straightforward way of handling things, and probably
means you can get rid of a lot of these other calls.
Alexander Potapenko Oct. 29, 2019, 2:45 p.m. UTC | #3
On Fri, Oct 18, 2019 at 6:22 PM Matthew Wilcox <willy@infradead.org> wrote:
>
> On Fri, Oct 18, 2019 at 11:43:01AM +0200, 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.
>
> ...
>
> > +++ 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>
> > @@ -2810,6 +2811,8 @@ static struct page *do_read_cache_page(struct address_space *mapping,
> >               page = wait_on_page_read(page);
> >               if (IS_ERR(page))
> >                       return page;
> > +             /* Assume all pages in page cache are initialized. */
> > +             kmsan_unpoison_shadow(page_address(page), PAGE_SIZE);
>
> Why would you do that?  The page cache already keeps track of which
> pages are initialised -- the PageUptodate flag is set on them.  Indeed,
> just adding a kmsan call to SetPageUptodate and __SetPageUptodate would
> probably be a very straightforward way of handling things, and probably
> means you can get rid of a lot of these other calls.
This seems like a very good thing to do, I'll definitely try that.
I however noticed that __SetPageUptodate is used when copying pages,
not during disk I/O. Is that really so?

We basically need the following behavior: if a device writes to a
page, the contents of that page are considered initialized.
However when the kernel copies one page to another, we must explicitly
copy the source shadow page to the destination.

On a related note, there seems to be a PG_dirty bit that indicates the
page is to be flushed to disk.
What's the best place to check such pages for being initialized, so
that we can also report writes of uninitialized data to the disk?
Alexander Potapenko Oct. 30, 2019, 12:43 p.m. UTC | #4
On Tue, Oct 29, 2019 at 3:45 PM Alexander Potapenko <glider@google.com> wrote:
>
> On Fri, Oct 18, 2019 at 6:22 PM Matthew Wilcox <willy@infradead.org> wrote:
> >
> > On Fri, Oct 18, 2019 at 11:43:01AM +0200, 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.
> >
> > ...
> >
> > > +++ 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>
> > > @@ -2810,6 +2811,8 @@ static struct page *do_read_cache_page(struct address_space *mapping,
> > >               page = wait_on_page_read(page);
> > >               if (IS_ERR(page))
> > >                       return page;
> > > +             /* Assume all pages in page cache are initialized. */
> > > +             kmsan_unpoison_shadow(page_address(page), PAGE_SIZE);
> >
> > Why would you do that?  The page cache already keeps track of which
> > pages are initialised -- the PageUptodate flag is set on them.  Indeed,
> > just adding a kmsan call to SetPageUptodate and __SetPageUptodate would
> > probably be a very straightforward way of handling things, and probably
> > means you can get rid of a lot of these other calls.
> This seems like a very good thing to do, I'll definitely try that.
Hm, turns out there's no need for this particular call to
kmsan_unpoison_memory(),
because the errors that it was suppressing are better addressed by
making READ_ONCE_NOCHECK() return initialized memory.
On the other hand, unpoisoning memory in SetPageUptodate doesn't seem
to address the same errors.

 =====================================================
 BUG: KMSAN: uninit-value in[<      none      >] get_wchan+0x2c6/0x410
arch/x86/kernel/process.c:851
 CPU: 0 PID: 5159 Comm: ps Not tainted 5.4.0-rc5+ #3220
 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.12.0-1 04/01/2014
 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
 [<      none      >] get_wchan+0x2c6/0x410 arch/x86/kernel/process.c:851
 [<      none      >] do_task_stat+0x16f3/0x30a0 fs/proc/array.c:522
 [<      none      >] proc_tgid_stat+0xbe/0xf0 fs/proc/array.c:632
 [<      none      >] proc_single_show+0x1a8/0x2b0 fs/proc/base.c:756
 [<      none      >] seq_read+0xad1/0x1da0 fs/seq_file.c:229
 [<      none      >] __vfs_read+0x1a9/0xc90 fs/read_write.c:425
 [<      none      >] vfs_read+0x333/0x6a0 fs/read_write.c:461
 [<      none      >] ksys_read+0x281/0x460 fs/read_write.c:587
 [<     inline     >] __do_sys_read fs/read_write.c:597
 [<      none      >] __se_sys_read+0x92/0xb0 fs/read_write.c:595
 [<      none      >] __x64_sys_read+0x4a/0x70 fs/read_write.c:595
 [<      none      >] do_syscall_64+0xb6/0x160 arch/x86/entry/common.c:291
 [<      none      >] entry_SYSCALL_64_after_hwframe+0x63/0xe7
arch/x86/entry/entry_64.S:177
 Local variable description: ----stat.i@__se_sys_newstat
 Variable was created at:
 [<     inline     >] __do_sys_newstat fs/stat.c:337
 [<      none      >] __se_sys_newstat+0x71/0xac0 fs/stat.c:337
 [<     inline     >] __do_sys_newstat fs/stat.c:337
 [<      none      >] __se_sys_newstat+0x71/0xac0 fs/stat.c:337
 =====================================================



> I however noticed that __SetPageUptodate is used when copying pages,
> not during disk I/O. Is that really so?
>
> We basically need the following behavior: if a device writes to a
> page, the contents of that page are considered initialized.
> However when the kernel copies one page to another, we must explicitly
> copy the source shadow page to the destination.
>
> On a related note, there seems to be a PG_dirty bit that indicates the
> page is to be flushed to disk.
> What's the best place to check such pages for being initialized, so
> that we can also report writes of uninitialized data to the disk?
>
>
> --
> 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 dc210b9d4896..4235b317ac5f 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 bdc08244a648..8b7ddc43618f 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 4351577b14d7..b8e9cd697248 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 1146fcfa3215..8a17f15806cc 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>
@@ -2810,6 +2811,8 @@  static struct page *do_read_cache_page(struct address_space *mapping,
 		page = wait_on_page_read(page);
 		if (IS_ERR(page))
 			return page;
+		/* Assume all pages in page cache are initialized. */
+		kmsan_unpoison_shadow(page_address(page), PAGE_SIZE);
 		goto out;
 	}
 	if (PageUptodate(page))
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;