FROMGIT: 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> (cherry picked from commit be625d803c3bbfa9652697eb57589fe6f2f24b89 https://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git for-next/sme-fixes) Bug: 393087661 Signed-off-by: Will Deacon <willdeacon@google.com> Change-Id: Idf13bb79dbb3dfe64c237badb8b6eabb02fa2361
This commit is contained in:
committed by
Will Deacon
parent
bed5006f4a
commit
b2853208b1
@@ -264,30 +264,40 @@ static int preserve_fpsimd_context(struct fpsimd_context __user *ctx)
|
||||
return err ? -EFAULT : 0;
|
||||
}
|
||||
|
||||
static int restore_fpsimd_context(struct user_ctxs *user)
|
||||
static int read_fpsimd_context(struct user_fpsimd_state *fpsimd,
|
||||
struct user_ctxs *user)
|
||||
{
|
||||
struct user_fpsimd_state fpsimd;
|
||||
int err = 0;
|
||||
int err;
|
||||
|
||||
/* check the size information */
|
||||
if (user->fpsimd_size != sizeof(struct fpsimd_context))
|
||||
return -EINVAL;
|
||||
|
||||
/* copy the FP and status/control registers */
|
||||
err = __copy_from_user(fpsimd.vregs, &(user->fpsimd->vregs),
|
||||
sizeof(fpsimd.vregs));
|
||||
__get_user_error(fpsimd.fpsr, &(user->fpsimd->fpsr), err);
|
||||
__get_user_error(fpsimd.fpcr, &(user->fpsimd->fpcr), err);
|
||||
err = __copy_from_user(fpsimd->vregs, &(user->fpsimd->vregs),
|
||||
sizeof(fpsimd->vregs));
|
||||
__get_user_error(fpsimd->fpsr, &(user->fpsimd->fpsr), err);
|
||||
__get_user_error(fpsimd->fpcr, &(user->fpsimd->fpcr), err);
|
||||
|
||||
return err ? -EFAULT : 0;
|
||||
}
|
||||
|
||||
static int restore_fpsimd_context(struct user_ctxs *user)
|
||||
{
|
||||
struct user_fpsimd_state fpsimd;
|
||||
int err;
|
||||
|
||||
err = read_fpsimd_context(&fpsimd, user);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
clear_thread_flag(TIF_SVE);
|
||||
current->thread.svcr &= ~SVCR_SM_MASK;
|
||||
current->thread.fp_type = FP_STATE_FPSIMD;
|
||||
|
||||
/* load the hardware registers from the fpsimd_state structure */
|
||||
if (!err)
|
||||
fpsimd_update_current_state(&fpsimd);
|
||||
|
||||
return err ? -EFAULT : 0;
|
||||
fpsimd_update_current_state(&fpsimd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int preserve_fpmr_context(struct fpmr_context __user *ctx)
|
||||
@@ -427,12 +437,8 @@ static int restore_sve_fpsimd_context(struct user_ctxs *user)
|
||||
* consistency and robustness, reject restoring streaming SVE state
|
||||
* without an SVE payload.
|
||||
*/
|
||||
if (!sm && user->sve_size == sizeof(*user->sve)) {
|
||||
clear_thread_flag(TIF_SVE);
|
||||
current->thread.svcr &= ~SVCR_SM_MASK;
|
||||
current->thread.fp_type = FP_STATE_FPSIMD;
|
||||
goto fpsimd_only;
|
||||
}
|
||||
if (!sm && user->sve_size == sizeof(*user->sve))
|
||||
return restore_fpsimd_context(user);
|
||||
|
||||
vq = sve_vq_from_vl(vl);
|
||||
|
||||
@@ -458,19 +464,14 @@ static int restore_sve_fpsimd_context(struct user_ctxs *user)
|
||||
set_thread_flag(TIF_SVE);
|
||||
current->thread.fp_type = FP_STATE_SVE;
|
||||
|
||||
fpsimd_only:
|
||||
/* copy the FP and status/control registers */
|
||||
/* restore_sigframe() already checked that user->fpsimd != NULL. */
|
||||
err = __copy_from_user(fpsimd.vregs, user->fpsimd->vregs,
|
||||
sizeof(fpsimd.vregs));
|
||||
__get_user_error(fpsimd.fpsr, &user->fpsimd->fpsr, err);
|
||||
__get_user_error(fpsimd.fpcr, &user->fpsimd->fpcr, err);
|
||||
err = read_fpsimd_context(&fpsimd, user);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* load the hardware registers from the fpsimd_state structure */
|
||||
if (!err)
|
||||
fpsimd_update_current_state(&fpsimd);
|
||||
/* Merge the FPSIMD registers into the SVE state */
|
||||
fpsimd_update_current_state(&fpsimd);
|
||||
|
||||
return err ? -EFAULT : 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else /* ! CONFIG_ARM64_SVE */
|
||||
|
||||
Reference in New Issue
Block a user