]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
arm64/fpsimd: ptrace: Fix SVE writes on !SME systems
authorMark Rutland <mark.rutland@arm.com>
Tue, 20 Jan 2026 14:51:05 +0000 (14:51 +0000)
committerCatalin Marinas <catalin.marinas@arm.com>
Thu, 22 Jan 2026 10:10:23 +0000 (10:10 +0000)
When SVE is supported but SME is not supported, a ptrace write to the
NT_ARM_SVE regset can place the tracee into an invalid state where
(non-streaming) SVE register data is stored in FP_STATE_SVE format but
TIF_SVE is clear. This can result in a later warning from
fpsimd_restore_current_state(), e.g.

  WARNING: CPU: 0 PID: 7214 at arch/arm64/kernel/fpsimd.c:383 fpsimd_restore_current_state+0x50c/0x748

When this happens, fpsimd_restore_current_state() will set TIF_SVE,
placing the task into the correct state. This occurs before any other
check of TIF_SVE can possibly occur, as other checks of TIF_SVE only
happen while the FPSIMD/SVE/SME state is live. Thus, aside from the
warning, there is no functional issue.

This bug was introduced during rework to error handling in commit:

  9f8bf718f2923 ("arm64/fpsimd: ptrace: Gracefully handle errors")

... where the setting of TIF_SVE was moved into a block which is only
executed when system_supports_sme() is true.

Fix this by removing the system_supports_sme() check. This ensures that
TIF_SVE is set for (SVE-formatted) writes to NT_ARM_SVE, at the cost of
unconditionally manipulating the tracee's saved svcr value. The
manipulation of svcr is benign and inexpensive, and we already do
similar elsewhere (e.g. during signal handling), so I don't think it's
worth guarding this with system_supports_sme() checks.

Aside from the above, there is no functional change. The 'type' argument
to sve_set_common() is only set to ARM64_VEC_SME (in ssve_set())) when
system_supports_sme(), so the ARM64_VEC_SME case in the switch statement
is still unreachable when !system_supports_sme(). When
CONFIG_ARM64_SME=n, the only caller of sve_set_common() is sve_set(),
and the compiler can constant-fold for the case where type is
ARM64_VEC_SVE, removing the logic for other cases.

Reported-by: syzbot+d4ab35af21e99d07ce67@syzkaller.appspotmail.com
Fixes: 9f8bf718f292 ("arm64/fpsimd: ptrace: Gracefully handle errors")
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Cc: <stable@vger.kernel.org>
Cc: Mark Brown <broonie@kernel.org>
Cc: Will Deacon <will@kernel.org>
Reviewed-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
arch/arm64/kernel/ptrace.c

index b9bdd83fbbca0f3ba6b6b0d1458fcfedb8a9a998..6c5ff6807d4cc82bb84d1dc7f7348cae39300769 100644 (file)
@@ -968,20 +968,18 @@ static int sve_set_common(struct task_struct *target,
        vq = sve_vq_from_vl(task_get_vl(target, type));
 
        /* Enter/exit streaming mode */
-       if (system_supports_sme()) {
-               switch (type) {
-               case ARM64_VEC_SVE:
-                       target->thread.svcr &= ~SVCR_SM_MASK;
-                       set_tsk_thread_flag(target, TIF_SVE);
-                       break;
-               case ARM64_VEC_SME:
-                       target->thread.svcr |= SVCR_SM_MASK;
-                       set_tsk_thread_flag(target, TIF_SME);
-                       break;
-               default:
-                       WARN_ON_ONCE(1);
-                       return -EINVAL;
-               }
+       switch (type) {
+       case ARM64_VEC_SVE:
+               target->thread.svcr &= ~SVCR_SM_MASK;
+               set_tsk_thread_flag(target, TIF_SVE);
+               break;
+       case ARM64_VEC_SME:
+               target->thread.svcr |= SVCR_SM_MASK;
+               set_tsk_thread_flag(target, TIF_SME);
+               break;
+       default:
+               WARN_ON_ONCE(1);
+               return -EINVAL;
        }
 
        /* Always zero V regs, FPSR, and FPCR */