diff options
author | Andy Lutomirski <luto@kernel.org> | 2021-06-12 19:08:23 -0700 |
---|---|---|
committer | Andy Lutomirski <luto@kernel.org> | 2021-06-12 19:10:43 -0700 |
commit | 06da31459fc35c080c629f1e86f9319cc0b0300b (patch) | |
tree | db70a64aed0d3736698914d3d02f213a58d5b627 | |
parent | 77af183be38ded859753c190e373e9cebe0cda50 (diff) | |
download | linux-x86/fpu.tar.gz |
x86/fpu: Clean up fpregs_set()x86/fpu
fpregs_set() had unnecessary complexity to support short or nonzero-offset
writes and to handle the case in which a copy from userspace overwrites
some of the target buffer and then fails. Support for partial writes is
useless -- just require that the write have offset 0 and the correct size,
and copy into a temporary kernel buffer to avoid clobbering the state if
the user access fails.
Signed-off-by: Andy Lutomirski <luto@kernel.org>
-rw-r--r-- | arch/x86/kernel/fpu/regset.c | 23 |
1 files changed, 12 insertions, 11 deletions
diff --git a/arch/x86/kernel/fpu/regset.c b/arch/x86/kernel/fpu/regset.c index 5e6b2049cff2a1..fb0bebbec46768 100644 --- a/arch/x86/kernel/fpu/regset.c +++ b/arch/x86/kernel/fpu/regset.c @@ -338,23 +338,23 @@ int fpregs_set(struct task_struct *target, const struct user_regset *regset, struct user_i387_ia32_struct env; int ret; - fpu__prepare_write(fpu); - fpstate_sanitize_legacy(fpu); + /* No funny business with partial or oversized writes is permitted. */ + if (pos != 0 || count != sizeof(struct user_i387_ia32_struct)) + return -EINVAL; if (!boot_cpu_has(X86_FEATURE_FPU)) return fpregs_soft_set(target, regset, pos, count, kbuf, ubuf); - if (!boot_cpu_has(X86_FEATURE_FXSR)) - return user_regset_copyin(&pos, &count, &kbuf, &ubuf, - &fpu->state.fsave, 0, - -1); + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &env, 0, -1); + if (ret) + return ret; - if (pos > 0 || count < sizeof(env)) - convert_from_fxsr(&env, target); + fpu__prepare_write(fpu); - ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &env, 0, -1); - if (!ret) + if (boot_cpu_has(X86_FEATURE_FXSR)) convert_to_fxsr(&target->thread.fpu.state.fxsave, &env); + else + memcpy(&target->thread.fpu.state.fsave, &env, sizeof(env)); /* * update the header bit in the xsave header, indicating the @@ -362,7 +362,8 @@ int fpregs_set(struct task_struct *target, const struct user_regset *regset, */ if (boot_cpu_has(X86_FEATURE_XSAVE)) fpu->state.xsave.header.xfeatures |= XFEATURE_MASK_FP; - return ret; + + return 0; } #endif /* CONFIG_X86_32 || CONFIG_IA32_EMULATION */ |