linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] arm64: mte: Avoid setting PG_mte_tagged if no tags cleared or restored
@ 2022-10-06 16:33 Catalin Marinas
  2022-10-07 15:25 ` Steven Price
  2022-10-12 16:36 ` Catalin Marinas
  0 siblings, 2 replies; 3+ messages in thread
From: Catalin Marinas @ 2022-10-06 16:33 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: james.morse, dvyukov, syzbot+c2c79c6d6eddc5262b77, stable,
	Steven Price, Andrey Konovalov, Vincenzo Frascino, Will Deacon

Prior to commit 69e3b846d8a7 ("arm64: mte: Sync tags for pages where PTE
is untagged"), mte_sync_tags() was only called for pte_tagged() entries
(those mapped with PROT_MTE). Therefore mte_sync_tags() could safely use
test_and_set_bit(PG_mte_tagged, &page->flags) without inadvertently
setting PG_mte_tagged on an untagged page.

The above commit was required as guests may enable MTE without any
control at the stage 2 mapping, nor a PROT_MTE mapping in the VMM.
However, the side-effect was that any page with a PTE that looked like
swap (or migration) was getting PG_mte_tagged set automatically. A
subsequent page copy (e.g. migration) copied the tags to the destination
page even if the tags were owned by KASAN.

This issue was masked by the page_kasan_tag_reset() call introduced in
commit e5b8d9218951 ("arm64: mte: reset the page tag in page->flags").
When this commit was reverted (20794545c146), KASAN started reporting
access faults because the overriding tags in a page did not match the
original page->flags (with CONFIG_KASAN_HW_TAGS=y):

  BUG: KASAN: invalid-access in copy_page+0x10/0xd0 arch/arm64/lib/copy_page.S:26
  Read at addr f5ff000017f2e000 by task syz-executor.1/2218
  Pointer tag: [f5], memory tag: [f2]

Move the PG_mte_tagged bit setting from mte_sync_tags() to the actual
place where tags are cleared (mte_sync_page_tags()) or restored
(mte_restore_tags()).

Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Reported-by: syzbot+c2c79c6d6eddc5262b77@syzkaller.appspotmail.com
Fixes: 69e3b846d8a7 ("arm64: mte: Sync tags for pages where PTE is untagged")
Cc: <stable@vger.kernel.org> # 5.14.x
Cc: Steven Price <steven.price@arm.com>
Cc: Andrey Konovalov <andreyknvl@gmail.com>
Cc: Vincenzo Frascino <vincenzo.frascino@arm.com>
Cc: Will Deacon <will@kernel.org>
Link: https://lore.kernel.org/r/0000000000004387dc05e5888ae5@google.com/
---

This seems to work for me but reproducing the issue is not entirely
consistent. Once reviewed, we can merge it and then it will hit the
various CI systems and syzbot.

 arch/arm64/kernel/mte.c | 9 +++++++--
 arch/arm64/mm/mteswap.c | 7 ++++++-
 2 files changed, 13 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/kernel/mte.c b/arch/arm64/kernel/mte.c
index aca88470fb69..7467217c1eaf 100644
--- a/arch/arm64/kernel/mte.c
+++ b/arch/arm64/kernel/mte.c
@@ -48,7 +48,12 @@ static void mte_sync_page_tags(struct page *page, pte_t old_pte,
 	if (!pte_is_tagged)
 		return;
 
-	mte_clear_page_tags(page_address(page));
+	/*
+	 * Test PG_mte_tagged again in case it was racing with another
+	 * set_pte_at().
+	 */
+	if (!test_and_set_bit(PG_mte_tagged, &page->flags))
+		mte_clear_page_tags(page_address(page));
 }
 
 void mte_sync_tags(pte_t old_pte, pte_t pte)
@@ -64,7 +69,7 @@ void mte_sync_tags(pte_t old_pte, pte_t pte)
 
 	/* if PG_mte_tagged is set, tags have already been initialised */
 	for (i = 0; i < nr_pages; i++, page++) {
-		if (!test_and_set_bit(PG_mte_tagged, &page->flags))
+		if (!test_bit(PG_mte_tagged, &page->flags))
 			mte_sync_page_tags(page, old_pte, check_swap,
 					   pte_is_tagged);
 	}
diff --git a/arch/arm64/mm/mteswap.c b/arch/arm64/mm/mteswap.c
index 4334dec93bd4..bed803d8e158 100644
--- a/arch/arm64/mm/mteswap.c
+++ b/arch/arm64/mm/mteswap.c
@@ -53,7 +53,12 @@ bool mte_restore_tags(swp_entry_t entry, struct page *page)
 	if (!tags)
 		return false;
 
-	mte_restore_page_tags(page_address(page), tags);
+	/*
+	 * Test PG_mte_tagged again in case it was racing with another
+	 * set_pte_at().
+	 */
+	if (!test_and_set_bit(PG_mte_tagged, &page->flags))
+		mte_restore_page_tags(page_address(page), tags);
 
 	return true;
 }

