forked from mirrors/linux
		
	kasan, page_alloc: allow skipping unpoisoning for HW_TAGS
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. Link: https://lkml.kernel.org/r/35c97d77a704f6ff971dd3bfe4be95855744108e.1643047180.git.andreyknvl@google.com Signed-off-by: Andrey Konovalov <andreyknvl@google.com> Acked-by: Marco Elver <elver@google.com> Cc: Alexander Potapenko <glider@google.com> Cc: Andrey Ryabinin <ryabinin.a.a@gmail.com> Cc: Catalin Marinas <catalin.marinas@arm.com> Cc: Dmitry Vyukov <dvyukov@google.com> Cc: Evgenii Stepanov <eugenis@google.com> Cc: Mark Rutland <mark.rutland@arm.com> Cc: Peter Collingbourne <pcc@google.com> Cc: Vincenzo Frascino <vincenzo.frascino@arm.com> Cc: Will Deacon <will@kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
		
							parent
							
								
									f49d9c5bb1
								
							
						
					
					
						commit
						53ae233c30
					
				
					 3 changed files with 38 additions and 19 deletions
				
			
		|  | @ -55,12 +55,14 @@ struct vm_area_struct; | ||||||
| #define ___GFP_ACCOUNT		0x400000u | #define ___GFP_ACCOUNT		0x400000u | ||||||
| #define ___GFP_ZEROTAGS		0x800000u | #define ___GFP_ZEROTAGS		0x800000u | ||||||
| #ifdef CONFIG_KASAN_HW_TAGS | #ifdef CONFIG_KASAN_HW_TAGS | ||||||
| #define ___GFP_SKIP_KASAN_POISON	0x1000000u | #define ___GFP_SKIP_KASAN_UNPOISON	0x1000000u | ||||||
|  | #define ___GFP_SKIP_KASAN_POISON	0x2000000u | ||||||
| #else | #else | ||||||
|  | #define ___GFP_SKIP_KASAN_UNPOISON	0 | ||||||
| #define ___GFP_SKIP_KASAN_POISON	0 | #define ___GFP_SKIP_KASAN_POISON	0 | ||||||
| #endif | #endif | ||||||
| #ifdef CONFIG_LOCKDEP | #ifdef CONFIG_LOCKDEP | ||||||
| #define ___GFP_NOLOCKDEP	0x2000000u | #define ___GFP_NOLOCKDEP	0x4000000u | ||||||
| #else | #else | ||||||
| #define ___GFP_NOLOCKDEP	0 | #define ___GFP_NOLOCKDEP	0 | ||||||
| #endif | #endif | ||||||
|  | @ -241,22 +243,25 @@ struct vm_area_struct; | ||||||
|  * intended for optimization: setting memory tags at the same time as zeroing |  * intended for optimization: setting memory tags at the same time as zeroing | ||||||
|  * memory has minimal additional performace impact. |  * memory has minimal additional performace impact. | ||||||
|  * |  * | ||||||
|  * %__GFP_SKIP_KASAN_POISON returns a page which does not need to be poisoned |  * %__GFP_SKIP_KASAN_UNPOISON makes KASAN skip unpoisoning on page allocation. | ||||||
|  * on deallocation. Typically used for userspace pages. Currently only has an |  * Only effective in HW_TAGS mode. | ||||||
|  * effect in HW tags mode. |  * | ||||||
|  |  * %__GFP_SKIP_KASAN_POISON makes KASAN skip poisoning on page deallocation. | ||||||
|  |  * Typically, used for userspace pages. Only effective in HW_TAGS mode. | ||||||
|  */ |  */ | ||||||
| #define __GFP_NOWARN	((__force gfp_t)___GFP_NOWARN) | #define __GFP_NOWARN	((__force gfp_t)___GFP_NOWARN) | ||||||
| #define __GFP_COMP	((__force gfp_t)___GFP_COMP) | #define __GFP_COMP	((__force gfp_t)___GFP_COMP) | ||||||
| #define __GFP_ZERO	((__force gfp_t)___GFP_ZERO) | #define __GFP_ZERO	((__force gfp_t)___GFP_ZERO) | ||||||
| #define __GFP_ZEROTAGS	((__force gfp_t)___GFP_ZEROTAGS) | #define __GFP_ZEROTAGS	((__force gfp_t)___GFP_ZEROTAGS) | ||||||
| #define __GFP_SKIP_KASAN_POISON	((__force gfp_t)___GFP_SKIP_KASAN_POISON) | #define __GFP_SKIP_KASAN_UNPOISON ((__force gfp_t)___GFP_SKIP_KASAN_UNPOISON) | ||||||
|  | #define __GFP_SKIP_KASAN_POISON   ((__force gfp_t)___GFP_SKIP_KASAN_POISON) | ||||||
| 
 | 
 | ||||||
| /* Disable lockdep for GFP context tracking */ | /* Disable lockdep for GFP context tracking */ | ||||||
| #define __GFP_NOLOCKDEP ((__force gfp_t)___GFP_NOLOCKDEP) | #define __GFP_NOLOCKDEP ((__force gfp_t)___GFP_NOLOCKDEP) | ||||||
| 
 | 
 | ||||||
