Skip to content

Commit 5d0a8d2

Browse files
brooniectmarinas
authored andcommitted
arm64/ptrace: Ensure that SME is set up for target when writing SSVE state
When we use NT_ARM_SSVE to either enable streaming mode or change the vector length for a process we do not currently do anything to ensure that there is storage allocated for the SME specific register state. If the task had not previously used SME or we changed the vector length then the task will not have had TIF_SME set or backing storage for ZA/ZT allocated, resulting in inconsistent register sizes when saving state and spurious traps which flush the newly set register state. We should set TIF_SME to disable traps and ensure that storage is allocated for ZA and ZT if it is not already allocated. This requires modifying sme_alloc() to make the flush of any existing register state optional so we don't disturb existing state for ZA and ZT. Fixes: e12310a ("arm64/sme: Implement ptrace support for streaming mode SVE registers") Reported-by: David Spickett <David.Spickett@arm.com> Signed-off-by: Mark Brown <broonie@kernel.org> Cc: <stable@vger.kernel.org> # 5.19.x Link: https://lore.kernel.org/r/20230810-arm64-fix-ptrace-race-v1-1-a5361fad2bd6@kernel.org Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
1 parent 69af56a commit 5d0a8d2

File tree

4 files changed

+15
-8
lines changed

4 files changed

+15
-8
lines changed

arch/arm64/include/asm/fpsimd.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,7 @@ static inline int sme_max_virtualisable_vl(void)
356356
return vec_max_virtualisable_vl(ARM64_VEC_SME);
357357
}
358358

359-
extern void sme_alloc(struct task_struct *task);
359+
extern void sme_alloc(struct task_struct *task, bool flush);
360360
extern unsigned int sme_get_vl(void);
361361
extern int sme_set_current_vl(unsigned long arg);
362362
extern int sme_get_current_vl(void);
@@ -388,7 +388,7 @@ static inline void sme_smstart_sm(void) { }
388388
static inline void sme_smstop_sm(void) { }
389389
static inline void sme_smstop(void) { }
390390

391-
static inline void sme_alloc(struct task_struct *task) { }
391+
static inline void sme_alloc(struct task_struct *task, bool flush) { }
392392
static inline void sme_setup(void) { }
393393
static inline unsigned int sme_get_vl(void) { return 0; }
394394
static inline int sme_max_vl(void) { return 0; }

arch/arm64/kernel/fpsimd.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1285,9 +1285,9 @@ void fpsimd_release_task(struct task_struct *dead_task)
12851285
* the interest of testability and predictability, the architecture
12861286
* guarantees that when ZA is enabled it will be zeroed.
12871287
*/
1288-
void sme_alloc(struct task_struct *task)
1288+
void sme_alloc(struct task_struct *task, bool flush)
12891289
{
1290-
if (task->thread.sme_state) {
1290+
if (task->thread.sme_state && flush) {
12911291
memset(task->thread.sme_state, 0, sme_state_size(task));
12921292
return;
12931293
}
@@ -1515,7 +1515,7 @@ void do_sme_acc(unsigned long esr, struct pt_regs *regs)
15151515
}
15161516

15171517
sve_alloc(current, false);
1518-
sme_alloc(current);
1518+
sme_alloc(current, true);
15191519
if (!current->thread.sve_state || !current->thread.sme_state) {
15201520
force_sig(SIGKILL);
15211521
return;

arch/arm64/kernel/ptrace.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -881,6 +881,13 @@ static int sve_set_common(struct task_struct *target,
881881
break;
882882
case ARM64_VEC_SME:
883883
target->thread.svcr |= SVCR_SM_MASK;
884+
885+
/*
886+
* Disable traps and ensure there is SME storage but
887+
* preserve any currently set values in ZA/ZT.
888+
*/
889+
sme_alloc(target, false);
890+
set_tsk_thread_flag(target, TIF_SME);
884891
break;
885892
default:
886893
WARN_ON_ONCE(1);
@@ -1100,7 +1107,7 @@ static int za_set(struct task_struct *target,
11001107
}
11011108

11021109
/* Allocate/reinit ZA storage */
1103-
sme_alloc(target);
1110+
sme_alloc(target, true);
11041111
if (!target->thread.sme_state) {
11051112
ret = -ENOMEM;
11061113
goto out;
@@ -1171,7 +1178,7 @@ static int zt_set(struct task_struct *target,
11711178
return -EINVAL;
11721179

11731180
if (!thread_za_enabled(&target->thread)) {
1174-
sme_alloc(target);
1181+
sme_alloc(target, true);
11751182
if (!target->thread.sme_state)
11761183
return -ENOMEM;
11771184
}

arch/arm64/kernel/signal.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -475,7 +475,7 @@ static int restore_za_context(struct user_ctxs *user)
475475
fpsimd_flush_task_state(current);
476476
/* From now, fpsimd_thread_switch() won't touch thread.sve_state */
477477

478-
sme_alloc(current);
478+
sme_alloc(current, true);
479479
if (!current->thread.sme_state) {
480480
current->thread.svcr &= ~SVCR_ZA_MASK;
481481
clear_thread_flag(TIF_SME);

0 commit comments

Comments
 (0)