base-commit: d2995249a2f72333a4ab4922ff3c42a76c023791

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH] arm64: mte: Avoid setting PG_mte_tagged if no tags cleared or restored
  2022-10-06 16:33 [PATCH] arm64: mte: Avoid setting PG_mte_tagged if no tags cleared or restored Catalin Marinas
@ 2022-10-07 15:25 ` Steven Price
  2022-10-12 16:36 ` Catalin Marinas
  1 sibling, 0 replies; 3+ messages in thread
From: Steven Price @ 2022-10-07 15:25 UTC (permalink / raw)
  To: Catalin Marinas, linux-arm-kernel
  Cc: james.morse, dvyukov, syzbot+c2c79c6d6eddc5262b77, stable,
	Andrey Konovalov, Vincenzo Frascino, Will Deacon

On 06/10/2022 17:33, Catalin Marinas wrote:
> Prior to commit 69e3b846d8a7 ("arm64: mte: Sync tags for pages where PTE
> is untagged"), mte_sync_tags() was only called for pte_tagged() entries
> (those mapped with PROT_MTE). Therefore mte_sync_tags() could safely use
> test_and_set_bit(PG_mte_tagged, &page->flags) without inadvertently
> setting PG_mte_tagged on an untagged page.
> 
> The above commit was required as guests may enable MTE without any
> control at the stage 2 mapping, nor a PROT_MTE mapping in the VMM.
> However, the side-effect was that any page with a PTE that looked like
> swap (or migration) was getting PG_mte_tagged set automatically. A
> subsequent page copy (e.g. migration) copied the tags to the destination
> page even if the tags were owned by KASAN.
> 
> This issue was masked by the page_kasan_tag_reset() call introduced in
> commit e5b8d9218951 ("arm64: mte: reset the page tag in page->flags").
> When this commit was reverted (20794545c146), KASAN started reporting
> access faults because the overriding tags in a page did not match the
> original page->flags (with CONFIG_KASAN_HW_TAGS=y):
> 
>   BUG: KASAN: invalid-access in copy_page+0x10/0xd0 arch/arm64/lib/copy_page.S:26
>   Read at addr f5ff000017f2e000 by task syz-executor.1/2218
>   Pointer tag: [f5], memory tag: [f2]
> 
> Move the PG_mte_tagged bit setting from mte_sync_tags() to the actual
> place where tags are cleared (mte_sync_page_tags()) or restored
> (mte_restore_tags()).
> 
> Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
> Reported-by: syzbot+c2c79c6d6eddc5262b77@syzkaller.appspotmail.com
> Fixes: 69e3b846d8a7 ("arm64: mte: Sync tags for pages where PTE is untagged")
> Cc: <stable@vger.kernel.org> # 5.14.x
> Cc: Steven Price <steven.price@arm.com>
> Cc: Andrey Konovalov <andreyknvl@gmail.com>
> Cc: Vincenzo Frascino <vincenzo.frascino@arm.com>
> Cc: Will Deacon <will@kernel.org>
> Link: https://lore.kernel.org/r/0000000000004387dc05e5888ae5@google.com/

Reviewed-by: Steven Price <steven.price@arm.com>

> ---
> 
> This seems to work for me but reproducing the issue is not entirely
> consistent. Once reviewed, we can merge it and then it will hit the
> various CI systems and syzbot.

As you say - it seems to work, hopefully the bots will agree!

Steve

> 
>  arch/arm64/kernel/mte.c | 9 +++++++--
>  arch/arm64/mm/mteswap.c | 7 ++++++-
>  2 files changed, 13 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/arm64/kernel/mte.c b/arch/arm64/kernel/mte.c
> index aca88470fb69..7467217c1eaf 100644
> --- a/arch/arm64/kernel/mte.c
> +++ b/arch/arm64/kernel/mte.c
> @@ -48,7 +48,12 @@ static void mte_sync_page_tags(struct page *page, pte_t old_pte,
>  	if (!pte_is_tagged)
>  		return;
>  
> -	mte_clear_page_tags(page_address(page));
> +	/*
> +	 * Test PG_mte_tagged again in case it was racing with another
> +	 * set_pte_at().
> +	 */
> +	if (!test_and_set_bit(PG_mte_tagged, &page->flags))
> +		mte_clear_page_tags(page_address(page));
>  }
>  
>  void mte_sync_tags(pte_t old_pte, pte_t pte)
> @@ -64,7 +69,7 @@ void mte_sync_tags(pte_t old_pte, pte_t pte)
>  
>  	/* if PG_mte_tagged is set, tags have already been initialised */
>  	for (i = 0; i < nr_pages; i++, page++) {
> -		if (!test_and_set_bit(PG_mte_tagged, &page->flags))
> +		if (!test_bit(PG_mte_tagged, &page->flags))
>  			mte_sync_page_tags(page, old_pte, check_swap,
>  					   pte_is_tagged);
>  	}
> diff --git a/arch/arm64/mm/mteswap.c b/arch/arm64/mm/mteswap.c
> index 4334dec93bd4..bed803d8e158 100644
> --- a/arch/arm64/mm/mteswap.c
> +++ b/arch/arm64/mm/mteswap.c
> @@ -53,7 +53,12 @@ bool mte_restore_tags(swp_entry_t entry, struct page *page)
>  	if (!tags)
>  		return false;
>  
> -	mte_restore_page_tags(page_address(page), tags);
> +	/*
> +	 * Test PG_mte_tagged again in case it was racing with another
> +	 * set_pte_at().
> +	 */
> +	if (!test_and_set_bit(PG_mte_tagged, &page->flags))
> +		mte_restore_page_tags(page_address(page), tags);
>  
>  	return true;
>  }
> 
> base-commit: d2995249a2f72333a4ab4922ff3c42a76c023791


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] arm64: mte: Avoid setting PG_mte_tagged if no tags cleared or restored
  2022-10-06 16:33 [PATCH] arm64: mte: Avoid setting PG_mte_tagged if no tags cleared or restored Catalin Marinas
  2022-10-07 15:25 ` Steven Price
@ 2022-10-12 16:36 ` Catalin Marinas
  1 sibling, 0 replies; 3+ messages in thread
