Skip to content

Commit be625d8

Browse files
mrutland-armwilldeacon
authored andcommitted
arm64/fpsimd: signal: Consistently read FPSIMD context
For historical reasons, restore_sve_fpsimd_context() has an open-coded copy of the logic from read_fpsimd_context(), which is used to either restore an FPSIMD-only context, or to merge FPSIMD state into an SVE state when restoring an SVE+FPSIMD context. The logic is *almost* identical. Refactor the logic to avoid duplication and make this clearer. This comes with two functional changes that I do not believe will be problematic in practice: * The user_fpsimd_state::size field will be checked in all restore paths that consume it user_fpsimd_state. The kernel always populates this field when delivering a signal, and so this should contain the expected value unless it has been corrupted. * If a read of user_fpsimd_state fails, we will return early without modifying TIF_SVE, the saved SVCR, or the save fp_type. This will leave the task in a consistent state, without potentially resurrecting stale FPSIMD state. A read of user_fpsimd_state should never fail unless the structure has been corrupted or the stack has been unmapped. Suggested-by: Will Deacon <will@kernel.org> Signed-off-by: Mark Rutland <mark.rutland@arm.com> Cc: Catalin Marinas <catalin.marinas@arm.com> Cc: Marc Zyngier <maz@kernel.org> Cc: Mark Brown <broonie@kernel.org> Cc: Will Deacon <will@kernel.org> Link: https://lore.kernel.org/r/20250508132644.1395904-5-mark.rutland@arm.com [will: Ensure read_fpsimd_context() returns negative error code or zero] Signed-off-by: Will Deacon <will@kernel.org>
1 parent b465ace commit be625d8

1 file changed

Lines changed: 29 additions & 28 deletions

File tree

arch/arm64/kernel/signal.c

Lines changed: 29 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -264,30 +264,40 @@ static int preserve_fpsimd_context(struct fpsimd_context __user *ctx)
264264
return err ? -EFAULT : 0;
265265
}
266266

267-
static int restore_fpsimd_context(struct user_ctxs *user)
267+
static int read_fpsimd_context(struct user_fpsimd_state *fpsimd,
268+
struct user_ctxs *user)
268269
{
269-
struct user_fpsimd_state fpsimd;
270-
int err = 0;
270+
int err;
271271

272272
/* check the size information */
273273
if (user->fpsimd_size != sizeof(struct fpsimd_context))
274274
return -EINVAL;
275275

276276
/* copy the FP and status/control registers */
277-
err = __copy_from_user(fpsimd.vregs, &(user->fpsimd->vregs),
278-
sizeof(fpsimd.vregs));
279-
__get_user_error(fpsimd.fpsr, &(user->fpsimd->fpsr), err);
280-
__get_user_error(fpsimd.fpcr, &(user->fpsimd->fpcr), err);
277+
err = __copy_from_user(fpsimd->vregs, &(user->fpsimd->vregs),
278+
sizeof(fpsimd->vregs));
279+
__get_user_error(fpsimd->fpsr, &(user->fpsimd->fpsr), err);
280+
__get_user_error(fpsimd->fpcr, &(user->fpsimd->fpcr), err);
281+
282+
return err ? -EFAULT : 0;
283+
}
284+
285+
static int restore_fpsimd_context(struct user_ctxs *user)
286+
{
287+
struct user_fpsimd_state fpsimd;
288+
int err;
289+
290+
err = read_fpsimd_context(&fpsimd, user);
291+
if (err)
292+
return err;
281293

282294
clear_thread_flag(TIF_SVE);
283295
current->thread.svcr &= ~SVCR_SM_MASK;
284296
current->thread.fp_type = FP_STATE_FPSIMD;
285297

286298
/* load the hardware registers from the fpsimd_state structure */
287-
if (!err)
288-
fpsimd_update_current_state(&fpsimd);
289-
290-
return err ? -EFAULT : 0;
299+
fpsimd_update_current_state(&fpsimd);
300+
return 0;
291301
}
292302

293303
static int preserve_fpmr_context(struct fpmr_context __user *ctx)
@@ -427,12 +437,8 @@ static int restore_sve_fpsimd_context(struct user_ctxs *user)
427437
* consistency and robustness, reject restoring streaming SVE state
428438
* without an SVE payload.
429439
*/
430-
if (!sm && user->sve_size == sizeof(*user->sve)) {
431-
clear_thread_flag(TIF_SVE);
432-
current->thread.svcr &= ~SVCR_SM_MASK;
433-
current->thread.fp_type = FP_STATE_FPSIMD;
434-
goto fpsimd_only;
435-
}
440+
if (!sm && user->sve_size == sizeof(*user->sve))
441+
return restore_fpsimd_context(user);
436442

437443
vq = sve_vq_from_vl(vl);
438444

@@ -458,19 +464,14 @@ static int restore_sve_fpsimd_context(struct user_ctxs *user)
458464
set_thread_flag(TIF_SVE);
459465
current->thread.fp_type = FP_STATE_SVE;
460466

461-
fpsimd_only:
462-
/* copy the FP and status/control registers */
463-
/* restore_sigframe() already checked that user->fpsimd != NULL. */
464-
err = __copy_from_user(fpsimd.vregs, user->fpsimd->vregs,
465-
sizeof(fpsimd.vregs));
466-
__get_user_error(fpsimd.fpsr, &user->fpsimd->fpsr, err);
467-
__get_user_error(fpsimd.fpcr, &user->fpsimd->fpcr, err);
467+
err = read_fpsimd_context(&fpsimd, user);
468+
if (err)
469+
return err;
468470

469-
/* load the hardware registers from the fpsimd_state structure */
470-
if (!err)
471-
fpsimd_update_current_state(&fpsimd);
471+
/* Merge the FPSIMD registers into the SVE state */
472+
fpsimd_update_current_state(&fpsimd);
472473

473-
return err ? -EFAULT : 0;
474+
return 0;
474475
}
475476

476477
#else /* ! CONFIG_ARM64_SVE */

0 commit comments

Comments
 (0)