Skip to content

Commit e5af50a

Browse files
pccwilldeacon
authored andcommitted
arm64: kasan: mte: move GCR_EL1 switch to task switch when KASAN disabled
It is not necessary to write to GCR_EL1 on every kernel entry and exit when HW tag-based KASAN is disabled because the kernel will not execute any IRG instructions in that mode. Since accessing GCR_EL1 can be expensive on some microarchitectures, avoid doing so by moving the access to task switch when HW tag-based KASAN is disabled. Signed-off-by: Peter Collingbourne <[email protected]> Acked-by: Andrey Konovalov <[email protected]> Link: https://linux-review.googlesource.com/id/I78e90d60612a94c24344526f476ac4ff216e10d2 Reviewed-by: Catalin Marinas <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Will Deacon <[email protected]>
1 parent 5816b3e commit e5af50a

File tree

3 files changed

+38
-7
lines changed

3 files changed

+38
-7
lines changed

arch/arm64/kernel/entry.S

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -168,20 +168,20 @@ alternative_else_nop_endif
168168

169169
.macro mte_set_kernel_gcr, tmp, tmp2
170170
#ifdef CONFIG_KASAN_HW_TAGS
171-
alternative_if_not ARM64_MTE
171+
alternative_cb kasan_hw_tags_enable
172172
b 1f
173-
alternative_else_nop_endif
173+
alternative_cb_end
174174
mov \tmp, KERNEL_GCR_EL1
175175
msr_s SYS_GCR_EL1, \tmp
176176
1:
177177
#endif
178178
.endm
179179

180180
.macro mte_set_user_gcr, tsk, tmp, tmp2
181-
#ifdef CONFIG_ARM64_MTE
182-
alternative_if_not ARM64_MTE
181+
#ifdef CONFIG_KASAN_HW_TAGS
182+
alternative_cb kasan_hw_tags_enable
183183
b 1f
184-
alternative_else_nop_endif
184+
alternative_cb_end
185185
ldr \tmp, [\tsk, #THREAD_MTE_CTRL]
186186

187187
mte_set_gcr \tmp, \tmp2

arch/arm64/kernel/mte.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,30 @@ static void mte_update_sctlr_user(struct task_struct *task)
179179
task->thread.sctlr_user = sctlr;
180180
}
181181

182+
static void mte_update_gcr_excl(struct task_struct *task)
183+
{
184+
/*
185+
* SYS_GCR_EL1 will be set to current->thread.mte_ctrl value by
186+
* mte_set_user_gcr() in kernel_exit, but only if KASAN is enabled.
187+
*/
188+
if (kasan_hw_tags_enabled())
189+
return;
190+
191+
write_sysreg_s(
192+
((task->thread.mte_ctrl >> MTE_CTRL_GCR_USER_EXCL_SHIFT) &
193+
SYS_GCR_EL1_EXCL_MASK) | SYS_GCR_EL1_RRND,
194+
SYS_GCR_EL1);
195+
}
196+
197+
void __init kasan_hw_tags_enable(struct alt_instr *alt, __le32 *origptr,
198+
__le32 *updptr, int nr_inst)
199+
{
200+
BUG_ON(nr_inst != 1); /* Branch -> NOP */
201+
202+
if (kasan_hw_tags_enabled())
203+
*updptr = cpu_to_le32(aarch64_insn_gen_nop());
204+
}
205+
182206
void mte_thread_init_user(void)
183207
{
184208
if (!system_supports_mte())
@@ -198,6 +222,7 @@ void mte_thread_switch(struct task_struct *next)
198222
return;
199223

200224
mte_update_sctlr_user(next);
225+
mte_update_gcr_excl(next);
201226

202227
/*
203228
* Check if an async tag exception occurred at EL1.
@@ -243,6 +268,7 @@ long set_mte_ctrl(struct task_struct *task, unsigned long arg)
243268
if (task == current) {
244269
preempt_disable();
245270
mte_update_sctlr_user(task);
271+
mte_update_gcr_excl(task);
246272
update_sctlr_el1(task->thread.sctlr_user);
247273
preempt_enable();
248274
}

include/linux/kasan.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ static __always_inline bool kasan_enabled(void)
8989
return static_branch_likely(&kasan_flag_enabled);
9090
}
9191

92-
static inline bool kasan_has_integrated_init(void)
92+
static inline bool kasan_hw_tags_enabled(void)
9393
{
9494
return kasan_enabled();
9595
}
@@ -104,7 +104,7 @@ static inline bool kasan_enabled(void)
104104
return IS_ENABLED(CONFIG_KASAN);
105105
}
106106

107-
static inline bool kasan_has_integrated_init(void)
107+
static inline bool kasan_hw_tags_enabled(void)
108108
{
109109
return false;
110110
}
@@ -125,6 +125,11 @@ static __always_inline void kasan_free_pages(struct page *page,
125125

126126
#endif /* CONFIG_KASAN_HW_TAGS */
127127

128+
static inline bool kasan_has_integrated_init(void)
129+
{
130+
return kasan_hw_tags_enabled();
131+
}
132+
128133
#ifdef CONFIG_KASAN
129134

130135
struct kasan_cache {

0 commit comments

Comments
 (0)