From: Catalin Marinas @ 2022-10-12 16:36 UTC (permalink / raw)
  To: linux-arm-kernel, Catalin Marinas
  Cc: Will Deacon, Steven Price, stable, syzbot+c2c79c6d6eddc5262b77,
	Andrey Konovalov, james.morse, Vincenzo Frascino, dvyukov

On Thu, 6 Oct 2022 17:33:54 +0100, Catalin Marinas wrote:
> Prior to commit 69e3b846d8a7 ("arm64: mte: Sync tags for pages where PTE
> is untagged"), mte_sync_tags() was only called for pte_tagged() entries
> (those mapped with PROT_MTE). Therefore mte_sync_tags() could safely use
> test_and_set_bit(PG_mte_tagged, &page->flags) without inadvertently
> setting PG_mte_tagged on an untagged page.
> 
> The above commit was required as guests may enable MTE without any
> control at the stage 2 mapping, nor a PROT_MTE mapping in the VMM.
> However, the side-effect was that any page with a PTE that looked like
> swap (or migration) was getting PG_mte_tagged set automatically. A
> subsequent page copy (e.g. migration) copied the tags to the destination
> page even if the tags were owned by KASAN.
> 
> [...]

Applied to arm64 (for-next/core), thanks!

[1/1] arm64: mte: Avoid setting PG_mte_tagged if no tags cleared or restored
      https://git.kernel.org/arm64/c/a8e5e5146ad0

-- 
Catalin


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2022-10-12 16:38 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-10-06 16:33 [PATCH] arm64: mte: Avoid setting PG_mte_tagged if no tags cleared or restored Catalin Marinas
2022-10-07 15:25 ` Steven Price
2022-10-12 16:36 ` Catalin Marinas

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).