mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson
synced 2025-09-01 15:14:52 +00:00
arm64/fpsimd: ptrace: Mandate SVE payload for streaming-mode state
When a task has PSTATE.SM==1, reads of NT_ARM_SSVE are required to
always present a header with SVE_PT_REGS_SVE, and register data in SVE
format. Reads of NT_ARM_SSVE must never present register data in FPSIMD
format. Within the kernel, we always expect streaming SVE data to be
stored in SVE format.
Currently a user can write to NT_ARM_SSVE with a header presenting
SVE_PT_REGS_FPSIMD rather than SVE_PT_REGS_SVE, placing the task's
FPSIMD/SVE data into an invalid state.
To fix this we can either:
(a) Forbid such writes.
(b) Accept such writes, and immediately convert data into SVE format.
Take the simple option and forbid such writes.
Fixes: e12310a0d3
("arm64/sme: Implement ptrace support for streaming mode SVE registers")
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: David Spickett <david.spickett@arm.com>
Cc: Luis Machado <luis.machado@arm.com>
Cc: Marc Zyngier <maz@kernel.org>
Cc: Mark Brown <broonie@kernel.org>
Cc: Will Deacon <will@kernel.org>
Reviewed-by: Mark Brown <broonie@kernel.org>
Link: https://lore.kernel.org/r/20250508132644.1395904-19-mark.rutland@arm.com
Signed-off-by: Will Deacon <will@kernel.org>
This commit is contained in:
parent
b93e685ecf
commit
f916dd32a9
@ -890,6 +890,7 @@ static int sve_set_common(struct task_struct *target,
|
||||
struct user_sve_header header;
|
||||
unsigned int vq;
|
||||
unsigned long start, end;
|
||||
bool fpsimd;
|
||||
|
||||
/* Header */
|
||||
if (count < sizeof(header))
|
||||
@ -899,6 +900,15 @@ static int sve_set_common(struct task_struct *target,
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* Streaming SVE data is always stored and presented in SVE format.
|
||||
* Require the user to provide SVE formatted data for consistency, and
|
||||
* to avoid the risk that we configure the task into an invalid state.
|
||||
*/
|
||||
fpsimd = (header.flags & SVE_PT_REGS_MASK) == SVE_PT_REGS_FPSIMD;
|
||||
if (fpsimd && type == ARM64_VEC_SME)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Apart from SVE_PT_REGS_MASK, all SVE_PT_* flags are consumed by
|
||||
* vec_set_vector_length(), which will also validate them for us:
|
||||
@ -945,7 +955,7 @@ static int sve_set_common(struct task_struct *target,
|
||||
/* Registers: FPSIMD-only case */
|
||||
|
||||
BUILD_BUG_ON(SVE_PT_FPSIMD_OFFSET != sizeof(header));
|
||||
if ((header.flags & SVE_PT_REGS_MASK) == SVE_PT_REGS_FPSIMD) {
|
||||
if (fpsimd) {
|
||||
clear_tsk_thread_flag(target, TIF_SVE);
|
||||
target->thread.fp_type = FP_STATE_FPSIMD;
|
||||
ret = __fpr_set(target, regset, pos, count, kbuf, ubuf,
|
||||
|
Loading…
Reference in New Issue
Block a user