51 lines
1.9 KiB
Diff
51 lines
1.9 KiB
Diff
From: Paul Burton <paul.burton@imgtec.com>
|
|
Date: Tue, 22 Jul 2014 14:21:21 +0100
|
|
Subject: MIPS: prevent user from setting FCSR cause bits
|
|
Origin: https://git.kernel.org/linus/b1442d39fac2fcfbe6a4814979020e993ca59c9e
|
|
|
|
If one or more matching FCSR cause & enable bits are set in saved thread
|
|
context then when that context is restored the kernel will take an FP
|
|
exception. This is of course undesirable and considered an oops, leading
|
|
to the kernel writing a backtrace to the console and potentially
|
|
rebooting depending upon the configuration. Thus the kernel avoids this
|
|
situation by clearing the cause bits of the FCSR register when handling
|
|
FP exceptions and after emulating FP instructions.
|
|
|
|
However the kernel does not prevent userland from setting arbitrary FCSR
|
|
cause & enable bits via ptrace, using either the PTRACE_POKEUSR or
|
|
PTRACE_SETFPREGS requests. This means userland can trivially cause the
|
|
kernel to oops on any system with an FPU. Prevent this from happening
|
|
by clearing the cause bits when writing to the saved FCSR context via
|
|
ptrace.
|
|
|
|
This problem appears to exist at least back to the beginning of the git
|
|
era in the PTRACE_POKEUSR case.
|
|
|
|
Signed-off-by: Paul Burton <paul.burton@imgtec.com>
|
|
Cc: stable@vger.kernel.org
|
|
Patchwork: http://patchwork.linux-mips.org/patch/7438/
|
|
Signed-off-by: James Hogan <james.hogan@imgtec.com>
|
|
---
|
|
arch/mips/kernel/ptrace.c | 3 ++-
|
|
1 file changed, 2 insertions(+), 1 deletion(-)
|
|
|
|
--- a/arch/mips/kernel/ptrace.c
|
|
+++ b/arch/mips/kernel/ptrace.c
|
|
@@ -151,6 +151,7 @@ int ptrace_setfpregs(struct task_struct
|
|
}
|
|
|
|
__get_user(child->thread.fpu.fcr31, data + 64);
|
|
+ child->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X;
|
|
|
|
/* FIR may not be written. */
|
|
|
|
@@ -565,7 +566,7 @@ long arch_ptrace(struct task_struct *chi
|
|
break;
|
|
#endif
|
|
case FPC_CSR:
|
|
- child->thread.fpu.fcr31 = data;
|
|
+ child->thread.fpu.fcr31 = data & ~FPU_CSR_ALL_X;
|
|
break;
|
|
case DSP_BASE ... DSP_BASE + 5: {
|
|
dspreg_t *dregs;
|