Skip to content

Commit 2d27e58

Browse files
fvincenzowilldeacon
authored andcommitted
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 <[email protected]> Cc: Andrey Ryabinin <[email protected]> Cc: Alexander Potapenko <[email protected]> Cc: Andrey Konovalov <[email protected]> Signed-off-by: Vincenzo Frascino <[email protected]> Reviewed-by: Catalin Marinas <[email protected]> Reviewed-by: Andrey Konovalov <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Will Deacon <[email protected]>
1 parent ec02883 commit 2d27e58

File tree

5 files changed

+52
-18
lines changed

5 files changed

+52
-18
lines changed

Documentation/dev-tools/kasan.rst

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,14 +194,17 @@ additional boot parameters that allow disabling KASAN or controlling features:
194194

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

197-
- ``kasan.mode=sync`` or ``=async`` controls whether KASAN is configured in
198-
synchronous or asynchronous mode of execution (default: ``sync``).
197+
- ``kasan.mode=sync``, ``=async`` or ``=asymm`` controls whether KASAN
198+
is configured in synchronous, asynchronous or asymmetric mode of
199+
execution (default: ``sync``).
199200
Synchronous mode: a bad access is detected immediately when a tag
200201
check fault occurs.
201202
Asynchronous mode: a bad access detection is delayed. When a tag check
202203
fault occurs, the information is stored in hardware (in the TFSR_EL1
203204
register for arm64). The kernel periodically checks the hardware and
204205
only reports tag faults during these checks.
206+
Asymmetric mode: a bad access is detected synchronously on reads and
207+
asynchronously on writes.
205208

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

lib/test_kasan.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ static void kasan_test_exit(struct kunit *test)
8888
*/
8989
#define KUNIT_EXPECT_KASAN_FAIL(test, expression) do { \
9090
if (IS_ENABLED(CONFIG_KASAN_HW_TAGS) && \
91-
!kasan_async_mode_enabled()) \
91+
kasan_sync_fault_possible()) \
9292
migrate_disable(); \
9393
KUNIT_EXPECT_FALSE(test, READ_ONCE(fail_data.report_found)); \
9494
barrier(); \

mm/kasan/hw_tags.c

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ enum kasan_arg_mode {
2929
KASAN_ARG_MODE_DEFAULT,
3030
KASAN_ARG_MODE_SYNC,
3131
KASAN_ARG_MODE_ASYNC,
32+
KASAN_ARG_MODE_ASYMM,
3233
};
3334

3435
enum kasan_arg_stacktrace {
@@ -45,9 +46,9 @@ static enum kasan_arg_stacktrace kasan_arg_stacktrace __ro_after_init;
4546
DEFINE_STATIC_KEY_FALSE(kasan_flag_enabled);
4647
EXPORT_SYMBOL(kasan_flag_enabled);
4748

48-
/* Whether the asynchronous mode is enabled. */
49-
bool kasan_flag_async __ro_after_init;
50-
EXPORT_SYMBOL_GPL(kasan_flag_async);
49+
/* Whether the selected mode is synchronous/asynchronous/asymmetric.*/
50+
enum kasan_mode kasan_mode __ro_after_init;
51+
EXPORT_SYMBOL_GPL(kasan_mode);
5152

5253
/* Whether to collect alloc/free stack traces. */
5354
DEFINE_STATIC_KEY_FALSE(kasan_flag_stacktrace);
@@ -69,7 +70,7 @@ static int __init early_kasan_flag(char *arg)
6970
}
7071
early_param("kasan", early_kasan_flag);
7172

72-
/* kasan.mode=sync/async */
73+
/* kasan.mode=sync/async/asymm */
7374
static int __init early_kasan_mode(char *arg)
7475
{
7576
if (!arg)
@@ -79,6 +80,8 @@ static int __init early_kasan_mode(char *arg)
7980
kasan_arg_mode = KASAN_ARG_MODE_SYNC;
8081
else if (!strcmp(arg, "async"))
8182
kasan_arg_mode = KASAN_ARG_MODE_ASYNC;
83+
else if (!strcmp(arg, "asymm"))
84+
kasan_arg_mode = KASAN_ARG_MODE_ASYMM;
8285
else
8386
return -EINVAL;
8487

@@ -116,11 +119,13 @@ void kasan_init_hw_tags_cpu(void)
116119
return;
117120

118121
/*
119-
* Enable async mode only when explicitly requested through
120-
* the command line.
122+
* Enable async or asymm modes only when explicitly requested
123+
* through the command line.
121124
*/
122125
if (kasan_arg_mode == KASAN_ARG_MODE_ASYNC)
123126
hw_enable_tagging_async();
127+
else if (kasan_arg_mode == KASAN_ARG_MODE_ASYMM)
128+
hw_enable_tagging_asymm();
124129
else
125130
hw_enable_tagging_sync();
126131
}
@@ -143,15 +148,19 @@ void __init kasan_init_hw_tags(void)
143148
case KASAN_ARG_MODE_DEFAULT:
144149
/*
145150
* Default to sync mode.
146-
* Do nothing, kasan_flag_async keeps its default value.
147151
*/
148-
break;
152+
fallthrough;
149153
case KASAN_ARG_MODE_SYNC:
150-
/* Do nothing, kasan_flag_async keeps its default value. */
154+
/* Sync mode enabled. */
155+
kasan_mode = KASAN_MODE_SYNC;
151156
break;
152157
case KASAN_ARG_MODE_ASYNC:
153158
/* Async mode enabled. */
154-
kasan_flag_async = true;
159+
kasan_mode = KASAN_MODE_ASYNC;
160+
break;
161+
case KASAN_ARG_MODE_ASYMM:
162+
/* Asymm mode enabled. */
163+
kasan_mode = KASAN_MODE_ASYMM;
155164
break;
156165
}
157166

