diff mbox series

[RFC,v3,35/36] kmsan: ext4: skip block merging logic in ext4_mpage_readpages for KMSAN

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

Commit Message

Alexander Potapenko Nov. 22, 2019, 11:26 a.m. UTC
KMSAN doesn't allow treating adjacent memory pages as such, if they were
allocated by different alloc_pages() calls.
ext4_mpage_readpages() however does so: adjacent pages end up being passed
together to dma_direct_map_sg().
To prevent this, jump directly to the buffer_head-based read function in
KMSAN builds.

Signed-off-by: Alexander Potapenko <glider@google.com>
Cc: "Theodore Ts'o" <tytso@mit.edu>
Cc: Andreas Dilger <adilger.kernel@dilger.ca>
Cc: Vegard Nossum <vegard.nossum@oracle.com>
Cc: Dmitry Vyukov <dvyukov@google.com>
Cc: linux-mm@kvack.org
---

Change-Id: I54ae8af536626a988e6398ff18a06c179b0ce034
---
 fs/ext4/readpage.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

Comments

Robin Murphy Nov. 25, 2019, 4:05 p.m. UTC | #1
On 22/11/2019 11:26 am, glider@google.com wrote:
> KMSAN doesn't allow treating adjacent memory pages as such, if they were
> allocated by different alloc_pages() calls.
> ext4_mpage_readpages() however does so: adjacent pages end up being passed
> together to dma_direct_map_sg().