| /* Room for N __GFP_FOO bits */ | /* Room for N __GFP_FOO bits */ | ||||||
| #define __GFP_BITS_SHIFT (24 +					\ | #define __GFP_BITS_SHIFT (24 +						\ | ||||||
| 			  IS_ENABLED(CONFIG_KASAN_HW_TAGS) +	\ | 			  2 * IS_ENABLED(CONFIG_KASAN_HW_TAGS) +	\ | ||||||
| 			  IS_ENABLED(CONFIG_LOCKDEP)) | 			  IS_ENABLED(CONFIG_LOCKDEP)) | ||||||
| #define __GFP_BITS_MASK ((__force gfp_t)((1 << __GFP_BITS_SHIFT) - 1)) | #define __GFP_BITS_MASK ((__force gfp_t)((1 << __GFP_BITS_SHIFT) - 1)) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -52,8 +52,9 @@ | ||||||
| 	{(unsigned long)__GFP_ZEROTAGS,		"__GFP_ZEROTAGS"}	\ | 	{(unsigned long)__GFP_ZEROTAGS,		"__GFP_ZEROTAGS"}	\ | ||||||
| 
 | 
 | ||||||
| #ifdef CONFIG_KASAN_HW_TAGS | #ifdef CONFIG_KASAN_HW_TAGS | ||||||
| #define __def_gfpflag_names_kasan					      \ | #define __def_gfpflag_names_kasan ,					       \ | ||||||
| 	, {(unsigned long)__GFP_SKIP_KASAN_POISON, "__GFP_SKIP_KASAN_POISON"} | 	{(unsigned long)__GFP_SKIP_KASAN_POISON,   "__GFP_SKIP_KASAN_POISON"}, \ | ||||||
|  | 	{(unsigned long)__GFP_SKIP_KASAN_UNPOISON, "__GFP_SKIP_KASAN_UNPOISON"} | ||||||
| #else | #else | ||||||
| #define __def_gfpflag_names_kasan | #define __def_gfpflag_names_kasan | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | @ -2343,6 +2343,26 @@ static inline bool check_new_pcp(struct page *page, unsigned int order) | ||||||
| } | } | ||||||
| #endif /* CONFIG_DEBUG_VM */ | #endif /* CONFIG_DEBUG_VM */ | ||||||
| 
 | 
 | ||||||
|  | static inline bool should_skip_kasan_unpoison(gfp_t flags, bool init_tags) | ||||||
|  | { | ||||||
|  | 	/* Don't skip if a software KASAN mode is enabled. */ | ||||||
|  | 	if (IS_ENABLED(CONFIG_KASAN_GENERIC) || | ||||||
|  | 	    IS_ENABLED(CONFIG_KASAN_SW_TAGS)) | ||||||
|  | 		return false; | ||||||
|  | 
 | ||||||
|  | 	/* Skip, if hardware tag-based KASAN is not enabled. */ | ||||||
|  | 	if (!kasan_hw_tags_enabled()) | ||||||
|  | 		return true; | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * With hardware tag-based KASAN enabled, skip if either: | ||||||
|  | 	 * | ||||||
|  | 	 * 1. Memory tags have already been cleared via tag_clear_highpage(). | ||||||
|  | 	 * 2. Skipping has been requested via __GFP_SKIP_KASAN_UNPOISON. | ||||||
|  | 	 */ | ||||||
|  | 	return init_tags || (flags & __GFP_SKIP_KASAN_UNPOISON); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| inline void post_alloc_hook(struct page *page, unsigned int order, | inline void post_alloc_hook(struct page *page, unsigned int order, | ||||||
| 				gfp_t gfp_flags) | 				gfp_t gfp_flags) | ||||||
| { | { | ||||||
|  | @ -2382,15 +2402,8 @@ inline void post_alloc_hook(struct page *page, unsigned int order, | ||||||
| 		/* Note that memory is already initialized by the loop above. */ | 		/* Note that memory is already initialized by the loop above. */ | ||||||
| 		init = false; | 		init = false; | ||||||
| 	} | 	} | ||||||
| 	/*
 | 	if (!should_skip_kasan_unpoison(gfp_flags, init_tags)) { | ||||||
| 	 * If either a software KASAN mode is enabled, or, | 		/* Unpoison shadow memory or set memory tags. */ | ||||||
| 	 * in the case of hardware tag-based KASAN, |  | ||||||
| 	 * if memory tags have not been cleared via tag_clear_highpage(). |  | ||||||
| 	 */ |  | ||||||
| 	if (IS_ENABLED(CONFIG_KASAN_GENERIC) || |  | ||||||
| 	    IS_ENABLED(CONFIG_KASAN_SW_TAGS) || |  | ||||||
| 	    kasan_hw_tags_enabled() && !init_tags) { |  | ||||||
| 		/* Mark shadow memory or set memory tags. */ |  | ||||||
| 		kasan_unpoison_pages(page, order, init); | 		kasan_unpoison_pages(page, order, init); | ||||||
| 
 | 
 | ||||||
| 		/* Note that memory is already initialized by KASAN. */ | 		/* Note that memory is already initialized by KASAN. */ | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Andrey Konovalov
						Andrey Konovalov