Commit 9eab331f authored by Vincenzo Frascino's avatar Vincenzo Frascino
Browse files

kasan: Extend KASAN mode kernel parameter



Architectures supported by KASAN_HW_TAGS can provide an asymmetric mode
of execution. On an MTE enabled arm64 hw for example this can be
identified with the asymmetric tagging mode of execution. In particular,
when such a mode is present, the CPU triggers a fault on a tag mismatch
during a load operation and asynchronously updates a register when a tag
mismatch is detected during a store operation.

Extend the KASAN HW execution mode kernel command line parameter to
support asymmetric mode.

Cc: Dmitry Vyukov <dvyukov@google.com>
Cc: Andrey Ryabinin <aryabinin@virtuozzo.com>
Cc: Alexander Potapenko <glider@google.com>
Cc: Andrey Konovalov <andreyknvl@gmail.com>
Signed-off-by: Vincenzo Frascino's avatarVincenzo Frascino <vincenzo.frascino@arm.com>
parent 6f22f85f
...@@ -194,14 +194,20 @@ additional boot parameters that allow disabling KASAN or controlling features: ...@@ -194,14 +194,20 @@ additional boot parameters that allow disabling KASAN or controlling features:
- ``kasan=off`` or ``=on`` controls whether KASAN is enabled (default: ``on``). - ``kasan=off`` or ``=on`` controls whether KASAN is enabled (default: ``on``).
- ``kasan.mode=sync`` or ``=async`` controls whether KASAN is configured in - ``kasan.mode=sync``, ``=async`` or ``=asymm`` controls whether KASAN
synchronous or asynchronous mode of execution (default: ``sync``). is configured in synchronous, asynchronous or asymmetric mode of
execution (default: ``sync``).
Synchronous mode: a bad access is detected immediately when a tag Synchronous mode: a bad access is detected immediately when a tag
check fault occurs. check fault occurs.
Asynchronous mode: a bad access detection is delayed. When a tag check Asynchronous mode: a bad access detection is delayed. When a tag check
fault occurs, the information is stored in hardware (in the TFSR_EL1 fault occurs, the information is stored in hardware (in the TFSR_EL1
register for arm64). The kernel periodically checks the hardware and register for arm64). The kernel periodically checks the hardware and
only reports tag faults during these checks. only reports tag faults during these checks.
Asymmetric mode: a bad access is detected immediately when a tag
check fault occurs during a load operation and its detection is
delayed during a store operation. For the store operations 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 - ``kasan.stacktrace=off`` or ``=on`` disables or enables alloc and free stack
traces collection (default: ``on``). traces collection (default: ``on``).
......
...@@ -29,6 +29,7 @@ enum kasan_arg_mode { ...@@ -29,6 +29,7 @@ enum kasan_arg_mode {
KASAN_ARG_MODE_DEFAULT, KASAN_ARG_MODE_DEFAULT,
KASAN_ARG_MODE_SYNC, KASAN_ARG_MODE_SYNC,
KASAN_ARG_MODE_ASYNC, KASAN_ARG_MODE_ASYNC,
KASAN_ARG_MODE_ASYMM,
}; };
enum kasan_arg_stacktrace { enum kasan_arg_stacktrace {
...@@ -49,6 +50,10 @@ EXPORT_SYMBOL(kasan_flag_enabled); ...@@ -49,6 +50,10 @@ EXPORT_SYMBOL(kasan_flag_enabled);
bool kasan_flag_async __ro_after_init; bool kasan_flag_async __ro_after_init;
EXPORT_SYMBOL_GPL(kasan_flag_async); EXPORT_SYMBOL_GPL(kasan_flag_async);
/* Whether the asymmetric mode is enabled. */
bool kasan_flag_asymm __ro_after_init;
EXPORT_SYMBOL_GPL(kasan_flag_asymm);
/* Whether to collect alloc/free stack traces. */ /* Whether to collect alloc/free stack traces. */
DEFINE_STATIC_KEY_FALSE(kasan_flag_stacktrace); DEFINE_STATIC_KEY_FALSE(kasan_flag_stacktrace);
...@@ -69,7 +74,7 @@ static int __init early_kasan_flag(char *arg) ...@@ -69,7 +74,7 @@ static int __init early_kasan_flag(char *arg)
} }
early_param("kasan", early_kasan_flag); early_param("kasan", early_kasan_flag);
/* kasan.mode=sync/async */ /* kasan.mode=sync/async/asymm */
static int __init early_kasan_mode(char *arg) static int __init early_kasan_mode(char *arg)
{ {
if (!arg) if (!arg)
...@@ -79,6 +84,8 @@ static int __init early_kasan_mode(char *arg) ...@@ -79,6 +84,8 @@ static int __init early_kasan_mode(char *arg)
kasan_arg_mode = KASAN_ARG_MODE_SYNC; kasan_arg_mode = KASAN_ARG_MODE_SYNC;
else if (!strcmp(arg, "async")) else if (!strcmp(arg, "async"))
kasan_arg_mode = KASAN_ARG_MODE_ASYNC; kasan_arg_mode = KASAN_ARG_MODE_ASYNC;
else if (!strcmp(arg, "asymm"))
kasan_arg_mode = KASAN_ARG_MODE_ASYMM;
else else
return -EINVAL; return -EINVAL;
...@@ -116,11 +123,13 @@ void kasan_init_hw_tags_cpu(void) ...@@ -116,11 +123,13 @@ void kasan_init_hw_tags_cpu(void)
return; return;
/* /*
* Enable async mode only when explicitly requested through * Enable async or asymm modes only when explicitly requested
* the command line. * through the command line.
*/ */
if (kasan_arg_mode == KASAN_ARG_MODE_ASYNC) if (kasan_arg_mode == KASAN_ARG_MODE_ASYNC)
hw_enable_tagging_async(); hw_enable_tagging_async();
else if (kasan_arg_mode == KASAN_ARG_MODE_ASYMM)
hw_enable_tagging_asymm();
else else
hw_enable_tagging_sync(); hw_enable_tagging_sync();
} }
...@@ -143,16 +152,24 @@ void __init kasan_init_hw_tags(void) ...@@ -143,16 +152,24 @@ void __init kasan_init_hw_tags(void)
case KASAN_ARG_MODE_DEFAULT: case KASAN_ARG_MODE_DEFAULT:
/* /*
* Default to sync mode. * Default to sync mode.
* Do nothing, kasan_flag_async keeps its default value. * Do nothing, kasan_flag_async and kasan_flag_asymm keep
* their default values.
*/ */
break; break;
case KASAN_ARG_MODE_SYNC: case KASAN_ARG_MODE_SYNC:
/* Do nothing, kasan_flag_async keeps its default value. */ /*
* Do nothing, kasan_flag_async and kasan_flag_asymm keep
* their default values.
*/
break; break;
case KASAN_ARG_MODE_ASYNC: case KASAN_ARG_MODE_ASYNC:
/* Async mode enabled. */ /* Async mode enabled. */
kasan_flag_async = true; kasan_flag_async = true;
break; break;
case KASAN_ARG_MODE_ASYMM:
/* Asymm mode enabled. */
kasan_flag_asymm = true;
break;
} }
switch (kasan_arg_stacktrace) { switch (kasan_arg_stacktrace) {
......
...@@ -287,6 +287,9 @@ static inline const void *arch_kasan_set_tag(const void *addr, u8 tag) ...@@ -287,6 +287,9 @@ static inline const void *arch_kasan_set_tag(const void *addr, u8 tag)
#ifndef arch_enable_tagging_async #ifndef arch_enable_tagging_async
#define arch_enable_tagging_async() #define arch_enable_tagging_async()
#endif #endif
#ifndef arch_enable_tagging_asymm
#define arch_enable_tagging_asymm()
#endif
#ifndef arch_force_async_tag_fault #ifndef arch_force_async_tag_fault
#define arch_force_async_tag_fault() #define arch_force_async_tag_fault()
#endif #endif
...@@ -302,6 +305,7 @@ static inline const void *arch_kasan_set_tag(const void *addr, u8 tag) ...@@ -302,6 +305,7 @@ static inline const void *arch_kasan_set_tag(const void *addr, u8 tag)
#define hw_enable_tagging_sync() arch_enable_tagging_sync() #define hw_enable_tagging_sync() arch_enable_tagging_sync()
#define hw_enable_tagging_async() arch_enable_tagging_async() #define hw_enable_tagging_async() arch_enable_tagging_async()
#define hw_enable_tagging_asymm() arch_enable_tagging_asymm()
#define hw_force_async_tag_fault() arch_force_async_tag_fault() #define hw_force_async_tag_fault() arch_force_async_tag_fault()
#define hw_get_random_tag() arch_get_random_tag() #define hw_get_random_tag() arch_get_random_tag()
#define hw_get_mem_tag(addr) arch_get_mem_tag(addr) #define hw_get_mem_tag(addr) arch_get_mem_tag(addr)
...@@ -312,6 +316,7 @@ static inline const void *arch_kasan_set_tag(const void *addr, u8 tag) ...@@ -312,6 +316,7 @@ static inline const void *arch_kasan_set_tag(const void *addr, u8 tag)
#define hw_enable_tagging_sync() #define hw_enable_tagging_sync()
#define hw_enable_tagging_async() #define hw_enable_tagging_async()
#define hw_enable_tagging_asymm()
#endif /* CONFIG_KASAN_HW_TAGS */ #endif /* CONFIG_KASAN_HW_TAGS */
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment