diff mbox series

[v2,2/4] mm: kasan: Skip unpoisoning of user pages

Message ID 20220610152141.2148929-3-catalin.marinas@arm.com (mailing list archive)
State New
Headers show
Series kasan: Fix ordering between MTE tag colouring and page->flags | expand

Commit Message

Catalin Marinas June 10, 2022, 3:21 p.m. UTC
Commit c275c5c6d50a ("kasan: disable freed user page poisoning with HW
tags") added __GFP_SKIP_KASAN_POISON to GFP_HIGHUSER_MOVABLE. A similar
argument can be made about unpoisoning, so also add
__GFP_SKIP_KASAN_UNPOISON to user pages. To ensure the user page is
still accessible via page_address() without a kasan fault, reset the
page->flags tag.

With the above changes, there is no need for the arm64
tag_clear_highpage() to reset the page->flags tag.

Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Cc: Andrey Ryabinin <ryabinin.a.a@gmail.com>
Cc: Andrey Konovalov <andreyknvl@gmail.com>
Cc: Peter Collingbourne <pcc@google.com>
Cc: Vincenzo Frascino <vincenzo.frascino@arm.com>
---
 arch/arm64/mm/fault.c | 1 -
 include/linux/gfp.h   | 2 +-
 mm/page_alloc.c       | 7 +++++--
 3 files changed, 6 insertions(+), 4 deletions(-)

Comments

Andrey Konovalov June 11, 2022, 7:40 p.m. UTC | #1
On Fri, Jun 10, 2022 at 5:21 PM Catalin Marinas <catalin.marinas@arm.com> wrote:
>
> Commit c275c5c6d50a ("kasan: disable freed user page poisoning with HW
> tags") added __GFP_SKIP_KASAN_POISON to GFP_HIGHUSER_MOVABLE. A similar
> argument can be made about unpoisoning, so also add
> __GFP_SKIP_KASAN_UNPOISON to user pages. To ensure the user page is
> still accessible via page_address() without a kasan fault, reset the
> page->flags tag.
>
> With the above changes, there is no need for the arm64
> tag_clear_highpage() to reset the page->flags tag.
>
> Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
> Cc: Andrey Ryabinin <ryabinin.a.a@gmail.com>
> Cc: Andrey Konovalov <andreyknvl@gmail.com>
> Cc: Peter Collingbourne <pcc@google.com>
> Cc: Vincenzo Frascino <vincenzo.frascino@arm.com>
> ---
>  arch/arm64/mm/fault.c | 1 -
>  include/linux/gfp.h   | 2 +-
>  mm/page_alloc.c       | 7 +++++--
>  3 files changed, 6 insertions(+), 4 deletions(-)
>
> diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
> index c5e11768e5c1..cdf3ffa0c223 100644
> --- a/arch/arm64/mm/fault.c
> +++ b/arch/arm64/mm/fault.c
> @@ -927,6 +927,5 @@ struct page *alloc_zeroed_user_highpage_movable(struct vm_area_struct *vma,
>  void tag_clear_highpage(struct page *page)
>  {
>         mte_zero_clear_page_tags(page_address(page));
> -       page_kasan_tag_reset(page);
>         set_bit(PG_mte_tagged, &page->flags);
>  }
> diff --git a/include/linux/gfp.h b/include/linux/gfp.h
> index 2d2ccae933c2..0ace7759acd2 100644
> --- a/include/linux/gfp.h
> +++ b/include/linux/gfp.h
> @@ -348,7 +348,7 @@ struct vm_area_struct;
>  #define GFP_DMA32      __GFP_DMA32
>  #define GFP_HIGHUSER   (GFP_USER | __GFP_HIGHMEM)
>  #define GFP_HIGHUSER_MOVABLE   (GFP_HIGHUSER | __GFP_MOVABLE | \
> -                        __GFP_SKIP_KASAN_POISON)
> +                        __GFP_SKIP_KASAN_POISON | __GFP_SKIP_KASAN_UNPOISON)
>  #define GFP_TRANSHUGE_LIGHT    ((GFP_HIGHUSER_MOVABLE | __GFP_COMP | \
>                          __GFP_NOMEMALLOC | __GFP_NOWARN) & ~__GFP_RECLAIM)
>  #define GFP_TRANSHUGE  (GFP_TRANSHUGE_LIGHT | __GFP_DIRECT_RECLAIM)
> diff --git a/mm/page_alloc.c b/mm/page_alloc.c
> index e008a3df0485..f6ed240870bc 100644
> --- a/mm/page_alloc.c
> +++ b/mm/page_alloc.c
> @@ -2397,6 +2397,7 @@ inline void post_alloc_hook(struct page *page, unsigned int order,
>         bool init = !want_init_on_free() && want_init_on_alloc(gfp_flags) &&
>                         !should_skip_init(gfp_flags);
>         bool init_tags = init && (gfp_flags & __GFP_ZEROTAGS);
> +       int i;
>
>         set_page_private(page, 0);
>         set_page_refcounted(page);
> @@ -2422,8 +2423,6 @@ inline void post_alloc_hook(struct page *page, unsigned int order,
>          * should be initialized as well).
>          */
>         if (init_tags) {
> -               int i;
> -
>                 /* Initialize both memory and tags. */
>                 for (i = 0; i != 1 << order; ++i)
>                         tag_clear_highpage(page + i);
> @@ -2438,6 +2437,10 @@ inline void post_alloc_hook(struct page *page, unsigned int order,
>                 /* Note that memory is already initialized by KASAN. */
>                 if (kasan_has_integrated_init())
>                         init = false;
> +       } else {
> +               /* Ensure page_address() dereferencing does not fault. */
> +               for (i = 0; i != 1 << order; ++i)
> +                       page_kasan_tag_reset(page + i);
>         }
>         /* If memory is still not initialized, do it now. */
>         if (init)

Reviewed-by: Andrey Konovalov <andreyknvl@gmail.com>
Vincenzo Frascino June 16, 2022, 8:42 a.m. UTC | #2
On 6/10/22 16:21, Catalin Marinas wrote:
> Commit c275c5c6d50a ("kasan: disable freed user page poisoning with HW
> tags") added __GFP_SKIP_KASAN_POISON to GFP_HIGHUSER_MOVABLE. A similar
> argument can be made about unpoisoning, so also add
> __GFP_SKIP_KASAN_UNPOISON to user pages. To ensure the user page is
> still accessible via page_address() without a kasan fault, reset the
> page->flags tag.
> 
> With the above changes, there is no need for the arm64
> tag_clear_highpage() to reset the page->flags tag.
> 
> Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
> Cc: Andrey Ryabinin <ryabinin.a.a@gmail.com>
> Cc: Andrey Konovalov <andreyknvl@gmail.com>
> Cc: Peter Collingbourne <pcc@google.com>
> Cc: Vincenzo Frascino <vincenzo.frascino@arm.com>
> ---
>  arch/arm64/mm/fault.c | 1 -
>  include/linux/gfp.h   | 2 +-
>  mm/page_alloc.c       | 7 +++++--
>  3 files changed, 6 insertions(+), 4 deletions(-)
> 
> diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
> index c5e11768e5c1..cdf3ffa0c223 100644
> --- a/arch/arm64/mm/fault.c
> +++ b/arch/arm64/mm/fault.c
> @@ -927,6 +927,5 @@ struct page *alloc_zeroed_user_highpage_movable(struct vm_area_struct *vma,
>  void tag_clear_highpage(struct page *page)
>  {
>  	mte_zero_clear_page_tags(page_address(page));
> -	page_kasan_tag_reset(page);
>  	set_bit(PG_mte_tagged, &page->flags);
>  }
> diff --git a/include/linux/gfp.h b/include/linux/gfp.h
> index 2d2ccae933c2..0ace7759acd2 100644
> --- a/include/linux/gfp.h
> +++ b/include/linux/gfp.h
> @@ -348,7 +348,7 @@ struct vm_area_struct;
>  #define GFP_DMA32	__GFP_DMA32
>  #define GFP_HIGHUSER	(GFP_USER | __GFP_HIGHMEM)
>  #define GFP_HIGHUSER_MOVABLE	(GFP_HIGHUSER | __GFP_MOVABLE | \
> -			 __GFP_SKIP_KASAN_POISON)
> +			 __GFP_SKIP_KASAN_POISON | __GFP_SKIP_KASAN_UNPOISON)
>  #define GFP_TRANSHUGE_LIGHT	((GFP_HIGHUSER_MOVABLE | __GFP_COMP | \
>  			 __GFP_NOMEMALLOC | __GFP_NOWARN) & ~__GFP_RECLAIM)
>  #define GFP_TRANSHUGE	(GFP_TRANSHUGE_LIGHT | __GFP_DIRECT_RECLAIM)
> diff --git a/mm/page_alloc.c b/mm/page_alloc.c
> index e008a3df0485..f6ed240870bc 100644
> --- a/mm/page_alloc.c
> +++ b/mm/page_alloc.c
> @@ -2397,6 +2397,7 @@ inline void post_alloc_hook(struct page *page, unsigned int order,
>  	bool init = !want_init_on_free() && want_init_on_alloc(gfp_flags) &&
>  			!should_skip_init(gfp_flags);
>  	bool init_tags = init && (gfp_flags & __GFP_ZEROTAGS);
> +	int i;
>  

Nit: Since "i" is not used outside of the for loop context we could use the
contract form "for (int i = 0; ..." which is allowed by C11.

>  	set_page_private(page, 0);
>  	set_page_refcounted(page);
> @@ -2422,8 +2423,6 @@ inline void post_alloc_hook(struct page *page, unsigned int order,
>  	 * should be initialized as well).
>  	 */
>  	if (init_tags) {
> -		int i;
> -
>  		/* Initialize both memory and tags. */
>  		for (i = 0; i != 1 << order; ++i)
>  			tag_clear_highpage(page + i);
> @@ -2438,6 +2437,10 @@ inline void post_alloc_hook(struct page *page, unsigned int order,
>  		/* Note that memory is already initialized by KASAN. */
>  		if (kasan_has_integrated_init())
>  			init = false;
> +	} else {
> +		/* Ensure page_address() dereferencing does not fault. */
> +		for (i = 0; i != 1 << order; ++i)
> +			page_kasan_tag_reset(page + i);
>  	}
>  	/* If memory is still not initialized, do it now. */
>  	if (init)

Either way:

Reviewed-by: Vincenzo Frascino <vincenzo.frascino@arm.com>
Catalin Marinas June 16, 2022, 5:40 p.m. UTC | #3
On Thu, Jun 16, 2022 at 09:42:10AM +0100, Vincenzo Frascino wrote:
> On 6/10/22 16:21, Catalin Marinas wrote:
> > diff --git a/mm/page_alloc.c b/mm/page_alloc.c
> > index e008a3df0485..f6ed240870bc 100644
> > --- a/mm/page_alloc.c
> > +++ b/mm/page_alloc.c
> > @@ -2397,6 +2397,7 @@ inline void post_alloc_hook(struct page *page, unsigned int order,
> >  	bool init = !want_init_on_free() && want_init_on_alloc(gfp_flags) &&
> >  			!should_skip_init(gfp_flags);
> >  	bool init_tags = init && (gfp_flags & __GFP_ZEROTAGS);
> > +	int i;
> >  
> 
> Nit: Since "i" is not used outside of the for loop context we could use the
> contract form "for (int i = 0; ..." which is allowed by C11.

Oh yeah, Linux moved to C11 in 5.18. But it looks better to be
consistent with the other for loop in this file.

> Reviewed-by: Vincenzo Frascino <vincenzo.frascino@arm.com>

Thanks.
diff mbox series

Patch

diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index c5e11768e5c1..cdf3ffa0c223 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -927,6 +927,5 @@  struct page *alloc_zeroed_user_highpage_movable(struct vm_area_struct *vma,
 void tag_clear_highpage(struct page *page)
 {
 	mte_zero_clear_page_tags(page_address(page));
-	page_kasan_tag_reset(page);
 	set_bit(PG_mte_tagged, &page->flags);
 }
diff --git a/include/linux/gfp.h b/include/linux/gfp.h
index 2d2ccae933c2..0ace7759acd2 100644
--- a/include/linux/gfp.h
+++ b/include/linux/gfp.h
@@ -348,7 +348,7 @@  struct vm_area_struct;
 #define GFP_DMA32	__GFP_DMA32
 #define GFP_HIGHUSER	(GFP_USER | __GFP_HIGHMEM)
 #define GFP_HIGHUSER_MOVABLE	(GFP_HIGHUSER | __GFP_MOVABLE | \
-			 __GFP_SKIP_KASAN_POISON)
+			 __GFP_SKIP_KASAN_POISON | __GFP_SKIP_KASAN_UNPOISON)
 #define GFP_TRANSHUGE_LIGHT	((GFP_HIGHUSER_MOVABLE | __GFP_COMP | \
 			 __GFP_NOMEMALLOC | __GFP_NOWARN) & ~__GFP_RECLAIM)
 #define GFP_TRANSHUGE	(GFP_TRANSHUGE_LIGHT | __GFP_DIRECT_RECLAIM)
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index e008a3df0485..f6ed240870bc 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -2397,6 +2397,7 @@  inline void post_alloc_hook(struct page *page, unsigned int order,
 	bool init = !want_init_on_free() && want_init_on_alloc(gfp_flags) &&
 			!should_skip_init(gfp_flags);
 	bool init_tags = init && (gfp_flags & __GFP_ZEROTAGS);
+	int i;
 
 	set_page_private(page, 0);
 	set_page_refcounted(page);
@@ -2422,8 +2423,6 @@  inline void post_alloc_hook(struct page *page, unsigned int order,
 	 * should be initialized as well).
 	 */
 	if (init_tags) {
-		int i;
-
 		/* Initialize both memory and tags. */
 		for (i = 0; i != 1 << order; ++i)
 			tag_clear_highpage(page + i);
@@ -2438,6 +2437,10 @@  inline void post_alloc_hook(struct page *page, unsigned int order,
 		/* Note that memory is already initialized by KASAN. */
 		if (kasan_has_integrated_init())
 			init = false;
+	} else {
+		/* Ensure page_address() dereferencing does not fault. */
+		for (i = 0; i != 1 << order; ++i)
+			page_kasan_tag_reset(page + i);
 	}
 	/* If memory is still not initialized, do it now. */
 	if (init)