| From dc24d0edf33c3e15099688b6bbdf7bdc24bf6e91 Mon Sep 17 00:00:00 2001 |
| From: "Maciej W. Rozycki" <macro@mips.com> |
| Date: Mon, 11 Dec 2017 22:52:15 +0000 |
| Subject: MIPS: Guard against any partial write attempt with PTRACE_SETREGSET |
| |
| From: Maciej W. Rozycki <macro@mips.com> |
| |
| commit dc24d0edf33c3e15099688b6bbdf7bdc24bf6e91 upstream. |
| |
| Complement commit d614fd58a283 ("mips/ptrace: Preserve previous |
| registers for short regset write") and ensure that no partial register |
| write attempt is made with PTRACE_SETREGSET, as we do not preinitialize |
| any temporaries used to hold incoming register data and consequently |
| random data could be written. |
| |
| It is the responsibility of the caller, such as `ptrace_regset', to |
| arrange for writes to span whole registers only, so here we only assert |
| that it has indeed happened. |
| |
| Signed-off-by: Maciej W. Rozycki <macro@mips.com> |
| Fixes: 72b22bbad1e7 ("MIPS: Don't assume 64-bit FP registers for FP regset") |
| Cc: James Hogan <james.hogan@mips.com> |
| Cc: Paul Burton <Paul.Burton@mips.com> |
| Cc: Alex Smith <alex@alex-smith.me.uk> |
| Cc: Dave Martin <Dave.Martin@arm.com> |
| Cc: linux-mips@linux-mips.org |
| Cc: linux-kernel@vger.kernel.org |
| Patchwork: https://patchwork.linux-mips.org/patch/17926/ |
| Signed-off-by: Ralf Baechle <ralf@linux-mips.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| arch/mips/kernel/ptrace.c | 12 +++++++++++- |
| 1 file changed, 11 insertions(+), 1 deletion(-) |
| |
| --- a/arch/mips/kernel/ptrace.c |
| +++ b/arch/mips/kernel/ptrace.c |
| @@ -497,7 +497,15 @@ static int fpr_set_msa(struct task_struc |
| return 0; |
| } |
| |
| -/* Copy the supplied NT_PRFPREG buffer to the floating-point context. */ |
| +/* |
| + * Copy the supplied NT_PRFPREG buffer to the floating-point context. |
| + * |
| + * We optimize for the case where `count % sizeof(elf_fpreg_t) == 0', |
| + * which is supposed to have been guaranteed by the kernel before |
| + * calling us, e.g. in `ptrace_regset'. We enforce that requirement, |
| + * so that we can safely avoid preinitializing temporaries for |
| + * partial register writes. |
| + */ |
| static int fpr_set(struct task_struct *target, |
| const struct user_regset *regset, |
| unsigned int pos, unsigned int count, |
| @@ -505,6 +513,8 @@ static int fpr_set(struct task_struct *t |
| { |
| int err; |
| |
| + BUG_ON(count % sizeof(elf_fpreg_t)); |
| + |
| /* XXX fcr31 */ |
| |
| if (sizeof(target->thread.fpu.fpr[0]) == sizeof(elf_fpreg_t)) |