mm/kasan/kasan.h

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,28 @@
1313
#include "../slab.h"
1414

1515
DECLARE_STATIC_KEY_FALSE(kasan_flag_stacktrace);
16-
extern bool kasan_flag_async __ro_after_init;
16+
17+
enum kasan_mode {
18+
KASAN_MODE_SYNC,
19+
KASAN_MODE_ASYNC,
20+
KASAN_MODE_ASYMM,
21+
};
22+
23+
extern enum kasan_mode kasan_mode __ro_after_init;
1724

1825
static inline bool kasan_stack_collection_enabled(void)
1926
{
2027
return static_branch_unlikely(&kasan_flag_stacktrace);
2128
}
2229

23-
static inline bool kasan_async_mode_enabled(void)
30+
static inline bool kasan_async_fault_possible(void)
31+
{
32+
return kasan_mode == KASAN_MODE_ASYNC || kasan_mode == KASAN_MODE_ASYMM;
33+
}
34+
35+
static inline bool kasan_sync_fault_possible(void)
2436
{
25-
return kasan_flag_async;
37+
return kasan_mode == KASAN_MODE_SYNC || kasan_mode == KASAN_MODE_ASYMM;
2638
}
2739
#else
2840

@@ -31,11 +43,16 @@ static inline bool kasan_stack_collection_enabled(void)
3143
return true;
3244
}
3345

34-
static inline bool kasan_async_mode_enabled(void)
46+
static inline bool kasan_async_fault_possible(void)
3547
{
3648
return false;
3749
}
3850

51+
static inline bool kasan_sync_fault_possible(void)
52+
{
53+
return true;
54+
}
55+
3956
#endif
4057

4158
#if defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KASAN_SW_TAGS)
@@ -287,6 +304,9 @@ static inline const void *arch_kasan_set_tag(const void *addr, u8 tag)
287304
#ifndef arch_enable_tagging_async
288305
#define arch_enable_tagging_async()
289306
#endif
307+
#ifndef arch_enable_tagging_asymm
308+
#define arch_enable_tagging_asymm()
309+
#endif
290310
#ifndef arch_force_async_tag_fault
291311
#define arch_force_async_tag_fault()
292312
#endif
@@ -302,6 +322,7 @@ static inline const void *arch_kasan_set_tag(const void *addr, u8 tag)
302322

303323
#define hw_enable_tagging_sync() arch_enable_tagging_sync()
304324
#define hw_enable_tagging_async() arch_enable_tagging_async()
325+
#define hw_enable_tagging_asymm() arch_enable_tagging_asymm()
305326
#define hw_force_async_tag_fault() arch_force_async_tag_fault()
306327
#define hw_get_random_tag() arch_get_random_tag()
307328
#define hw_get_mem_tag(addr) arch_get_mem_tag(addr)
@@ -312,6 +333,7 @@ static inline const void *arch_kasan_set_tag(const void *addr, u8 tag)
312333

313334
#define hw_enable_tagging_sync()
314335
#define hw_enable_tagging_async()
336+
#define hw_enable_tagging_asymm()
315337

316338
#endif /* CONFIG_KASAN_HW_TAGS */
317339

mm/kasan/report.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ static void start_report(unsigned long *flags)
112112

113113
static void end_report(unsigned long *flags, unsigned long addr)
114114
{
115-
if (!kasan_async_mode_enabled())
115+
if (!kasan_async_fault_possible())
116116
trace_error_report_end(ERROR_DETECTOR_KASAN, addr);
117117
pr_err("==================================================================\n");
118118
add_taint(TAINT_BAD_PAGE, LOCKDEP_NOW_UNRELIABLE);

0 commit comments

Comments
 (0)