From: Andrey Konovalov <redacted>
Hi,
This patchset adds vmalloc tagging support for SW_TAGS and HW_TAGS
KASAN modes.
The tree with patches is available here:
https://github.com/xairy/linux/tree/up-kasan-vmalloc-tags-v3-akpm
About half of patches are cleanups I went for along the way. None of
them seem to be important enough to go through stable, so I decided
not to split them out into separate patches/series.
The patchset is partially based on an early version of the HW_TAGS
patchset by Vincenzo that had vmalloc support. Thus, I added a
Co-developed-by tag into a few patches.
SW_TAGS vmalloc tagging support is straightforward. It reuses all of
the generic KASAN machinery, but uses shadow memory to store tags
instead of magic values. Naturally, vmalloc tagging requires adding
a few kasan_reset_tag() annotations to the vmalloc code.
HW_TAGS vmalloc tagging support stands out. HW_TAGS KASAN is based on
Arm MTE, which can only assigns tags to physical memory. As a result,
HW_TAGS KASAN only tags vmalloc() allocations, which are backed by
page_alloc memory. It ignores vmap() and others.
Changes in v2->v3:
- Rebase onto mm.
- New patch: "kasan, arm64: reset pointer tags of vmapped stacks".
- New patch: "kasan, vmalloc: don't tag executable vmalloc allocations".
- New patch: "kasan, arm64: don't tag executable vmalloc allocations".
- Allowing enabling KASAN_VMALLOC with SW/HW_TAGS is moved to
"kasan: allow enabling KASAN_VMALLOC and SW/HW_TAGS", as this can only
be done once executable allocations are no longer tagged.
- Minor fixes, see patches for lists of changes.
Changes in v1->v2:
- Move memory init for vmalloc() into vmalloc code for HW_TAGS KASAN.
- Minor fixes and code reshuffling, see patches for lists of changes.
Thanks!
Andrey Konovalov (38):
kasan, page_alloc: deduplicate should_skip_kasan_poison
kasan, page_alloc: move tag_clear_highpage out of
kernel_init_free_pages
kasan, page_alloc: merge kasan_free_pages into free_pages_prepare
kasan, page_alloc: simplify kasan_poison_pages call site
kasan, page_alloc: init memory of skipped pages on free
kasan: drop skip_kasan_poison variable in free_pages_prepare
mm: clarify __GFP_ZEROTAGS comment
kasan: only apply __GFP_ZEROTAGS when memory is zeroed
kasan, page_alloc: refactor init checks in post_alloc_hook
kasan, page_alloc: merge kasan_alloc_pages into post_alloc_hook
kasan, page_alloc: combine tag_clear_highpage calls in post_alloc_hook
kasan, page_alloc: move SetPageSkipKASanPoison in post_alloc_hook
kasan, page_alloc: move kernel_init_free_pages in post_alloc_hook
kasan, page_alloc: simplify kasan_unpoison_pages call site
kasan: clean up metadata byte definitions
kasan: define KASAN_VMALLOC_INVALID for SW_TAGS
kasan, x86, arm64, s390: rename functions for modules shadow
kasan, vmalloc: drop outdated VM_KASAN comment
kasan: reorder vmalloc hooks
kasan: add wrappers for vmalloc hooks
kasan, vmalloc: reset tags in vmalloc functions
kasan, fork: reset pointer tags of vmapped stacks
kasan, arm64: reset pointer tags of vmapped stacks
kasan, vmalloc: add vmalloc tagging for SW_TAGS
kasan, vmalloc, arm64: mark vmalloc mappings as pgprot_tagged
kasan, vmalloc: don't unpoison VM_ALLOC pages before mapping
kasan, page_alloc: allow skipping unpoisoning for HW_TAGS
kasan, page_alloc: allow skipping memory init for HW_TAGS
kasan, vmalloc: add vmalloc tagging for HW_TAGS
kasan, vmalloc: don't tag executable vmalloc allocations
kasan, arm64: don't tag executable vmalloc allocations
kasan: mark kasan_arg_stacktrace as __initdata
kasan: simplify kasan_init_hw_tags
kasan: add kasan.vmalloc command line flag
kasan: allow enabling KASAN_VMALLOC and SW/HW_TAGS
arm64: select KASAN_VMALLOC for SW/HW_TAGS modes
kasan: documentation updates
kasan: improve vmalloc tests
Documentation/dev-tools/kasan.rst | 17 ++-
arch/arm64/Kconfig | 2 +-
arch/arm64/include/asm/vmalloc.h | 10 ++
arch/arm64/include/asm/vmap_stack.h | 5 +-
arch/arm64/kernel/module.c | 5 +-
arch/arm64/net/bpf_jit_comp.c | 3 +-
arch/s390/kernel/module.c | 2 +-
arch/x86/kernel/module.c | 2 +-
include/linux/gfp.h | 28 +++--
include/linux/kasan.h | 97 +++++++++------
include/linux/vmalloc.h | 18 ++-
kernel/fork.c | 1 +
kernel/scs.c | 4 +-
lib/Kconfig.kasan | 20 +--
lib/test_kasan.c | 181 +++++++++++++++++++++++++++-
mm/kasan/common.c | 4 +-
mm/kasan/hw_tags.c | 166 ++++++++++++++++++++-----
mm/kasan/kasan.h | 16 ++-
mm/kasan/shadow.c | 63 ++++++----
mm/page_alloc.c | 150 +++++++++++++++--------
mm/vmalloc.c | 78 ++++++++++--
21 files changed, 668 insertions(+), 204 deletions(-)
--
2.25.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: Andrey Konovalov <redacted>
Currently, should_skip_kasan_poison() has two definitions: one for when
CONFIG_DEFERRED_STRUCT_PAGE_INIT is enabled, one for when it's not.
Instead of duplicating the checks, add a deferred_pages_enabled()
helper and use it in a single should_skip_kasan_poison() definition.
Also move should_skip_kasan_poison() closer to its caller and clarify
all conditions in the comment.
Signed-off-by: Andrey Konovalov <redacted>
---
Changes v2->v3:
- Update patch description.
---
mm/page_alloc.c | 55 +++++++++++++++++++++++++++++--------------------
1 file changed, 33 insertions(+), 22 deletions(-)
@@ -377,25 +377,9 @@ int page_group_by_mobility_disabled __read_mostly;*/staticDEFINE_STATIC_KEY_TRUE(deferred_pages);-/*-*Callingkasan_poison_pages()onlyafterdeferredmemoryinitialization-*hascompleted.Poisoningpagesduringdeferredmemoryinitwillgreatly-*lengthentheprocessandcauseprobleminlargememorysystemsasthe-*deferredpagesinitializationisdonewithinterruptdisabled.-*-*Assumingthattherewillbenoreferencetothosenewlyinitialized-*pagesbeforetheyareeverallocated,thisshouldhavenoeffecton-*KASANmemorytrackingasthepoisonwillbeproperlyinsertedatpage-*allocationtime.Theonlycornercaseiswhenpagesareallocatedby-*on-demandallocationandthenfreedagainbeforethedeferredpages-*initializationisdone,butthisisnotlikelytohappen.-*/-staticinlineboolshould_skip_kasan_poison(structpage*page,fpi_tfpi_flags)+staticinlinebooldeferred_pages_enabled(void){-returnstatic_branch_unlikely(&deferred_pages)||-(!IS_ENABLED(CONFIG_KASAN_GENERIC)&&-(fpi_flags&FPI_SKIP_KASAN_POISON))||-PageSkipKASanPoison(page);+returnstatic_branch_unlikely(&deferred_pages);}/* Returns true if the struct page for the pfn is uninitialised */
@@ -446,11 +430,9 @@ defer_init(int nid, unsigned long pfn, unsigned long end_pfn)returnfalse;}#else-staticinlineboolshould_skip_kasan_poison(structpage*page,fpi_tfpi_flags)+staticinlinebooldeferred_pages_enabled(void){-return(!IS_ENABLED(CONFIG_KASAN_GENERIC)&&-(fpi_flags&FPI_SKIP_KASAN_POISON))||-PageSkipKASanPoison(page);+returnfalse;}staticinlineboolearly_page_uninitialised(unsignedlongpfn)
From: Andrey Konovalov <redacted>
Currently, kernel_init_free_pages() serves two purposes: it either only
zeroes memory or zeroes both memory and memory tags via a different
code path. As this function has only two callers, each using only one
code path, this behaviour is confusing.
Pull the code that zeroes both memory and tags out of
kernel_init_free_pages().
As a result of this change, the code in free_pages_prepare() starts to
look complicated, but this is improved in the few following patches.
Those improvements are not integrated into this patch to make diffs
easier to read.
This patch does no functional changes.
Signed-off-by: Andrey Konovalov <redacted>
Reviewed-by: Alexander Potapenko <glider@google.com>
---
Changes v2->v3:
- Update patch description.
---
mm/page_alloc.c | 24 +++++++++++++-----------
1 file changed, 13 insertions(+), 11 deletions(-)
From: Andrey Konovalov <redacted>
Currently, the code responsible for initializing and poisoning memory
in free_pages_prepare() is scattered across two locations:
kasan_free_pages() for HW_TAGS KASAN and free_pages_prepare() itself.
This is confusing.
This and a few following patches combine the code from these two
locations. Along the way, these patches also simplify the performed
checks to make them easier to follow.
Replaces the only caller of kasan_free_pages() with its implementation.
As kasan_has_integrated_init() is only true when CONFIG_KASAN_HW_TAGS
is enabled, moving the code does no functional changes.
This patch is not useful by itself but makes the simplifications in
the following patches easier to follow.
Signed-off-by: Andrey Konovalov <redacted>
Reviewed-by: Alexander Potapenko <glider@google.com>
---
Changes v2->v3:
- Update patch description.
---
include/linux/kasan.h | 8 --------
mm/kasan/common.c | 2 +-
mm/kasan/hw_tags.c | 11 -----------
mm/page_alloc.c | 6 ++++--
4 files changed, 5 insertions(+), 22 deletions(-)
From: Alexander Potapenko <glider@google.com> Date: 2021-12-16 12:55:05
On Mon, Dec 13, 2021 at 10:52 PM [off-list ref] wrote:
From: Andrey Konovalov <redacted>
Simplify the code around calling kasan_poison_pages() in
free_pages_prepare().
This patch does no functional changes.
Signed-off-by: Andrey Konovalov <redacted>
From: Andrey Konovalov <redacted>
Since commit 7a3b83537188 ("kasan: use separate (un)poison implementation
for integrated init"), when all init, kasan_has_integrated_init(), and
skip_kasan_poison are true, free_pages_prepare() doesn't initialize
the page. This is wrong.
Fix it by remembering whether kasan_poison_pages() performed
initialization, and call kernel_init_free_pages() if it didn't.
Reordering kasan_poison_pages() and kernel_init_free_pages() is OK,
since kernel_init_free_pages() can handle poisoned memory.
Signed-off-by: Andrey Konovalov <redacted>
---
Changes v2->v3:
- Drop Fixes tag, as the patch won't cleanly apply to older kernels
anyway. The commit is mentioned in the patch description.
Changes v1->v2:
- Reorder kasan_poison_pages() and free_pages_prepare() in this patch
instead of doing it in the previous one.
---
mm/page_alloc.c | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
@@ -1374,11 +1374,16 @@ static __always_inline bool free_pages_prepare(struct page *page,*Withhardwaretag-basedKASAN,memorytagsmustbesetbeforethe*pagebecomesunavailableviadebug_pageallocorarch_free_page.*/-if(init&&!kasan_has_integrated_init())-kernel_init_free_pages(page,1<<order);-if(!skip_kasan_poison)+if(!skip_kasan_poison){kasan_poison_pages(page,order,init);+/* Memory is already initialized if KASAN did it internally. */+if(kasan_has_integrated_init())+init=false;+}+if(init)+kernel_init_free_pages(page,1<<order);+/**arch_free_page()canmakethepage'scontentsinaccessible.s390*doesthis.Sonothingwhichcanaccessthepage'scontentsshould
--
2.25.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: Andrey Konovalov <redacted>
skip_kasan_poison is only used in a single place.
Call should_skip_kasan_poison() directly for simplicity.
Signed-off-by: Andrey Konovalov <redacted>
Suggested-by: Marco Elver <elver@google.com>
---
Changes v1->v2:
- Add this patch.
---
mm/page_alloc.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
@@ -1374,7 +1373,7 @@ static __always_inline bool free_pages_prepare(struct page *page,*Withhardwaretag-basedKASAN,memorytagsmustbesetbeforethe*pagebecomesunavailableviadebug_pageallocorarch_free_page.*/-if(!skip_kasan_poison){+if(!should_skip_kasan_poison(page,fpi_flags)){kasan_poison_pages(page,order,init);/* Memory is already initialized if KASAN did it internally. */
--
2.25.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: Andrey Konovalov <redacted>
__GFP_ZEROTAGS should only be effective if memory is being zeroed.
Currently, hardware tag-based KASAN violates this requirement.
Fix by including an initialization check along with checking for
__GFP_ZEROTAGS.
Signed-off-by: Andrey Konovalov <redacted>
Reviewed-by: Alexander Potapenko <glider@google.com>
---
mm/kasan/hw_tags.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
From: Andrey Konovalov <redacted>
__GFP_ZEROTAGS is intended as an optimization: if memory is zeroed during
allocation, it's possible to set memory tags at the same time with little
performance impact.
Clarify this intention of __GFP_ZEROTAGS in the comment.
Signed-off-by: Andrey Konovalov <redacted>
---
include/linux/gfp.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
From: Andrey Konovalov <redacted>
Separate code for zeroing memory from the code clearing tags in
post_alloc_hook().
This patch is not useful by itself but makes the simplifications in
the following patches easier to follow.
This patch does no functional changes.
Signed-off-by: Andrey Konovalov <redacted>
---
Changes v2->v3:
- Update patch description.
---
mm/page_alloc.c | 18 ++++++++++--------
1 file changed, 10 insertions(+), 8 deletions(-)
From: Alexander Potapenko <glider@google.com> Date: 2021-12-16 13:33:35
On Mon, Dec 13, 2021 at 10:52 PM [off-list ref] wrote:
From: Andrey Konovalov <redacted>
Separate code for zeroing memory from the code clearing tags in
post_alloc_hook().
This patch is not useful by itself but makes the simplifications in
the following patches easier to follow.
This patch does no functional changes.
Signed-off-by: Andrey Konovalov <redacted>
From: Andrey Konovalov <redacted>
Currently, the code responsible for initializing and poisoning memory in
post_alloc_hook() is scattered across two locations: kasan_alloc_pages()
hook for HW_TAGS KASAN and post_alloc_hook() itself. This is confusing.
This and a few following patches combine the code from these two
locations. Along the way, these patches do a step-by-step restructure
the many performed checks to make them easier to follow.
Replace the only caller of kasan_alloc_pages() with its implementation.
As kasan_has_integrated_init() is only true when CONFIG_KASAN_HW_TAGS
is enabled, moving the code does no functional changes.
Also move init and init_tags variables definitions out of
kasan_has_integrated_init() clause in post_alloc_hook(), as they have
the same values regardless of what the if condition evaluates to.
This patch is not useful by itself but makes the simplifications in
the following patches easier to follow.
Signed-off-by: Andrey Konovalov <redacted>
---
Changes v2->v3:
- Update patch description.
---
include/linux/kasan.h | 9 ---------
mm/kasan/common.c | 2 +-
mm/kasan/hw_tags.c | 22 ----------------------
mm/page_alloc.c | 20 +++++++++++++++-----
4 files changed, 16 insertions(+), 37 deletions(-)
@@ -2418,30 +2418,30 @@ inline void post_alloc_hook(struct page *page, unsigned int order,*KASANunpoisoningandmemoryinitializioncodemustbe*kepttogethertoavoiddiscrepanciesinbehavior.*/++/*+*Ifmemorytagsshouldbezeroed(whichhappensonlywhenmemory+*shouldbeinitializedaswell).+*/+if(init_tags){+inti;++/* Initialize both memory and tags. */+for(i=0;i!=1<<order;++i)+tag_clear_highpage(page+i);++/* Note that memory is already initialized by the loop above. */+init=false;+}if(kasan_has_integrated_init()){if(gfp_flags&__GFP_SKIP_KASAN_POISON)SetPageSkipKASanPoison(page);-if(init_tags){-inti;--for(i=0;i!=1<<order;++i)-tag_clear_highpage(page+i);-}else{+if(!init_tags)kasan_unpoison_pages(page,order,init);-}}else{kasan_unpoison_pages(page,order,init);-if(init_tags){-inti;--for(i=0;i<1<<order;i++)-tag_clear_highpage(page+i);--init=false;-}-if(init)kernel_init_free_pages(page,1<<order);}
--
2.25.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: Alexander Potapenko <glider@google.com> Date: 2021-12-16 13:05:39
On Mon, Dec 13, 2021 at 10:53 PM [off-list ref] wrote:
From: Andrey Konovalov <redacted>
Move tag_clear_highpage() loops out of the kasan_has_integrated_init()
clause as a code simplification.
This patch does no functional changes.
Signed-off-by: Andrey Konovalov <redacted>
From: Andrey Konovalov <redacted>
Pull the SetPageSkipKASanPoison() call in post_alloc_hook() out of the
big if clause for better code readability. This also allows for more
simplifications in the following patches.
Also turn the kasan_has_integrated_init() check into the proper
CONFIG_KASAN_HW_TAGS one. These checks evaluate to the same value,
but logically skipping kasan poisoning has nothing to do with
integrated init.
Signed-off-by: Andrey Konovalov <redacted>
---
mm/page_alloc.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
From: Andrey Konovalov <redacted>
Pull the kernel_init_free_pages() call in post_alloc_hook() out of the
big if clause for better code readability. This also allows for more
simplifications in the following patch.
This patch does no functional changes.
Signed-off-by: Andrey Konovalov <redacted>
---
mm/page_alloc.c | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
@@ -2434,14 +2434,18 @@ inline void post_alloc_hook(struct page *page, unsigned int order,init=false;}if(kasan_has_integrated_init()){-if(!init_tags)+if(!init_tags){kasan_unpoison_pages(page,order,init);++/* Note that memory is already initialized by KASAN. */+init=false;+}}else{kasan_unpoison_pages(page,order,init);--if(init)-kernel_init_free_pages(page,1<<order);}+/* If memory is still not initialized, do it now. */+if(init)+kernel_init_free_pages(page,1<<order);/* Propagate __GFP_SKIP_KASAN_POISON to page flags. */if(IS_ENABLED(CONFIG_KASAN_HW_TAGS)&&(gfp_flags&__GFP_SKIP_KASAN_POISON))
--
2.25.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: Alexander Potapenko <glider@google.com> Date: 2021-12-16 11:00:45
On Mon, Dec 13, 2021 at 10:53 PM [off-list ref] wrote:
From: Andrey Konovalov <redacted>
Pull the kernel_init_free_pages() call in post_alloc_hook() out of the
big if clause for better code readability. This also allows for more
simplifications in the following patch.
This patch does no functional changes.
Signed-off-by: Andrey Konovalov <redacted>
From: Andrey Konovalov <redacted>
Simplify the checks around kasan_unpoison_pages() call in
post_alloc_hook().
The logical condition for calling this function is:
- If a software KASAN mode is enabled, we need to mark shadow memory.
- Otherwise, HW_TAGS KASAN is enabled, and it only makes sense to
set tags if they haven't already been cleared by tag_clear_highpage(),
which is indicated by init_tags.
This patch concludes the simplifications for post_alloc_hook().
Signed-off-by: Andrey Konovalov <redacted>
---
mm/page_alloc.c | 17 ++++++++++-------
1 file changed, 10 insertions(+), 7 deletions(-)
@@ -2433,15 +2433,18 @@ inline void post_alloc_hook(struct page *page, unsigned int order,/* Note that memory is already initialized by the loop above. */init=false;}-if(kasan_has_integrated_init()){-if(!init_tags){-kasan_unpoison_pages(page,order,init);+/*+*IfeitherasoftwareKASANmodeisenabled,or,+*inthecaseofhardwaretag-basedKASAN,+*ifmemorytagshavenotbeenclearedviatag_clear_highpage().+*/+if(!IS_ENABLED(CONFIG_KASAN_HW_TAGS)||!init_tags){+/* Mark shadow memory or set memory tags. */+kasan_unpoison_pages(page,order,init);-/* Note that memory is already initialized by KASAN. */+/* Note that memory is already initialized by KASAN. */+if(kasan_has_integrated_init())init=false;-}-}else{-kasan_unpoison_pages(page,order,init);}/* If memory is still not initialized, do it now. */if(init)
--
2.25.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: Andrey Konovalov <redacted>
Most of the metadata byte values are only used for Generic KASAN.
Remove KASAN_KMALLOC_FREETRACK definition for !CONFIG_KASAN_GENERIC
case, and put it along with other metadata values for the Generic
mode under a corresponding ifdef.
Signed-off-by: Andrey Konovalov <redacted>
---
mm/kasan/kasan.h | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
From: Alexander Potapenko <glider@google.com> Date: 2021-12-16 10:53:09
On Mon, Dec 13, 2021 at 10:53 PM [off-list ref] wrote:
From: Andrey Konovalov <redacted>
Most of the metadata byte values are only used for Generic KASAN.
Remove KASAN_KMALLOC_FREETRACK definition for !CONFIG_KASAN_GENERIC
case, and put it along with other metadata values for the Generic
mode under a corresponding ifdef.
Signed-off-by: Andrey Konovalov <redacted>
From: Andrey Konovalov <redacted>
In preparation for adding vmalloc support to SW_TAGS KASAN,
provide a KASAN_VMALLOC_INVALID definition for it.
HW_TAGS KASAN won't be using this value, as it falls back onto
page_alloc for poisoning freed vmalloc() memory.
Signed-off-by: Andrey Konovalov <redacted>
---
mm/kasan/kasan.h | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
From: Andrey Konovalov <redacted>
Rename kasan_free_shadow to kasan_free_module_shadow and
kasan_module_alloc to kasan_alloc_module_shadow.
These functions are used to allocate/free shadow memory for kernel
modules when KASAN_VMALLOC is not enabled. The new names better
reflect their purpose.
Also reword the comment next to their declaration to improve clarity.
Signed-off-by: Andrey Konovalov <redacted>
Acked-by: Catalin Marinas <catalin.marinas@arm.com>
---
arch/arm64/kernel/module.c | 2 +-
arch/s390/kernel/module.c | 2 +-
arch/x86/kernel/module.c | 2 +-
include/linux/kasan.h | 14 +++++++-------
mm/kasan/shadow.c | 4 ++--
mm/vmalloc.c | 2 +-
6 files changed, 13 insertions(+), 13 deletions(-)
From: Andrey Konovalov <redacted>
The comment about VM_KASAN in include/linux/vmalloc.c is outdated.
VM_KASAN is currently only used to mark vm_areas allocated for
kernel modules when CONFIG_KASAN_VMALLOC is disabled.
Drop the comment.
Signed-off-by: Andrey Konovalov <redacted>
---
include/linux/vmalloc.h | 11 -----------
1 file changed, 11 deletions(-)
From: Alexander Potapenko <glider@google.com> Date: 2021-12-16 10:54:27
On Mon, Dec 13, 2021 at 10:53 PM [off-list ref] wrote:
From: Andrey Konovalov <redacted>
The comment about VM_KASAN in include/linux/vmalloc.c is outdated.
VM_KASAN is currently only used to mark vm_areas allocated for
kernel modules when CONFIG_KASAN_VMALLOC is disabled.
Drop the comment.
Signed-off-by: Andrey Konovalov <redacted>
From: Andrey Konovalov <redacted>
Group functions that [de]populate shadow memory for vmalloc.
Group functions that [un]poison memory for vmalloc.
This patch does no functional changes but prepares KASAN code for
adding vmalloc support to HW_TAGS KASAN.
Signed-off-by: Andrey Konovalov <redacted>
---
include/linux/kasan.h | 20 +++++++++-----------
mm/kasan/shadow.c | 43 ++++++++++++++++++++++---------------------
2 files changed, 31 insertions(+), 32 deletions(-)
@@ -345,27 +345,6 @@ int kasan_populate_vmalloc(unsigned long addr, unsigned long size)return0;}-/*-*Poisontheshadowforavmallocregion.Calledaspartofthe-*freeingprocessatthetimetheregionisfreed.-*/-voidkasan_poison_vmalloc(constvoid*start,unsignedlongsize)-{-if(!is_vmalloc_or_module_addr(start))-return;--size=round_up(size,KASAN_GRANULE_SIZE);-kasan_poison(start,size,KASAN_VMALLOC_INVALID,false);-}--voidkasan_unpoison_vmalloc(constvoid*start,unsignedlongsize)-{-if(!is_vmalloc_or_module_addr(start))-return;--kasan_unpoison(start,size,false);-}-staticintkasan_depopulate_vmalloc_pte(pte_t*ptep,unsignedlongaddr,void*unused){
@@ -496,6 +475,28 @@ void kasan_release_vmalloc(unsigned long start, unsigned long end,}}++voidkasan_unpoison_vmalloc(constvoid*start,unsignedlongsize)+{+if(!is_vmalloc_or_module_addr(start))+return;++kasan_unpoison(start,size,false);+}++/*+*Poisontheshadowforavmallocregion.Calledaspartofthe+*freeingprocessatthetimetheregionisfreed.+*/+voidkasan_poison_vmalloc(constvoid*start,unsignedlongsize)+{+if(!is_vmalloc_or_module_addr(start))+return;++size=round_up(size,KASAN_GRANULE_SIZE);+kasan_poison(start,size,KASAN_VMALLOC_INVALID,false);+}+#else /* CONFIG_KASAN_VMALLOC */intkasan_alloc_module_shadow(void*addr,size_tsize,gfp_tgfp_mask)
--
2.25.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: Alexander Potapenko <glider@google.com> Date: 2021-12-16 10:55:45
On Mon, Dec 13, 2021 at 10:53 PM [off-list ref] wrote:
From: Andrey Konovalov <redacted>
Group functions that [de]populate shadow memory for vmalloc.
Group functions that [un]poison memory for vmalloc.
This patch does no functional changes but prepares KASAN code for
adding vmalloc support to HW_TAGS KASAN.
Signed-off-by: Andrey Konovalov <redacted>
From: Andrey Konovalov <redacted>
Add wrappers around functions that [un]poison memory for vmalloc
allocations. These functions will be used by HW_TAGS KASAN and
therefore need to be disabled when kasan=off command line argument
is provided.
This patch does no functional changes for software KASAN modes.
Signed-off-by: Andrey Konovalov <redacted>
---
include/linux/kasan.h | 17 +++++++++++++++--
mm/kasan/shadow.c | 5 ++---
2 files changed, 17 insertions(+), 5 deletions(-)
From: Andrey Konovalov <redacted>
In preparation for adding vmalloc support to SW/HW_TAGS KASAN,
reset pointer tags in functions that use pointer values in
range checks.
vread() is a special case here. Despite the untagging of the addr
pointer in its prologue, the accesses performed by vread() are checked.
Instead of accessing the virtual mappings though addr directly, vread()
recovers the physical address via page_address(vmalloc_to_page()) and
acceses that. And as page_address() recovers the pointer tag, the
accesses get checked.
Signed-off-by: Andrey Konovalov <redacted>
---
Changes v1->v2:
- Clarified the description of untagging in vread().
---
mm/vmalloc.c | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
From: Andrey Konovalov <redacted>
Once tag-based KASAN modes start tagging vmalloc() allocations,
kernel stacks start getting tagged if CONFIG_VMAP_STACK is enabled.
Reset the tag of kernel stack pointers after allocation in
alloc_thread_stack_node().
For SW_TAGS KASAN, when CONFIG_KASAN_STACK is enabled, the
instrumentation can't handle the SP register being tagged.
For HW_TAGS KASAN, there's no instrumentation-related issues. However,
the impact of having a tagged SP register needs to be properly evaluated,
so keep it non-tagged for now.
Note, that the memory for the stack allocation still gets tagged to
catch vmalloc-into-stack out-of-bounds accesses.
Signed-off-by: Andrey Konovalov <redacted>
---
Changes v2->v3:
- Update patch description.
---
kernel/fork.c | 1 +
1 file changed, 1 insertion(+)
From: Andrey Konovalov <redacted>
Once tag-based KASAN modes start tagging vmalloc() allocations,
kernel stacks start getting tagged if CONFIG_VMAP_STACK is enabled.
Reset the tag of kernel stack pointers after allocation in
arch_alloc_vmap_stack().
For SW_TAGS KASAN, when CONFIG_KASAN_STACK is enabled, the
instrumentation can't handle the SP register being tagged.
For HW_TAGS KASAN, there's no instrumentation-related issues. However,
the impact of having a tagged SP register needs to be properly evaluated,
so keep it non-tagged for now.
Note, that the memory for the stack allocation still gets tagged to
catch vmalloc-into-stack out-of-bounds accesses.
Signed-off-by: Andrey Konovalov <redacted>
---
Changes v2->v3:
- Add this patch.
---
arch/arm64/include/asm/vmap_stack.h | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
On Mon, Dec 13, 2021 at 10:54 PM [off-list ref] wrote:
quoted hunk
From: Andrey Konovalov <redacted>
Once tag-based KASAN modes start tagging vmalloc() allocations,
kernel stacks start getting tagged if CONFIG_VMAP_STACK is enabled.
Reset the tag of kernel stack pointers after allocation in
arch_alloc_vmap_stack().
For SW_TAGS KASAN, when CONFIG_KASAN_STACK is enabled, the
instrumentation can't handle the SP register being tagged.
For HW_TAGS KASAN, there's no instrumentation-related issues. However,
the impact of having a tagged SP register needs to be properly evaluated,
so keep it non-tagged for now.
Note, that the memory for the stack allocation still gets tagged to
catch vmalloc-into-stack out-of-bounds accesses.
Signed-off-by: Andrey Konovalov <redacted>
---
Changes v2->v3:
- Add this patch.
---
arch/arm64/include/asm/vmap_stack.h | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
Catalin, Vincenzo,
This is a new patch added in v3. Could you PTAL? Thanks!
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
On Mon, Dec 13, 2021 at 10:54:19PM +0100, andrey.konovalov@linux.dev wrote:
From: Andrey Konovalov <redacted>
Once tag-based KASAN modes start tagging vmalloc() allocations,
kernel stacks start getting tagged if CONFIG_VMAP_STACK is enabled.
Reset the tag of kernel stack pointers after allocation in
arch_alloc_vmap_stack().
For SW_TAGS KASAN, when CONFIG_KASAN_STACK is enabled, the
instrumentation can't handle the SP register being tagged.
For HW_TAGS KASAN, there's no instrumentation-related issues. However,
the impact of having a tagged SP register needs to be properly evaluated,
so keep it non-tagged for now.
Note, that the memory for the stack allocation still gets tagged to
catch vmalloc-into-stack out-of-bounds accesses.
Signed-off-by: Andrey Konovalov <redacted>
From: Andrey Konovalov <redacted>
Add vmalloc tagging support to SW_TAGS KASAN.
- __kasan_unpoison_vmalloc() now assigns a random pointer tag, poisons
the virtual mapping accordingly, and embeds the tag into the returned
pointer.
- __get_vm_area_node() (used by vmalloc() and vmap()) and
pcpu_get_vm_areas() save the tagged pointer into vm_struct->addr
(note: not into vmap_area->addr). This requires putting
kasan_unpoison_vmalloc() after setup_vmalloc_vm[_locked]();
otherwise the latter will overwrite the tagged pointer.
The tagged pointer then is naturally propagateed to vmalloc()
and vmap().
- vm_map_ram() returns the tagged pointer directly.
Enabling KASAN_VMALLOC with SW_TAGS is not yet allowed.
Signed-off-by: Andrey Konovalov <redacted>
---
Changes v2->v3:
- Drop accidentally added kasan_unpoison_vmalloc() argument for when
KASAN is off.
- Drop __must_check for kasan_unpoison_vmalloc(), as its result is
sometimes intentionally ignored.
- Move allowing enabling KASAN_VMALLOC with SW_TAGS into a separate
patch.
- Update patch description.
Changes v1->v2:
- Allow enabling KASAN_VMALLOC with SW_TAGS in this patch.
---
include/linux/kasan.h | 16 ++++++++++------
mm/kasan/shadow.c | 6 ++++--
mm/vmalloc.c | 14 ++++++++------
3 files changed, 22 insertions(+), 14 deletions(-)
@@ -2208,7 +2208,7 @@ void *vm_map_ram(struct page **pages, unsigned int count, int node)mem=(void*)addr;}-kasan_unpoison_vmalloc(mem,size);+mem=kasan_unpoison_vmalloc(mem,size);if(vmap_pages_range(addr,addr+size,PAGE_KERNEL,pages,PAGE_SHIFT)<0){
@@ -2441,10 +2441,10 @@ static struct vm_struct *__get_vm_area_node(unsigned long size,returnNULL;}-kasan_unpoison_vmalloc((void*)va->va_start,requested_size);-setup_vmalloc_vm(area,va,flags,caller);+area->addr=kasan_unpoison_vmalloc(area->addr,requested_size);+returnarea;}
@@ -3785,9 +3785,6 @@ struct vm_struct **pcpu_get_vm_areas(const unsigned long *offsets,for(area=0;area<nr_vms;area++){if(kasan_populate_vmalloc(vas[area]->va_start,sizes[area]))gotoerr_free_shadow;--kasan_unpoison_vmalloc((void*)vas[area]->va_start,-sizes[area]);}/* insert all vm's */
@@ -3800,6 +3797,11 @@ struct vm_struct **pcpu_get_vm_areas(const unsigned long *offsets,}spin_unlock(&vmap_area_lock);+/* mark allocated areas as accessible */+for(area=0;area<nr_vms;area++)+vms[area]->addr=kasan_unpoison_vmalloc(vms[area]->addr,+vms[area]->size);+kfree(vas);returnvms;
--
2.25.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: Andrey Konovalov <redacted>
HW_TAGS KASAN relies on ARM Memory Tagging Extension (MTE). With MTE,
a memory region must be mapped as MT_NORMAL_TAGGED to allow setting
memory tags via MTE-specific instructions.
Add proper protection bits to vmalloc() allocations. These allocations
are always backed by page_alloc pages, so the tags will actually be
getting set on the corresponding physical memory.
Signed-off-by: Andrey Konovalov <redacted>
Co-developed-by: Vincenzo Frascino <vincenzo.frascino@arm.com>
Signed-off-by: Vincenzo Frascino <vincenzo.frascino@arm.com>
---
Changes v2->v3:
- Update patch description.
---
arch/arm64/include/asm/vmalloc.h | 10 ++++++++++
include/linux/vmalloc.h | 7 +++++++
mm/vmalloc.c | 2 ++
3 files changed, 19 insertions(+)
@@ -3060,6 +3060,8 @@ void *__vmalloc_node_range(unsigned long size, unsigned long align,returnNULL;}+prot=arch_vmalloc_pgprot_modify(prot);+if(vmap_allow_huge&&!(vm_flags&VM_NO_HUGE_VMAP)){unsignedlongsize_per_node;
I wonder whether we could fix the prot bits in the caller instead and we
won't need to worry about the exec or the module_alloc() case. Something
like:
with pgprot_hwasan() defined to pgprot_tagged() only if KASAN_HW_TAGS is
enabled.
--
Catalin
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
@@ -3060,6 +3060,8 @@ void *__vmalloc_node_range(unsigned long size, unsigned long align,returnNULL;}+prot=arch_vmalloc_pgprot_modify(prot);+if(vmap_allow_huge&&!(vm_flags&VM_NO_HUGE_VMAP)){unsignedlongsize_per_node;
I wonder whether we could fix the prot bits in the caller instead and we
won't need to worry about the exec or the module_alloc() case. Something
like:
with pgprot_hwasan() defined to pgprot_tagged() only if KASAN_HW_TAGS is
enabled.
And also change kasan_unpoison_vmalloc() to tag only if
pgprot_tagged() has been applied, I assume.
Hm. Then __vmalloc_node_range() callers will never get tagged memory
unless requested. I suppose that's OK, most of them untag the pointer
anyway.
But this won't work for SW_TAGS mode, which is also affected by the
exec issue and needs those kasan_reset_tag()s in module_alloc()/BPF.
We could invent some virtual protection bit for it and reuse
pgprot_hwasan(). Not sure if this would be acceptable.
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
@@ -3060,6 +3060,8 @@ void *__vmalloc_node_range(unsigned long size, unsigned long align,returnNULL;}+prot=arch_vmalloc_pgprot_modify(prot);+if(vmap_allow_huge&&!(vm_flags&VM_NO_HUGE_VMAP)){unsignedlongsize_per_node;
I wonder whether we could fix the prot bits in the caller instead and we
won't need to worry about the exec or the module_alloc() case. Something
like:
with pgprot_hwasan() defined to pgprot_tagged() only if KASAN_HW_TAGS is
enabled.
And also change kasan_unpoison_vmalloc() to tag only if
pgprot_tagged() has been applied, I assume.
Hm. Then __vmalloc_node_range() callers will never get tagged memory
unless requested. I suppose that's OK, most of them untag the pointer
anyway.
But this won't work for SW_TAGS mode, which is also affected by the
exec issue and needs those kasan_reset_tag()s in module_alloc()/BPF.
We could invent some virtual protection bit for it and reuse
pgprot_hwasan(). Not sure if this would be acceptable.
Ah, a pgprot_hwasan() for the sw tags is probably not acceptable as this
requires an unnecessary pte bit. An alternative could be a GFP flag that
gets passed only from __vmalloc_node() etc.
Otherwise your original approach works as well.
--
Catalin
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
@@ -3060,6 +3060,8 @@ void *__vmalloc_node_range(unsigned long size, unsigned long align,returnNULL;}+prot=arch_vmalloc_pgprot_modify(prot);+if(vmap_allow_huge&&!(vm_flags&VM_NO_HUGE_VMAP)){unsignedlongsize_per_node;
I wonder whether we could fix the prot bits in the caller instead and we
won't need to worry about the exec or the module_alloc() case. Something
like:
with pgprot_hwasan() defined to pgprot_tagged() only if KASAN_HW_TAGS is
enabled.
And also change kasan_unpoison_vmalloc() to tag only if
pgprot_tagged() has been applied, I assume.
Hm. Then __vmalloc_node_range() callers will never get tagged memory
unless requested. I suppose that's OK, most of them untag the pointer
anyway.
But this won't work for SW_TAGS mode, which is also affected by the
exec issue and needs those kasan_reset_tag()s in module_alloc()/BPF.
We could invent some virtual protection bit for it and reuse
pgprot_hwasan(). Not sure if this would be acceptable.
Ah, a pgprot_hwasan() for the sw tags is probably not acceptable as this
requires an unnecessary pte bit. An alternative could be a GFP flag that
gets passed only from __vmalloc_node() etc.
This will still leave the BPF JIT special case though.
So I'm leaning towards keeping my approach.
Thanks!
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: Andrey Konovalov <redacted>
Make KASAN unpoison vmalloc mappings after that have been mapped in
when it's possible: for vmalloc() (indentified via VM_ALLOC) and
vm_map_ram().
The reasons for this are:
- For vmalloc() and vm_map_ram(): pages don't get unpoisoned in case
mapping them fails.
- For vmalloc(): HW_TAGS KASAN needs pages to be mapped to set tags via
kasan_unpoison_vmalloc().
Signed-off-by: Andrey Konovalov <redacted>
---
Changes v2->v3:
- Update patch description.
---
mm/vmalloc.c | 26 ++++++++++++++++++++++----
1 file changed, 22 insertions(+), 4 deletions(-)
@@ -2208,14 +2208,15 @@ void *vm_map_ram(struct page **pages, unsigned int count, int node)mem=(void*)addr;}-mem=kasan_unpoison_vmalloc(mem,size);-if(vmap_pages_range(addr,addr+size,PAGE_KERNEL,pages,PAGE_SHIFT)<0){vm_unmap_ram(mem,count);returnNULL;}+/* Mark the pages as accessible after they were mapped in. */+mem=kasan_unpoison_vmalloc(mem,size);+returnmem;}EXPORT_SYMBOL(vm_map_ram);
@@ -2443,7 +2444,14 @@ static struct vm_struct *__get_vm_area_node(unsigned long size,setup_vmalloc_vm(area,va,flags,caller);-area->addr=kasan_unpoison_vmalloc(area->addr,requested_size);+/*+*ForVM_ALLOCmappings,__vmalloc_node_range()markthepagesas+*accessibleaftertheyaremappedin.+*Otherwise,asthepagescanbemappedoutsideofvmalloccode,+*markthemnowasabest-effortapproach.+*/+if(!(flags&VM_ALLOC))+area->addr=kasan_unpoison_vmalloc(area->addr,requested_size);returnarea;}
@@ -3104,6 +3112,12 @@ void *__vmalloc_node_range(unsigned long size, unsigned long align,if(!addr)gotofail;+/*+*MarkthepagesforVM_ALLOCmappingsasaccessibleaftertheywere+*mappedin.+*/+addr=kasan_unpoison_vmalloc(addr,real_size);+/**Inthisfunction,newlyallocatedvm_structhasVM_UNINITIALIZED*flag.Itmeansthatvm_structisnotfullyinitialized.
@@ -3799,7 +3813,11 @@ struct vm_struct **pcpu_get_vm_areas(const unsigned long *offsets,}spin_unlock(&vmap_area_lock);-/* mark allocated areas as accessible */+/*+*Markallocatedareasasaccessible.+*Asthepagesaremappedoutsideofvmalloccode,+*markthemnowasabest-effortapproach.+*/for(area=0;area<nr_vms;area++)vms[area]->addr=kasan_unpoison_vmalloc(vms[area]->addr,vms[area]->size);
--
2.25.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: Alexander Potapenko <glider@google.com> Date: 2021-12-16 19:08:27
On Mon, Dec 13, 2021 at 10:54 PM [off-list ref] wrote:
From: Andrey Konovalov <redacted>
Make KASAN unpoison vmalloc mappings after that have been mapped in
when it's possible: for vmalloc() (indentified via VM_ALLOC) and
vm_map_ram().
The subject says "don't unpoison VM_ALLOC pages", whereas the
description says "unpoison VM_ALLOC pages", or am I missing something?
quoted hunk
The reasons for this are:
- For vmalloc() and vm_map_ram(): pages don't get unpoisoned in case
mapping them fails.
- For vmalloc(): HW_TAGS KASAN needs pages to be mapped to set tags via
kasan_unpoison_vmalloc().
Signed-off-by: Andrey Konovalov <redacted>
---
Changes v2->v3:
- Update patch description.
---
mm/vmalloc.c | 26 ++++++++++++++++++++++----
1 file changed, 22 insertions(+), 4 deletions(-)
@@ -2208,14 +2208,15 @@ void *vm_map_ram(struct page **pages, unsigned int count, int node)mem=(void*)addr;}-mem=kasan_unpoison_vmalloc(mem,size);-if(vmap_pages_range(addr,addr+size,PAGE_KERNEL,pages,PAGE_SHIFT)<0){vm_unmap_ram(mem,count);returnNULL;}+/* Mark the pages as accessible after they were mapped in. */+mem=kasan_unpoison_vmalloc(mem,size);+returnmem;}EXPORT_SYMBOL(vm_map_ram);
@@ -2443,7 +2444,14 @@ static struct vm_struct *__get_vm_area_node(unsigned long size,setup_vmalloc_vm(area,va,flags,caller);-area->addr=kasan_unpoison_vmalloc(area->addr,requested_size);+/*+*ForVM_ALLOCmappings,__vmalloc_node_range()markthepagesas+*accessibleaftertheyaremappedin.+*Otherwise,asthepagescanbemappedoutsideofvmalloccode,+*markthemnowasabest-effortapproach.+*/+if(!(flags&VM_ALLOC))+area->addr=kasan_unpoison_vmalloc(area->addr,requested_size);returnarea;}
@@ -3104,6 +3112,12 @@ void *__vmalloc_node_range(unsigned long size, unsigned long align,if(!addr)gotofail;+/*+*MarkthepagesforVM_ALLOCmappingsasaccessibleaftertheywere+*mappedin.+*/+addr=kasan_unpoison_vmalloc(addr,real_size);+/**Inthisfunction,newlyallocatedvm_structhasVM_UNINITIALIZED*flag.Itmeansthatvm_structisnotfullyinitialized.
@@ -3799,7 +3813,11 @@ struct vm_struct **pcpu_get_vm_areas(const unsigned long *offsets,}spin_unlock(&vmap_area_lock);-/* mark allocated areas as accessible */+/*+*Markallocatedareasasaccessible.+*Asthepagesaremappedoutsideofvmalloccode,+*markthemnowasabest-effortapproach.+*/for(area=0;area<nr_vms;area++)vms[area]->addr=kasan_unpoison_vmalloc(vms[area]->addr,vms[area]->size);--
--
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
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
On Thu, Dec 16, 2021 at 8:08 PM Alexander Potapenko [off-list ref] wrote:
On Mon, Dec 13, 2021 at 10:54 PM [off-list ref] wrote:
quoted
From: Andrey Konovalov <redacted>
Make KASAN unpoison vmalloc mappings after that have been mapped in
when it's possible: for vmalloc() (indentified via VM_ALLOC) and
vm_map_ram().
The subject says "don't unpoison VM_ALLOC pages", whereas the
description says "unpoison VM_ALLOC pages", or am I missing something?
Yes :) The title says "don't unpoison *before*", and the body says
"unpoison *after*".
I'll reword the changelog in v4 to make it less confusing.
Thanks!
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: Andrey Konovalov <redacted>
Add a new GFP flag __GFP_SKIP_KASAN_UNPOISON that allows skipping KASAN
poisoning for page_alloc allocations. The flag is only effective with
HW_TAGS KASAN.
This flag will be used by vmalloc code for page_alloc allocations
backing vmalloc() mappings in a following patch. The reason to skip
KASAN poisoning for these pages in page_alloc is because vmalloc code
will be poisoning them instead.
Also reword the comment for __GFP_SKIP_KASAN_POISON.
Signed-off-by: Andrey Konovalov <redacted>
---
Changes v2->v3:
- Update patch description.
---
include/linux/gfp.h | 18 +++++++++++-------
mm/page_alloc.c | 24 +++++++++++++++++-------
2 files changed, 28 insertions(+), 14 deletions(-)
@@ -2394,6 +2394,21 @@ static bool check_new_pages(struct page *page, unsigned int order)returnfalse;}+staticinlineboolshould_skip_kasan_unpoison(gfp_tflags,boolinit_tags)+{+/* Don't skip if a software KASAN mode is enabled. */+if(!IS_ENABLED(CONFIG_KASAN_HW_TAGS))+returnfalse;++/*+*Forhardwaretag-basedKASAN,skipifeither:+*+*1.Memorytagshavealreadybeenclearedviatag_clear_highpage().+*2.Skippinghasbeenrequestedvia__GFP_SKIP_KASAN_UNPOISON.+*/+returninit_tags||(flags&__GFP_SKIP_KASAN_UNPOISON);+}+inlinevoidpost_alloc_hook(structpage*page,unsignedintorder,gfp_tgfp_flags){
@@ -2433,13 +2448,8 @@ inline void post_alloc_hook(struct page *page, unsigned int order,/* Note that memory is already initialized by the loop above. */init=false;}-/*-*IfeitherasoftwareKASANmodeisenabled,or,-*inthecaseofhardwaretag-basedKASAN,-*ifmemorytagshavenotbeenclearedviatag_clear_highpage().-*/-if(!IS_ENABLED(CONFIG_KASAN_HW_TAGS)||!init_tags){-/* Mark shadow memory or set memory tags. */+if(!should_skip_kasan_unpoison(gfp_flags,init_tags)){+/* Unpoison shadow memory or set memory tags. */kasan_unpoison_pages(page,order,init);/* Note that memory is already initialized by KASAN. */
--
2.25.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: Andrey Konovalov <redacted>
Add a new GFP flag __GFP_SKIP_ZERO that allows to skip memory
initialization. The flag is only effective with HW_TAGS KASAN.
This flag will be used by vmalloc code for page_alloc allocations
backing vmalloc() mappings in a following patch. The reason to skip
memory initialization for these pages in page_alloc is because vmalloc
code will be initializing them instead.
With the current implementation, when __GFP_SKIP_ZERO is provided,
__GFP_ZEROTAGS is ignored. This doesn't matter, as these two flags are
never provided at the same time. However, if this is changed in the
future, this particular implementation detail can be changed as well.
Signed-off-by: Andrey Konovalov <redacted>
---
Changes v2->v3:
- Update patch description.
Changes v1->v2:
- Add this patch.
---
include/linux/gfp.h | 16 +++++++++++-----
mm/page_alloc.c | 13 ++++++++++++-
2 files changed, 23 insertions(+), 6 deletions(-)
From: Marco Elver <elver@google.com> Date: 2021-12-14 18:00:46
On Mon, Dec 13, 2021 at 10:54PM +0100, andrey.konovalov@linux.dev wrote:
From: Andrey Konovalov <redacted>
Add a new GFP flag __GFP_SKIP_ZERO that allows to skip memory
initialization. The flag is only effective with HW_TAGS KASAN.
[...]
quoted hunk
- * is being zeroed (either via __GFP_ZERO or via init_on_alloc).
+ * is being zeroed (either via __GFP_ZERO or via init_on_alloc, provided that
+ * __GFP_SKIP_ZERO is not set).
+ *
+ * %__GFP_SKIP_ZERO makes page_alloc skip zeroing memory.
+ * Only effective when HW_TAGS KASAN is enabled.
*
* %__GFP_SKIP_KASAN_UNPOISON makes KASAN skip unpoisoning on page allocation.
* Only effective in HW_TAGS mode.
You're adding several new flags, I think you should also make a
corresponding change to include/trace/events/mmflags.h?
At least __GFP_SKIP_KASAN_POISON is currently in there.
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
On Tue, Dec 14, 2021 at 7:00 PM Marco Elver [off-list ref] wrote:
On Mon, Dec 13, 2021 at 10:54PM +0100, andrey.konovalov@linux.dev wrote:
quoted
From: Andrey Konovalov <redacted>
Add a new GFP flag __GFP_SKIP_ZERO that allows to skip memory
initialization. The flag is only effective with HW_TAGS KASAN.
[...]
quoted
- * is being zeroed (either via __GFP_ZERO or via init_on_alloc).
+ * is being zeroed (either via __GFP_ZERO or via init_on_alloc, provided that
+ * __GFP_SKIP_ZERO is not set).
+ *
+ * %__GFP_SKIP_ZERO makes page_alloc skip zeroing memory.
+ * Only effective when HW_TAGS KASAN is enabled.
*
* %__GFP_SKIP_KASAN_UNPOISON makes KASAN skip unpoisoning on page allocation.
* Only effective in HW_TAGS mode.
You're adding several new flags, I think you should also make a
corresponding change to include/trace/events/mmflags.h?
At least __GFP_SKIP_KASAN_POISON is currently in there.
From: Kuan-Ying Lee <hidden> Date: 2021-12-17 01:50:28
On Tue, 2021-12-14 at 05:54 +0800, andrey.konovalov@linux.dev wrote:
quoted hunk
From: Andrey Konovalov <redacted>
Add a new GFP flag __GFP_SKIP_ZERO that allows to skip memory
initialization. The flag is only effective with HW_TAGS KASAN.
This flag will be used by vmalloc code for page_alloc allocations
backing vmalloc() mappings in a following patch. The reason to skip
memory initialization for these pages in page_alloc is because
vmalloc
code will be initializing them instead.
With the current implementation, when __GFP_SKIP_ZERO is provided,
__GFP_ZEROTAGS is ignored. This doesn't matter, as these two flags
are
never provided at the same time. However, if this is changed in the
future, this particular implementation detail can be changed as well.
Signed-off-by: Andrey Konovalov <redacted>
---
Changes v2->v3:
- Update patch description.
Changes v1->v2:
- Add this patch.
---
include/linux/gfp.h | 16 +++++++++++-----
mm/page_alloc.c | 13 ++++++++++++-
2 files changed, 23 insertions(+), 6 deletions(-)
memory itself
- * is being zeroed (either via __GFP_ZERO or via init_on_alloc).
+ * is being zeroed (either via __GFP_ZERO or via init_on_alloc,
provided that
+ * __GFP_SKIP_ZERO is not set).
+ *
+ * %__GFP_SKIP_ZERO makes page_alloc skip zeroing memory.
+ * Only effective when HW_TAGS KASAN is enabled.
*
* %__GFP_SKIP_KASAN_UNPOISON makes KASAN skip unpoisoning on page
allocation.
* Only effective in HW_TAGS mode.
should_skip_kasan_unpoison(gfp_t flags, bool init_tags)
return init_tags || (flags & __GFP_SKIP_KASAN_UNPOISON);
}
+static inline bool should_skip_init(gfp_t flags)
+{
+ /* Don't skip if a software KASAN mode is enabled. */
+ if (!IS_ENABLED(CONFIG_KASAN_HW_TAGS))
+ return false;
+
Hi Andrey,
Should we use kasan_hw_tags_enabled() in should_skip_init() function
instead of checking the config?
I think we should handle the condition which is CONFIG_KASAN_HW_TAGS=y
and command line="kasan=off".
On Fri, Dec 17, 2021 at 2:50 AM Kuan-Ying Lee
[off-list ref] wrote:
On Tue, 2021-12-14 at 05:54 +0800, andrey.konovalov@linux.dev wrote:
quoted
From: Andrey Konovalov <redacted>
Add a new GFP flag __GFP_SKIP_ZERO that allows to skip memory
initialization. The flag is only effective with HW_TAGS KASAN.
This flag will be used by vmalloc code for page_alloc allocations
backing vmalloc() mappings in a following patch. The reason to skip
memory initialization for these pages in page_alloc is because
vmalloc
code will be initializing them instead.
With the current implementation, when __GFP_SKIP_ZERO is provided,
__GFP_ZEROTAGS is ignored. This doesn't matter, as these two flags
are
never provided at the same time. However, if this is changed in the
future, this particular implementation detail can be changed as well.
Signed-off-by: Andrey Konovalov <redacted>
---
Changes v2->v3:
- Update patch description.
Changes v1->v2:
- Add this patch.
---
include/linux/gfp.h | 16 +++++++++++-----
mm/page_alloc.c | 13 ++++++++++++-
2 files changed, 23 insertions(+), 6 deletions(-)
memory itself
- * is being zeroed (either via __GFP_ZERO or via init_on_alloc).
+ * is being zeroed (either via __GFP_ZERO or via init_on_alloc,
provided that
+ * __GFP_SKIP_ZERO is not set).
+ *
+ * %__GFP_SKIP_ZERO makes page_alloc skip zeroing memory.
+ * Only effective when HW_TAGS KASAN is enabled.
*
* %__GFP_SKIP_KASAN_UNPOISON makes KASAN skip unpoisoning on page
allocation.
* Only effective in HW_TAGS mode.
should_skip_kasan_unpoison(gfp_t flags, bool init_tags)
return init_tags || (flags & __GFP_SKIP_KASAN_UNPOISON);
}
+static inline bool should_skip_init(gfp_t flags)
+{
+ /* Don't skip if a software KASAN mode is enabled. */
+ if (!IS_ENABLED(CONFIG_KASAN_HW_TAGS))
+ return false;
+
Hi Andrey,
Should we use kasan_hw_tags_enabled() in should_skip_init() function
instead of checking the config?
I think we should handle the condition which is CONFIG_KASAN_HW_TAGS=y
and command line="kasan=off".
From: Andrey Konovalov <redacted>
Add vmalloc tagging support to HW_TAGS KASAN.
The key difference between HW_TAGS and the other two KASAN modes
when it comes to vmalloc: HW_TAGS KASAN can only assign tags to
physical memory. The other two modes have shadow memory covering
every mapped virtual memory region.
Make __kasan_unpoison_vmalloc() for HW_TAGS KASAN:
- Skip non-VM_ALLOC mappings as HW_TAGS KASAN can only tag a single
mapping of normal physical memory; see the comment in the function.
- Generate a random tag, tag the returned pointer and the allocation,
and initialize the allocation at the same time.
- Propagate the tag into the page stucts to allow accesses through
page_address(vmalloc_to_page()).
The rest of vmalloc-related KASAN hooks are not needed:
- The shadow-related ones are fully skipped.
- __kasan_poison_vmalloc() is kept as a no-op with a comment.
Poisoning and zeroing of physical pages that are backing vmalloc()
allocations are skipped via __GFP_SKIP_KASAN_UNPOISON and
__GFP_SKIP_ZERO: __kasan_unpoison_vmalloc() does that instead.
Enabling CONFIG_KASAN_VMALLOC with HW_TAGS is not yet allowed.
Signed-off-by: Andrey Konovalov <redacted>
Co-developed-by: Vincenzo Frascino <vincenzo.frascino@arm.com>
Signed-off-by: Vincenzo Frascino <vincenzo.frascino@arm.com>
---
Changes v2->v3:
- Switch kasan_unpoison_vmalloc() to using a single flags argument.
- Update kasan_unpoison_vmalloc() arguments in kernel/scs.c.
- Move allowing enabling KASAN_VMALLOC with SW_TAGS into a separate
patch.
- Minor comments fixes.
- Update patch description.
Changes v1->v2:
- Allow enabling CONFIG_KASAN_VMALLOC with HW_TAGS in this patch.
- Move memory init for page_alloc pages backing vmalloc() into
kasan_unpoison_vmalloc().
---
include/linux/kasan.h | 36 +++++++++++++++--
kernel/scs.c | 4 +-
mm/kasan/hw_tags.c | 91 +++++++++++++++++++++++++++++++++++++++++++
mm/kasan/shadow.c | 10 ++++-
mm/vmalloc.c | 34 +++++++++++++---
5 files changed, 163 insertions(+), 12 deletions(-)
@@ -192,6 +192,97 @@ void __init kasan_init_hw_tags(void)kasan_stack_collection_enabled()?"on":"off");}+#ifdef CONFIG_KASAN_VMALLOC++staticvoidunpoison_vmalloc_pages(constvoid*addr,u8tag)+{+structvm_struct*area;+inti;++/*+*Ashardwaretag-basedKASANonlytagsVM_ALLOCvmallocallocations+*(seethecommentin__kasan_unpoison_vmalloc),allofthepages+*shouldbelongtoasinglearea.+*/+area=find_vm_area((void*)addr);+if(WARN_ON(!area))+return;++for(i=0;i<area->nr_pages;i++){+structpage*page=area->pages[i];++page_kasan_tag_set(page,tag);+}+}++void*__kasan_unpoison_vmalloc(constvoid*start,unsignedlongsize,+kasan_vmalloc_flags_tflags)+{+u8tag;+unsignedlongredzone_start,redzone_size;++if(!is_vmalloc_or_module_addr(start))+return(void*)start;++/* Skip unpoisoning and assigning a pointer tag for non-VM_ALLOC+*mappingsas:+*+*1.UnlikethesoftwareKASANmodes,hardwaretag-basedKASANonly+*supportstaggingphysicalmemory.Therefore,itcanonlytaga+*singlemappingofnormalphysicalpages.+*2.Hardwaretag-basedKASANcanonlytagmemorymappedwithspecial+*mappingprotectionbits,seearch_vmalloc_pgprot_modify().+*Asnon-VM_ALLOCmappingscanbemappedoutsideofvmalloccode,+*providingthesebitswouldrequiretrackingallnon-VM_ALLOC+*mappers.+*+*Thus,forVM_ALLOCmappings,hardwaretag-basedKASANonlytags+*thefirstvirtualmapping,whichiscreatedbyvmalloc().+*Taggingthepage_allocmemorybackingthatvmalloc()allocationis+*skipped,see___GFP_SKIP_KASAN_UNPOISON.+*+*Fornon-VM_ALLOCallocations,page_allocmemoryistaggedasusual.+*/+if(!(flags&KASAN_VMALLOC_VM_ALLOC))+return(void*)start;++tag=kasan_random_tag();+start=set_tag(start,tag);++/* Unpoison and initialize memory up to size. */+kasan_unpoison(start,size,flags&KASAN_VMALLOC_INIT);++/*+*Explicitlypoisonandinitializethein-pagevmalloc()redzone.+*UnlikesoftwareKASANmodes,hardwaretag-basedKASANdoesn't+*unpoisonmemorywhenpopulatingshadowforvmalloc()space.+*/+redzone_start=round_up((unsignedlong)start+size,+KASAN_GRANULE_SIZE);+redzone_size=round_up(redzone_start,PAGE_SIZE)-redzone_start;+kasan_poison((void*)redzone_start,redzone_size,KASAN_TAG_INVALID,+flags&KASAN_VMALLOC_INIT);++/*+*Setper-pagetagflagstoallowaccessingphysicalmemoryforthe+*vmalloc()mappingthroughpage_address(vmalloc_to_page()).+*/+unpoison_vmalloc_pages(start,tag);++return(void*)start;+}++void__kasan_poison_vmalloc(constvoid*start,unsignedlongsize)+{+/*+*Notagginghere.+*Thephysicalpagesbackingthevmalloc()allocationarepoisoned+*throughtheusualpage_allocpaths.+*/+}++#endif+#if IS_ENABLED(CONFIG_KASAN_KUNIT_TEST)voidkasan_enable_tagging_sync(void)
@@ -2214,8 +2214,12 @@ void *vm_map_ram(struct page **pages, unsigned int count, int node)returnNULL;}-/* Mark the pages as accessible after they were mapped in. */-mem=kasan_unpoison_vmalloc(mem,size);+/*+*Markthepagesasaccessibleaftertheyweremappedin.+*Withhardwaretag-basedKASAN,markingisskippedfor+*non-VM_ALLOCmappings,see__kasan_unpoison_vmalloc().+*/+mem=kasan_unpoison_vmalloc(mem,size,KASAN_VMALLOC_NONE);returnmem;}
@@ -2449,9 +2453,12 @@ static struct vm_struct *__get_vm_area_node(unsigned long size,*accessibleaftertheyaremappedin.*Otherwise,asthepagescanbemappedoutsideofvmalloccode,*markthemnowasabest-effortapproach.+*Withhardwaretag-basedKASAN,markingisskippedfor+*non-VM_ALLOCmappings,see__kasan_unpoison_vmalloc().*/if(!(flags&VM_ALLOC))-area->addr=kasan_unpoison_vmalloc(area->addr,requested_size);+area->addr=kasan_unpoison_vmalloc(area->addr,requested_size,+KASAN_VMALLOC_NONE);returnarea;}
@@ -2849,6 +2856,12 @@ vm_area_alloc_pages(gfp_t gfp, int nid,structpage*page;inti;+/*+*Skippage_allocpoisoningandzeroingforpagesbackingVM_ALLOC+*mappings.OnlyeffectiveinHW_TAGSmode.+*/+gfp&=__GFP_SKIP_KASAN_UNPOISON&__GFP_SKIP_ZERO;+/**Fororder-0pageswemakeuseofbulkallocator,if*thepagearrayispartlyornotatallpopulateddue
@@ -3054,6 +3067,7 @@ void *__vmalloc_node_range(unsigned long size, unsigned long align,{structvm_struct*area;void*addr;+kasan_vmalloc_flags_tkasan_flags;unsignedlongreal_size=size;unsignedlongreal_align=align;unsignedintshift=PAGE_SHIFT;
@@ -3115,8 +3129,15 @@ void *__vmalloc_node_range(unsigned long size, unsigned long align,/**MarkthepagesforVM_ALLOCmappingsasaccessibleaftertheywere*mappedin.+*Theinitconditionshouldmatchtheoneinpost_alloc_hook()+*(exceptfortheshould_skip_init()check)tomakesurethatmemory+*isinitializedunderthesameconditionsregardlessoftheenabled+*KASANmode.*/-addr=kasan_unpoison_vmalloc(addr,real_size);+kasan_flags=KASAN_VMALLOC_VM_ALLOC;+if(!want_init_on_free()&&want_init_on_alloc(gfp_mask))+kasan_flags|=KASAN_VMALLOC_INIT;+addr=kasan_unpoison_vmalloc(addr,real_size,kasan_flags);/**Inthisfunction,newlyallocatedvm_structhasVM_UNINITIALIZED
@@ -3817,10 +3838,13 @@ struct vm_struct **pcpu_get_vm_areas(const unsigned long *offsets,*Markallocatedareasasaccessible.*Asthepagesaremappedoutsideofvmalloccode,*markthemnowasabest-effortapproach.+*Withhardwaretag-basedKASAN,markingisskippedfor+*non-VM_ALLOCmappings,see__kasan_unpoison_vmalloc().*/for(area=0;area<nr_vms;area++)vms[area]->addr=kasan_unpoison_vmalloc(vms[area]->addr,-vms[area]->size);+vms[area]->size,+KASAN_VMALLOC_NONE);kfree(vas);returnvms;
--
2.25.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: Marco Elver <elver@google.com> Date: 2021-12-14 19:56:12
On Mon, Dec 13, 2021 at 10:54PM +0100, andrey.konovalov@linux.dev wrote:
[...]
+ /*
+ * Skip page_alloc poisoning and zeroing for pages backing VM_ALLOC
+ * mappings. Only effective in HW_TAGS mode.
+ */
+ gfp &= __GFP_SKIP_KASAN_UNPOISON & __GFP_SKIP_ZERO;
This will turn gfp == 0 always. Should it have been
gfp |= __GFP_SKIP_KASAN_UNPOISON | __GFP_SKIP_ZERO
Also, not sure it matters, but on non-KASAN builds, this will now always
generate an extra instruction. You could conditionally define GFP_SKIP*
only in the KASAN modes that need them, otherwise they become 0, so the
compiler optimizes this out. (Although I think it does does complicate
GFP_SHIFT a little?)
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel