Skip to content

Commit a8e5e51

Browse files
committed
arm64: mte: Avoid setting PG_mte_tagged if no tags cleared or restored
Prior to commit 69e3b84 ("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 e5b8d92 ("arm64: mte: reset the page tag in page->flags"). When this commit was reverted (2079454), 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: 69e3b84 ("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> Link: https://lore.kernel.org/r/20221006163354.3194102-1-catalin.marinas@arm.com Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
1 parent 5f4853e commit a8e5e51

File tree

2 files changed

+13
-3
lines changed

2 files changed

+13
-3
lines changed

arch/arm64/kernel/mte.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,12 @@ static void mte_sync_page_tags(struct page *page, pte_t old_pte,
4848
if (!pte_is_tagged)
4949
return;
5050

51-
mte_clear_page_tags(page_address(page));
51+
/*
52+
* Test PG_mte_tagged again in case it was racing with another
53+
* set_pte_at().
54+
*/
55+
if (!test_and_set_bit(PG_mte_tagged, &page->flags))
56+
mte_clear_page_tags(page_address(page));
5257
}
5358

5459
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)
6469

6570
/* if PG_mte_tagged is set, tags have already been initialised */
6671
for (i = 0; i < nr_pages; i++, page++) {
67-
if (!test_and_set_bit(PG_mte_tagged, &page->flags))
72+
if (!test_bit(PG_mte_tagged, &page->flags))
6873
mte_sync_page_tags(page, old_pte, check_swap,
6974
pte_is_tagged);
7075
}

arch/arm64/mm/mteswap.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,12 @@ bool mte_restore_tags(swp_entry_t entry, struct page *page)
5353
if (!tags)
5454
return false;
5555

56-
mte_restore_page_tags(page_address(page), tags);
56+
/*
57+
* Test PG_mte_tagged again in case it was racing with another
58+
* set_pte_at().
59+
*/
60+
if (!test_and_set_bit(PG_mte_tagged, &page->flags))
61+
mte_restore_page_tags(page_address(page), tags);
5762

5863
return true;
5964
}

0 commit comments

Comments
 (0)