Urgh, there are definitely more places where physically-contiguous pages 
are coalesced into single scatterlist entries - see 
sg_alloc_table_from_pages() for instance. I wouldn't be surprised if 
there are further open-coded versions hiding out in various other 
drivers/subsystems too. Unless I've misunderstood, this seems like quite 
an invasive limitation :(

Robin.

> To prevent this, jump directly to the buffer_head-based read function in
> KMSAN builds.
> 
> Signed-off-by: Alexander Potapenko <glider@google.com>
> Cc: "Theodore Ts'o" <tytso@mit.edu>
> Cc: Andreas Dilger <adilger.kernel@dilger.ca>
> Cc: Vegard Nossum <vegard.nossum@oracle.com>
> Cc: Dmitry Vyukov <dvyukov@google.com>
> Cc: linux-mm@kvack.org
> ---
> 
> Change-Id: I54ae8af536626a988e6398ff18a06c179b0ce034
> ---
>   fs/ext4/readpage.c | 11 +++++++++++
>   1 file changed, 11 insertions(+)
> 
> diff --git a/fs/ext4/readpage.c b/fs/ext4/readpage.c
> index a30b203fa461..a3bb9e3ce5de 100644
> --- a/fs/ext4/readpage.c
> +++ b/fs/ext4/readpage.c
> @@ -252,6 +252,17 @@ int ext4_mpage_readpages(struct address_space *mapping,
>   		if (page_has_buffers(page))
>   			goto confused;
>   
> +#if defined(CONFIG_KMSAN)
> +		/*
> +		 * The following code may treat adjacent pages allocated
> +		 * separately as a bigger contiguous allocation.
> +		 * KMSAN doesn't allow this, as the corresponding metadata
> +		 * pages may be separated.
> +		 * Skip this complex logic for KMSAN builds.
> +		 */
> +		goto confused;
> +#endif
> +
>   		block_in_file = (sector_t)page->index << (PAGE_SHIFT - blkbits);
>   		last_block = block_in_file + nr_pages * blocks_per_page;
>   		last_block_in_file = (ext4_readpage_limit(inode) +
>
Alexander Potapenko Nov. 25, 2019, 5:03 p.m. UTC | #2
On Mon, Nov 25, 2019 at 5:05 PM Robin Murphy <robin.murphy@arm.com> wrote:
>
> On 22/11/2019 11:26 am, glider@google.com wrote:
> > KMSAN doesn't allow treating adjacent memory pages as such, if they were
> > allocated by different alloc_pages() calls.
> > ext4_mpage_readpages() however does so: adjacent pages end up being passed
> > together to dma_direct_map_sg().
>
> Urgh, there are definitely more places where physically-contiguous pages
> are coalesced into single scatterlist entries - see
> sg_alloc_table_from_pages() for instance. I wouldn't be surprised if
> there are further open-coded versions hiding out in various other
> drivers/subsystems too. Unless I've misunderstood, this seems like quite
> an invasive limitation :(
You're right.
Other places haven't fired off so far, so I was just unaware of them,
but I'm anticipating more.
There are two possible solutions to that problem:
1. Allocate shadow and origin pages at fixed offset from the kernel page.
This is what we already do for vmalloc, but not for page_alloc(), as
it turned out to be quite hard.
Ideas on how to implement this approach are still welcome, because
it'll simplify the rest of the KMSAN runtime a lot.
2. Make all accesses touching non-contiguous pages access dummy shadow
pages instead, so that such accesses don't produce any uninitialized
values.
This is quite controversial, as it may prevent true positives from
being reported.

> Robin.
>
> > To prevent this, jump directly to the buffer_head-based read function in
> > KMSAN builds.
> >
> > Signed-off-by: Alexander Potapenko <glider@google.com>
> > Cc: "Theodore Ts'o" <tytso@mit.edu>
> > Cc: Andreas Dilger <adilger.kernel@dilger.ca>
> > Cc: Vegard Nossum <vegard.nossum@oracle.com>
> > Cc: Dmitry Vyukov <dvyukov@google.com>
> > Cc: linux-mm@kvack.org
> > ---
> >
> > Change-Id: I54ae8af536626a988e6398ff18a06c179b0ce034
> > ---
> >   fs/ext4/readpage.c | 11 +++++++++++
> >   1 file changed, 11 insertions(+)
> >
> > diff --git a/fs/ext4/readpage.c b/fs/ext4/readpage.c
> > index a30b203fa461..a3bb9e3ce5de 100644
> > --- a/fs/ext4/readpage.c
> > +++ b/fs/ext4/readpage.c
> > @@ -252,6 +252,17 @@ int ext4_mpage_readpages(struct address_space *mapping,
> >               if (page_has_buffers(page))
> >                       goto confused;
> >
> > +#if defined(CONFIG_KMSAN)
> > +             /*
> > +              * The following code may treat adjacent pages allocated
> > +              * separately as a bigger contiguous allocation.
> > +              * KMSAN doesn't allow this, as the corresponding metadata
> > +              * pages may be separated.
> > +              * Skip this complex logic for KMSAN builds.
> > +              */
> > +             goto confused;
> > +#endif
> > +
> >               block_in_file = (sector_t)page->index << (PAGE_SHIFT - blkbits);
> >               last_block = block_in_file + nr_pages * blocks_per_page;
> >               last_block_in_file = (ext4_readpage_limit(inode) +
> >
Marco Elver Dec. 3, 2019, 2:22 p.m. UTC | #3
On Fri, 22 Nov 2019 at 12:28, <glider@google.com> wrote:
>
> KMSAN doesn't allow treating adjacent memory pages as such, if they were
> allocated by different alloc_pages() calls.
> ext4_mpage_readpages() however does so: adjacent pages end up being passed
> together to dma_direct_map_sg().
> To prevent this, jump directly to the buffer_head-based read function in
> KMSAN builds.
>
> Signed-off-by: Alexander Potapenko <glider@google.com>
> Cc: "Theodore Ts'o" <tytso@mit.edu>
> Cc: Andreas Dilger <adilger.kernel@dilger.ca>
> Cc: Vegard Nossum <vegard.nossum@oracle.com>
> Cc: Dmitry Vyukov <dvyukov@google.com>
> Cc: linux-mm@kvack.org
> ---
>
> Change-Id: I54ae8af536626a988e6398ff18a06c179b0ce034
> ---
>  fs/ext4/readpage.c | 11 +++++++++++
>  1 file changed, 11 insertions(+)
>
> diff --git a/fs/ext4/readpage.c b/fs/ext4/readpage.c
> index a30b203fa461..a3bb9e3ce5de 100644
> --- a/fs/ext4/readpage.c
> +++ b/fs/ext4/readpage.c
> @@ -252,6 +252,17 @@ int ext4_mpage_readpages(struct address_space *mapping,
>                 if (page_has_buffers(page))
>                         goto confused;
>
> +#if defined(CONFIG_KMSAN)

Prefer 'if (IS_ENABLED(CONFIG_KMSAN))'.

Thanks,
-- Marco
Alexander Potapenko Dec. 5, 2019, 2:31 p.m. UTC | #4
On Tue, Dec 3, 2019 at 3:22 PM Marco Elver <elver@google.com> wrote:
>
> On Fri, 22 Nov 2019 at 12:28, <glider@google.com> wrote:
> >
> > KMSAN doesn't allow treating adjacent memory pages as such, if they were
> > allocated by different alloc_pages() calls.
> > ext4_mpage_readpages() however does so: adjacent pages end up being passed
> > together to dma_direct_map_sg().
> > To prevent this, jump directly to the buffer_head-based read function in
> > KMSAN builds.
> >
> > Signed-off-by: Alexander Potapenko <glider@google.com>
> > Cc: "Theodore Ts'o" <tytso@mit.edu>
> > Cc: Andreas Dilger <adilger.kernel@dilger.ca>
> > Cc: Vegard Nossum <vegard.nossum@oracle.com>
> > Cc: Dmitry Vyukov <dvyukov@google.com>
> > Cc: linux-mm@kvack.org
> > ---
> >
> > Change-Id: I54ae8af536626a988e6398ff18a06c179b0ce034
> > ---
> >  fs/ext4/readpage.c | 11 +++++++++++
> >  1 file changed, 11 insertions(+)
> >
> > diff --git a/fs/ext4/readpage.c b/fs/ext4/readpage.c
> > index a30b203fa461..a3bb9e3ce5de 100644
> > --- a/fs/ext4/readpage.c
> > +++ b/fs/ext4/readpage.c
> > @@ -252,6 +252,17 @@ int ext4_mpage_readpages(struct address_space *mapping,
> >                 if (page_has_buffers(page))
> >                         goto confused;
> >
> > +#if defined(CONFIG_KMSAN)
>
> Prefer 'if (IS_ENABLED(CONFIG_KMSAN))'.
Done in v4.
> Thanks,
> -- Marco
diff mbox series

Patch

diff --git a/fs/ext4/readpage.c b/fs/ext4/readpage.c
index a30b203fa461..a3bb9e3ce5de 100644
--- a/fs/ext4/readpage.c
+++ b/fs/ext4/readpage.c
@@ -252,6 +252,17 @@  int ext4_mpage_readpages(struct address_space *mapping,
 		if (page_has_buffers(page))
 			goto confused;
 
+#if defined(CONFIG_KMSAN)
+		/*
+		 * The following code may treat adjacent pages allocated
+		 * separately as a bigger contiguous allocation.
+		 * KMSAN doesn't allow this, as the corresponding metadata
+		 * pages may be separated.
+		 * Skip this complex logic for KMSAN builds.
+		 */
+		goto confused;
+#endif
+
 		block_in_file = (sector_t)page->index << (PAGE_SHIFT - blkbits);
 		last_block = block_in_file + nr_pages * blocks_per_page;
 		last_block_in_file = (ext4_readpage_limit(inode) +