Commit ac9ad83b authored by Paul Burton's avatar Paul Burton Committed by Ralf Baechle

MIPS: prevent FP context set via ptrace being discarded

If a ptracee has not used the FPU and the ptracer sets its FP context
using PTRACE_POKEUSR, PTRACE_SETFPREGS or PTRACE_SETREGSET then that
context will be discarded upon either the ptracee using the FPU or a
further write to the context via ptrace. Prevent this loss by recording
that the task has "used" math once its FP context has been written to.
The context initialisation code that was present for the PTRACE_POKEUSR
case is reused for the other 2 cases to provide consistent behaviour
for the different ptrace requests.
Signed-off-by: default avatarPaul Burton <paul.burton@imgtec.com>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/9166/Signed-off-by: default avatarRalf Baechle <ralf@linux-mips.org>
parent ad70c13a
...@@ -46,6 +46,26 @@ ...@@ -46,6 +46,26 @@
#define CREATE_TRACE_POINTS #define CREATE_TRACE_POINTS
#include <trace/events/syscalls.h> #include <trace/events/syscalls.h>
static void init_fp_ctx(struct task_struct *target)
{
/* If FP has been used then the target already has context */
if (tsk_used_math(target))
return;
/* Begin with data registers set to all 1s... */
memset(&target->thread.fpu.fpr, ~0, sizeof(target->thread.fpu.fpr));
/* ...and FCSR zeroed */
target->thread.fpu.fcr31 = 0;
/*
* Record that the target has "used" math, such that the context
* just initialised, and any modifications made by the caller,
* aren't discarded.
*/
set_stopped_child_used_math(target);
}
/* /*
* Called by kernel/ptrace.c when detaching.. * Called by kernel/ptrace.c when detaching..
* *
...@@ -142,6 +162,7 @@ int ptrace_setfpregs(struct task_struct *child, __u32 __user *data) ...@@ -142,6 +162,7 @@ int ptrace_setfpregs(struct task_struct *child, __u32 __user *data)
if (!access_ok(VERIFY_READ, data, 33 * 8)) if (!access_ok(VERIFY_READ, data, 33 * 8))
return -EIO; return -EIO;
init_fp_ctx(child);
fregs = get_fpu_regs(child); fregs = get_fpu_regs(child);
for (i = 0; i < 32; i++) { for (i = 0; i < 32; i++) {
...@@ -439,6 +460,8 @@ static int fpr_set(struct task_struct *target, ...@@ -439,6 +460,8 @@ static int fpr_set(struct task_struct *target,
/* XXX fcr31 */ /* XXX fcr31 */
init_fp_ctx(target);
if (sizeof(target->thread.fpu.fpr[i]) == sizeof(elf_fpreg_t)) if (sizeof(target->thread.fpu.fpr[i]) == sizeof(elf_fpreg_t))
return user_regset_copyin(&pos, &count, &kbuf, &ubuf, return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
&target->thread.fpu, &target->thread.fpu,
...@@ -660,12 +683,7 @@ long arch_ptrace(struct task_struct *child, long request, ...@@ -660,12 +683,7 @@ long arch_ptrace(struct task_struct *child, long request,
case FPR_BASE ... FPR_BASE + 31: { case FPR_BASE ... FPR_BASE + 31: {
union fpureg *fregs = get_fpu_regs(child); union fpureg *fregs = get_fpu_regs(child);
if (!tsk_used_math(child)) { init_fp_ctx(child);
/* FP not yet used */
memset(&child->thread.fpu, ~0,
sizeof(child->thread.fpu));
child->thread.fpu.fcr31 = 0;
}
#ifdef CONFIG_32BIT #ifdef CONFIG_32BIT
if (test_thread_flag(TIF_32BIT_FPREGS)) { if (test_thread_flag(TIF_32BIT_FPREGS)) {
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment