kasan: split kasan_*enabled() functions into a separate header
Subsystems (3)
PATCH v5 1/2 kasan: split kasan_*enabled() functions into a separate header
In an upcoming commit we are going to need to call kasan_hw_tags_enabled() from arch/arm64/include/asm/mte.h. This would create a circular dependency between headers if KASAN_GENERIC or KASAN_SW_TAGS is enabled: linux/kasan.h -> linux/pgtable.h -> asm/pgtable.h -> asm/mte.h -> linux/kasan.h. Break the cycle by introducing a new header linux/kasan-enabled.h with the kasan_*enabled() functions that can be included from asm/mte.h.
--- include/linux/kasan-enabled.h | 33 +++++++++++++++++++++++++++++++++ include/linux/kasan.h | 23 +---------------------- 2 files changed, 34 insertions(+), 22 deletions(-) create mode 100644 include/linux/kasan-enabled.h
include/linux/kasan-enabled.h new file +33 -0
@@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _LINUX_KASAN_ENABLED_H +#define _LINUX_KASAN_ENABLED_H + +#ifdef CONFIG_KASAN_HW_TAGS + +DECLARE_STATIC_KEY_FALSE (kasan_flag_enabled); + +static __always_inline bool kasan_enabled(void) +{ +return static_branch_likely (&kasan_flag_enabled); +} + +static inline bool kasan_hw_tags_enabled (void ) +{ +return kasan_enabled (); +} + +#else /* CONFIG_KASAN_HW_TAGS */ + +static inline bool kasan_enabled (void ) +{ +return IS_ENABLED (CONFIG_KASAN ); +} + +static inline bool kasan_hw_tags_enabled (void ) +{ +return false; +} + +#endif /* CONFIG_KASAN_HW_TAGS */ + +#endif /* LINUX_KASAN_ENABLED_H */
include/linux/kasan.h +1 -22
@@ -3,6 +3,7 @@#define _LINUX_KASAN_H#include <linux/bug.h> +#include <linux/kasan-enabled.h> #include <linux/kernel.h> #include <linux/static_key.h> #include <linux/types.h>
@@ -83,33 +84,11 @@ static inline void kasan_disable_current(void) {}#ifdef CONFIG_KASAN_HW_TAGS -DECLARE_STATIC_KEY_FALSE (kasan_flag_enabled); - -static __always_inline bool kasan_enabled(void) -{ -return static_branch_likely (&kasan_flag_enabled); -} - -static inline bool kasan_hw_tags_enabled (void ) -{ -return kasan_enabled (); -} -void kasan_alloc_pages (struct page *page,unsigned int order,gfp_t flags);void kasan_free_pages (struct page *page,unsigned int order);#else /* CONFIG_KASAN_HW_TAGS */ -static inline bool kasan_enabled (void ) -{ -return IS_ENABLED (CONFIG_KASAN ); -} - -static inline bool kasan_hw_tags_enabled (void ) -{ -return false; -} - static __always_inline void kasan_alloc_pages(struct page *page,unsigned int order,gfp_t flags) {
Signature · 1 line
2.35.1.473.g83b2b277ed-goog
PATCH v5 2/2 arm64: mte: avoid clearing PSTATE.TCO on entry unless necessary
On some microarchitectures, clearing PSTATE.TCO is expensive. Clearing TCO is only necessary if in-kernel MTE is enabled, or if MTE is enabled in the userspace process in synchronous (or, soon, asymmetric) mode, because we do not report uaccess faults to userspace in none or asynchronous modes. Therefore, adjust the kernel entry code to clear TCO only if necessary.
Because it is now possible to switch to a task in which TCO needs to be clear from a task in which TCO is set, we also need to do the same thing on task switch.
---
v5:
- fix header circular dependency with KASAN_GENERIC/KASAN_SW_TAGS enabled with a dependent patch
v4:
- some changes suggested by Catalin
v3:
- switch to a C implementation
v2:
- do the same thing in cpu_switch_to()
arch/arm64/include/asm/mte.h | 22 ++++++++++++++++++++++ arch/arm64/kernel/entry-common.c | 3 +++ arch/arm64/kernel/entry.S | 7 ------- arch/arm64/kernel/mte.c | 3 +++ 4 files changed, 28 insertions(+), 7 deletions(-)
arch/arm64/include/asm/mte.h +22 -0
@@ -11,7 +11,9 @@#ifndef __ASSEMBLY__#include <linux/bitfield.h> +#include <linux/kasan-enabled.h> #include <linux/page-flags.h> +#include <linux/sched.h> #include <linux/types.h> #include <asm/pgtable-types.h>
@@ -86,6 +88,26 @@ static inline int mte_ptrace_copy_tags(struct task_struct *child,#endif /* CONFIG_ARM64_MTE */ +static inline void mte_disable_tco_entry (struct task_struct *task) +{ +if (!system_supports_mte ()) +return ; + +/* +* Re-enable tag checking (TCO set on exception entry). This is only +* necessary if MTE is enabled in either the kernel or the userspace +* task in synchronous or asymmetric mode (SCTLR_EL1.TCF0 bit 0 is set +* for both). With MTE disabled in the kernel and disabled or +* asynchronous in userspace, tag check faults (including in uaccesses) +* are not reported, therefore there is no need to re-enable checking. +* This is beneficial on microarchitectures where re-enabling TCO is +* expensive. +*/ +if (kasan_hw_tags_enabled () || + (task->thread.sctlr_user & (1UL <<SCTLR_EL1_TCF0_SHIFT ))) + asm volatile(SET_PSTATE_TCO(0)); +} +#ifdef CONFIG_KASAN_HW_TAGS /* Whether the MTE asynchronous mode is enabled. */ DECLARE_STATIC_KEY_FALSE (mte_async_or_asymm_mode);
arch/arm64/kernel/entry-common.c +3 -0
@@ -6,6 +6,7 @@*/ #include <linux/context_tracking.h> +#include <linux/kasan.h> #include <linux/linkage.h> #include <linux/lockdep.h> #include <linux/ptrace.h>
@@ -56,6 +57,7 @@ static void noinstr enter_from_kernel_mode(struct pt_regs *regs) {__enter_from_kernel_mode (regs);mte_check_tfsr_entry (); +mte_disable_tco_entry (current); }/*
@@ -103,6 +105,7 @@ static __always_inline void __enter_from_user_mode(void)CT_WARN_ON (ct_state () !=CONTEXT_USER );user_exit_irqoff ();trace_hardirqs_off_finish (); +mte_disable_tco_entry (current); } static __always_inline void enter_from_user_mode(struct pt_regs *regs)
arch/arm64/kernel/entry.S +0 -7
@@ -308,13 +308,6 @@ alternative_if ARM64_HAS_IRQ_PRIO_MASKING msr_s SYS_ICC_PMR_EL1, x20 alternative_else_nop_endif - /* Re-enable tag checking (TCO set on exception entry) */ -#ifdef CONFIG_ARM64_MTE -alternative_if ARM64_MTE - SET_PSTATE_TCO(0) -alternative_else_nop_endif -#endif - /* * Registers that may be useful after this macro is invoked: *
arch/arm64/kernel/mte.c +3 -0
@@ -253,6 +253,9 @@ void mte_thread_switch(struct task_struct *next)mte_update_sctlr_user (next);mte_update_gcr_excl (next); +/* TCO may not have been disabled on exception entry for the current task. */ +mte_disable_tco_entry (next); +/* * Check if an async tag exception occurred at EL1. *
Signature · 1 line
2.35.1.473.g83b2b277ed-goog
Quoted 103 lines · Peter Collingbourne
In an upcoming commit we are going to need to call
kasan_hw_tags_enabled()fromarch/arm64/include/asm/mte.h. This would create a circular dependency between headers ifKASAN_GENERICorKASAN_SW_TAGSis enabled:linux/kasan.h->linux/pgtable.h->asm/pgtable.h->asm/mte.h->linux/kasan.h. Break the cycle by introducing a new headerlinux/kasan-enabled.hwith the kasan_*enabled() functions that can be included fromasm/mte.h.Signed-off-by Peter Collingbourne <[email protected]>--- include/linux/kasan-enabled.h | 33 +++++++++++++++++++++++++++++++++ include/linux/kasan.h | 23 +---------------------- 2 files changed, 34 insertions(+), 22 deletions(-) create mode 100644 include/linux/kasan-enabled.hinclude/linux/kasan-enabled.h new file +33
-0@@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _LINUX_KASAN_ENABLED_H +#define _LINUX_KASAN_ENABLED_H + +#ifdef CONFIG_KASAN_HW_TAGS + +DECLARE_STATIC_KEY_FALSE (kasan_flag_enabled); + +static __always_inline bool kasan_enabled(void) +{ +return static_branch_likely (&kasan_flag_enabled); +} + +static inline bool kasan_hw_tags_enabled (void ) +{ +return kasan_enabled (); +} + +#else /* CONFIG_KASAN_HW_TAGS */ + +static inline bool kasan_enabled (void ) +{ +return IS_ENABLED (CONFIG_KASAN ); +} + +static inline bool kasan_hw_tags_enabled (void ) +{ +return false; +} + +#endif /* CONFIG_KASAN_HW_TAGS */ + +#endif /* LINUX_KASAN_ENABLED_H */ include/linux/kasan.h +1
-23@@ -3,6 +3,7 @@#define _LINUX_KASAN_H#include <linux/bug.h> +#include <linux/kasan-enabled.h> #include <linux/kernel.h> #include <linux/static_key.h> #include <linux/types.h> @@ -83,33 +84,11 @@ static inline void kasan_disable_current(void) {}#ifdef CONFIG_KASAN_HW_TAGS -DECLARE_STATIC_KEY_FALSE (kasan_flag_enabled); - -static __always_inline bool kasan_enabled(void) -{ -return static_branch_likely (&kasan_flag_enabled); -} - -static inline bool kasan_hw_tags_enabled (void ) -{ -return kasan_enabled (); -} -void kasan_alloc_pages (struct page *page,unsigned int order,gfp_t flags);void kasan_free_pages (struct page *page,unsigned int order);#else /* CONFIG_KASAN_HW_TAGS */ -static inline bool kasan_enabled (void ) -{ -return IS_ENABLED (CONFIG_KASAN ); -} - -static inline bool kasan_hw_tags_enabled (void ) -{ -return false; -} - static __always_inline void kasan_alloc_pages(struct page *page,unsigned int order,gfp_t flags) { --
Quoted 2 lines
2.35.1.473.g83b2b277ed-goog
Quoted 9 lines · Peter Collingbourne
In an upcoming commit we are going to need to call
kasan_hw_tags_enabled()fromarch/arm64/include/asm/mte.h. This would create a circular dependency between headers ifKASAN_GENERICorKASAN_SW_TAGSis enabled:linux/kasan.h->linux/pgtable.h->asm/pgtable.h->asm/mte.h->linux/kasan.h. Break the cycle by introducing a new headerlinux/kasan-enabled.hwith the kasan_*enabled() functions that can be included fromasm/mte.h.[...]
Applied to arm64 (for-next/mte), thanks!
[1/2] kasan: split kasan_*enabled() functions into a separate header
https://git.kernel.org/arm64/c/f9b5e46f4097 [2/2] arm64: mte: avoid clearing PSTATE.TCO on entry unless necessary https://git.kernel.org/arm64/c/38ddf7dafaea
Cheers,
Signature · 5 lines
Will https://fixes.arm64.dev https://next.arm64.dev https://will.arm64.dev