Skip to content

Commit d2e0d8f

Browse files
pccctmarinas
authored andcommitted
arm64: move preemption disablement to prctl handlers
In the next patch, we will start reading sctlr_user from mte_update_sctlr_user and subsequently writing a new value based on the task's TCF setting and potentially the per-CPU TCF preference. This means that we need to be careful to disable preemption around any code sequences that read from sctlr_user and subsequently write to sctlr_user and/or SCTLR_EL1, so that we don't end up writing a stale value (based on the previous CPU's TCF preference) to either of them. We currently have four such sequences, in the prctl handlers for PR_SET_TAGGED_ADDR_CTRL and PR_PAC_SET_ENABLED_KEYS, as well as in the task initialization code that resets the prctl settings. Change the prctl handlers to disable preemption in the handlers themselves rather than the functions that they call, and change the task initialization code to call the respective prctl handlers instead of setting sctlr_user directly. As a result of this change, we no longer need the helper function set_task_sctlr_el1, nor does its behavior make sense any more, so remove it. Signed-off-by: Peter Collingbourne <[email protected]> Link: https://linux-review.googlesource.com/id/Ic0e8a0c00bb47d786c1e8011df0b7fe99bee4bb5 Link: https://lore.kernel.org/r/[email protected] Acked-by: Will Deacon <[email protected]> Signed-off-by: Catalin Marinas <[email protected]>
1 parent 433c38f commit d2e0d8f

File tree

5 files changed

+24
-29
lines changed

5 files changed

+24
-29
lines changed

arch/arm64/include/asm/pointer_auth.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
#include <asm/memory.h>
1111
#include <asm/sysreg.h>
1212

13+
#define PR_PAC_ENABLED_KEYS_MASK \
14+
(PR_PAC_APIAKEY | PR_PAC_APIBKEY | PR_PAC_APDAKEY | PR_PAC_APDBKEY)
15+
1316
#ifdef CONFIG_ARM64_PTR_AUTH
1417
/*
1518
* Each key is a 128-bit quantity which is split across a pair of 64-bit
@@ -117,9 +120,9 @@ static __always_inline void ptrauth_enable(void)
117120
\
118121
/* enable all keys */ \
119122
if (system_supports_address_auth()) \
120-
set_task_sctlr_el1(current->thread.sctlr_user | \
121-
SCTLR_ELx_ENIA | SCTLR_ELx_ENIB | \
122-
SCTLR_ELx_ENDA | SCTLR_ELx_ENDB); \
123+
ptrauth_set_enabled_keys(current, \
124+
PR_PAC_ENABLED_KEYS_MASK, \
125+
PR_PAC_ENABLED_KEYS_MASK); \
123126
} while (0)
124127

125128
#define ptrauth_thread_switch_user(tsk) \
@@ -146,7 +149,4 @@ static __always_inline void ptrauth_enable(void)
146149
#define ptrauth_thread_switch_kernel(tsk)
147150
#endif /* CONFIG_ARM64_PTR_AUTH_KERNEL */
148151

149-
#define PR_PAC_ENABLED_KEYS_MASK \
150-
(PR_PAC_APIAKEY | PR_PAC_APIBKEY | PR_PAC_APDAKEY | PR_PAC_APDBKEY)
151-
152152
#endif /* __ASM_POINTER_AUTH_H */

arch/arm64/include/asm/processor.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,7 @@ extern void release_thread(struct task_struct *);
259259

260260
unsigned long get_wchan(struct task_struct *p);
261261

262-
void set_task_sctlr_el1(u64 sctlr);
262+
void update_sctlr_el1(u64 sctlr);
263263

264264
/* Thread switching */
265265
extern struct task_struct *cpu_switch_to(struct task_struct *prev,

arch/arm64/kernel/mte.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -218,9 +218,7 @@ void mte_thread_init_user(void)
218218
write_sysreg_s(0, SYS_TFSRE0_EL1);
219219
clear_thread_flag(TIF_MTE_ASYNC_FAULT);
220220
/* disable tag checking and reset tag generation mask */
221-
current->thread.mte_ctrl = MTE_CTRL_GCR_USER_EXCL_MASK;
222-
mte_update_sctlr_user(current);
223-
set_task_sctlr_el1(current->thread.sctlr_user);
221+
set_mte_ctrl(current, 0);
224222
}
225223

226224
void mte_thread_switch(struct task_struct *next)
@@ -278,8 +276,10 @@ long set_mte_ctrl(struct task_struct *task, unsigned long arg)
278276

279277
task->thread.mte_ctrl = mte_ctrl;
280278
if (task == current) {
279+
preempt_disable();
281280
mte_update_sctlr_user(task);
282-
set_task_sctlr_el1(task->thread.sctlr_user);
281+
update_sctlr_el1(task->thread.sctlr_user);
282+
preempt_enable();
283283
}
284284

285285
return 0;

arch/arm64/kernel/pointer_auth.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ static u64 arg_to_enxx_mask(unsigned long arg)
6767
int ptrauth_set_enabled_keys(struct task_struct *tsk, unsigned long keys,
6868
unsigned long enabled)
6969
{
70-
u64 sctlr = tsk->thread.sctlr_user;
70+
u64 sctlr;
7171

7272
if (!system_supports_address_auth())
7373
return -EINVAL;
@@ -78,12 +78,14 @@ int ptrauth_set_enabled_keys(struct task_struct *tsk, unsigned long keys,
7878
if ((keys & ~PR_PAC_ENABLED_KEYS_MASK) || (enabled & ~keys))
7979
return -EINVAL;
8080

81+
preempt_disable();
82+
sctlr = tsk->thread.sctlr_user;
8183
sctlr &= ~arg_to_enxx_mask(keys);
8284
sctlr |= arg_to_enxx_mask(enabled);
85+
tsk->thread.sctlr_user = sctlr;
8386
if (tsk == current)
84-
set_task_sctlr_el1(sctlr);
85-
else
86-
tsk->thread.sctlr_user = sctlr;
87+
update_sctlr_el1(sctlr);
88+
preempt_enable();
8789

8890
return 0;
8991
}

arch/arm64/kernel/process.c

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -477,7 +477,13 @@ static void compat_thread_switch(struct task_struct *next)
477477
set_tsk_thread_flag(next, TIF_NOTIFY_RESUME);
478478
}
479479

480-
static void update_sctlr_el1(u64 sctlr)
480+
/*
481+
* __switch_to() checks current->thread.sctlr_user as an optimisation. Therefore
482+
* this function must be called with preemption disabled and the update to
483+
* sctlr_user must be made in the same preemption disabled block so that
484+
* __switch_to() does not see the variable update before the SCTLR_EL1 one.
485+
*/
486+
void update_sctlr_el1(u64 sctlr)
481487
{
482488
/*
483489
* EnIA must not be cleared while in the kernel as this is necessary for
@@ -489,19 +495,6 @@ static void update_sctlr_el1(u64 sctlr)
489495
isb();
490496
}
491497

492-
void set_task_sctlr_el1(u64 sctlr)
493-
{
494-
/*
495-
* __switch_to() checks current->thread.sctlr as an
496-
* optimisation. Disable preemption so that it does not see
497-
* the variable update before the SCTLR_EL1 one.
498-
*/
499-
preempt_disable();
500-
current->thread.sctlr_user = sctlr;
501-
update_sctlr_el1(sctlr);
502-
preempt_enable();
503-
}
504-
505498
/*
506499
* Thread switching.
507500
*/

0 commit comments

Comments
 (0)