Commit 604df13d authored by Catalin Marinas's avatar Catalin Marinas
Browse files

Merge branch 'for-next/mte-async-kernel-mode' into for-next/core

* for-next/mte-async-kernel-mode:
  : Add MTE asynchronous kernel mode support
  kasan, arm64: tests supports for HW_TAGS async mode
  arm64: mte: Report async tag faults before suspend
  arm64: mte: Enable async tag check fault
  arm64: mte: Conditionally compile mte_enable_kernel_*()
  arm64: mte: Enable TCO in functions that can read beyond buffer limits
  kasan: Add report for async mode
  arm64: mte: Drop arch_enable_tagging()
  kasan: Add KASAN mode kernel parameter
  arm64: mte: Add asynchronous mode support
parents a1e1edde e80a76aa
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -161,6 +161,15 @@ particular KASAN features.

- ``kasan=off`` or ``=on`` controls whether KASAN is enabled (default: ``on``).

- ``kasan.mode=sync`` or ``=async`` controls whether KASAN is configured in
  synchronous or asynchronous mode of execution (default: ``sync``).
  Synchronous mode: a bad access is detected immediately when a tag
  check fault occurs.
  Asynchronous mode: a bad access detection is delayed. When a tag check
  fault occurs, the information is stored in hardware (in the TFSR_EL1
  register for arm64). The kernel periodically checks the hardware and
  only reports tag faults during these checks.

- ``kasan.stacktrace=off`` or ``=on`` disables or enables alloc and free stack
  traces collection (default: ``on``).

+3 −1
Original line number Diff line number Diff line
@@ -243,8 +243,10 @@ static inline const void *__tag_set(const void *addr, u8 tag)
}

#ifdef CONFIG_KASAN_HW_TAGS
#define arch_enable_tagging()			mte_enable_kernel()
#define arch_enable_tagging_sync()		mte_enable_kernel_sync()
#define arch_enable_tagging_async()		mte_enable_kernel_async()
#define arch_set_tagging_report_once(state)	mte_set_report_once(state)
#define arch_force_async_tag_fault()		mte_check_tfsr_exit()
#define arch_init_tags(max_tag)			mte_init_tags(max_tag)
#define arch_get_random_tag()			mte_get_random_tag()
#define arch_get_mem_tag(addr)			mte_get_mem_tag(addr)
+7 −2
Original line number Diff line number Diff line
@@ -77,7 +77,8 @@ static inline void mte_set_mem_tag_range(void *addr, size_t size, u8 tag)
	} while (curr != end);
}

void mte_enable_kernel(void);
void mte_enable_kernel_sync(void);
void mte_enable_kernel_async(void);
void mte_init_tags(u64 max_tag);

void mte_set_report_once(bool state);
@@ -104,7 +105,11 @@ static inline void mte_set_mem_tag_range(void *addr, size_t size, u8 tag)
{
}

static inline void mte_enable_kernel(void)
static inline void mte_enable_kernel_sync(void)
{
}

static inline void mte_enable_kernel_async(void)
{
}

+48 −0
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@ void mte_sync_tags(pte_t *ptep, pte_t pte);
void mte_copy_page_tags(void *kto, const void *kfrom);
void flush_mte_state(void);
void mte_thread_switch(struct task_struct *next);
void mte_suspend_enter(void);
void mte_suspend_exit(void);
long set_mte_ctrl(struct task_struct *task, unsigned long arg);
long get_mte_ctrl(struct task_struct *task);
@@ -64,6 +65,9 @@ static inline void flush_mte_state(void)
static inline void mte_thread_switch(struct task_struct *next)
{
}
static inline void mte_suspend_enter(void)
{
}
static inline void mte_suspend_exit(void)
{
}
@@ -84,5 +88,49 @@ static inline int mte_ptrace_copy_tags(struct task_struct *child,

#endif /* CONFIG_ARM64_MTE */

#ifdef CONFIG_KASAN_HW_TAGS
/* Whether the MTE asynchronous mode is enabled. */
DECLARE_STATIC_KEY_FALSE(mte_async_mode);

static inline bool system_uses_mte_async_mode(void)
{
	return static_branch_unlikely(&mte_async_mode);
}

void mte_check_tfsr_el1(void);

static inline void mte_check_tfsr_entry(void)
{
	mte_check_tfsr_el1();
}

static inline void mte_check_tfsr_exit(void)
{
	/*
	 * The asynchronous faults are sync'ed automatically with
	 * TFSR_EL1 on kernel entry but for exit an explicit dsb()
	 * is required.
	 */
	dsb(nsh);
	isb();

	mte_check_tfsr_el1();
}
#else
static inline bool system_uses_mte_async_mode(void)
{
	return false;
}
static inline void mte_check_tfsr_el1(void)
{
}
static inline void mte_check_tfsr_entry(void)
{
}
static inline void mte_check_tfsr_exit(void)
{
}
#endif /* CONFIG_KASAN_HW_TAGS */

#endif /* __ASSEMBLY__ */
#endif /* __ASM_MTE_H  */
+22 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@

#include <asm/cpufeature.h>
#include <asm/mmu.h>
#include <asm/mte.h>
#include <asm/ptrace.h>
#include <asm/memory.h>
#include <asm/extable.h>
@@ -188,6 +189,23 @@ static inline void __uaccess_enable_tco(void)
				 ARM64_MTE, CONFIG_KASAN_HW_TAGS));
}

/*
 * These functions disable tag checking only if in MTE async mode
 * since the sync mode generates exceptions synchronously and the
 * nofault or load_unaligned_zeropad can handle them.
 */
static inline void __uaccess_disable_tco_async(void)
{
	if (system_uses_mte_async_mode())
		 __uaccess_disable_tco();
}

static inline void __uaccess_enable_tco_async(void)
{
	if (system_uses_mte_async_mode())
		__uaccess_enable_tco();
}

static inline void uaccess_disable_privileged(void)
{
	__uaccess_disable_tco();
@@ -307,8 +325,10 @@ do { \
do {									\
	int __gkn_err = 0;						\
									\
	__uaccess_enable_tco_async();					\
	__raw_get_mem("ldr", *((type *)(dst)),				\
		      (__force type *)(src), __gkn_err);		\
	__uaccess_disable_tco_async();					\
	if (unlikely(__gkn_err))					\
		goto err_label;						\
} while (0)
@@ -380,8 +400,10 @@ do { \
do {									\
	int __pkn_err = 0;						\
									\
	__uaccess_enable_tco_async();					\
	__raw_put_mem("str", *((type *)(src)),				\
		      (__force type *)(dst), __pkn_err);		\
	__uaccess_disable_tco_async();					\
	if (unlikely(__pkn_err))					\
		goto err_label;						\
} while(0)
Loading