summaryrefslogtreecommitdiff
path: root/arch/metag
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-03-29 08:55:25 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2017-03-29 08:55:25 -0700
commit72c33734b5fa8a788734ad2312a89b944589c5a0 (patch)
treef6e7aade79c95b3c655f288bc1745c1cf9750e2f /arch/metag
parentfe82203b63e598c34d96e846dea49679a726fc7a (diff)
parentd3805c546b275c8cc7d40f759d029ae92c7175f2 (diff)
Merge branch 'regset' (PTRACE_SETREGSET data leakage)
Merge PTRACE_SETREGSET leakage fixes from Dave Martin: "This series is the collection of fixes I proposed on this topic, that have not yet appeared upstream or in the stable branches, The issue can leak kernel stack, but doesn't appear to allow userspace to attack the kernel directly. The affected architectures are c6x, h8300, metag, mips and sparc. [ Mark Salter points out that c6x has no MMU or other mechanism to prevent userspace access to kernel code or data on c6x, but it doesn't hurt to clean that case up too. ] The bugs arise from use of user_regset_copyin(). Users of user_regset_copyin() can work in one of two ways: 1) Copy directly to thread_struct or equivalent. (This seems to be the design assumption of the regset API, and is the most common approach.) 2) Copy to a local variable and then transfer to thread_struct. (A significant minority of cases.) Buggy code typically involves approach 2" * emailed patches from Dave Martin <Dave.Martin@arm.com>: sparc/ptrace: Preserve previous registers for short regset write mips/ptrace: Preserve previous registers for short regset write metag/ptrace: Reject partial NT_METAG_RPIPE writes metag/ptrace: Provide default TXSTATUS for short NT_PRSTATUS metag/ptrace: Preserve previous registers for short regset write h8300/ptrace: Fix incorrect register transfer count c6x/ptrace: Remove useless PTRACE_SETREGSET implementation
Diffstat (limited to 'arch/metag')
-rw-r--r--arch/metag/kernel/ptrace.c19
1 files changed, 15 insertions, 4 deletions
diff --git a/arch/metag/kernel/ptrace.c b/arch/metag/kernel/ptrace.c
index 5fd16ee5280c..e615603a4b0a 100644
--- a/arch/metag/kernel/ptrace.c
+++ b/arch/metag/kernel/ptrace.c
@@ -26,6 +26,16 @@
* user_regset definitions.
*/
+static unsigned long user_txstatus(const struct pt_regs *regs)
+{
+ unsigned long data = (unsigned long)regs->ctx.Flags;
+
+ if (regs->ctx.SaveMask & TBICTX_CBUF_BIT)
+ data |= USER_GP_REGS_STATUS_CATCH_BIT;
+
+ return data;
+}
+
int metag_gp_regs_copyout(const struct pt_regs *regs,
unsigned int pos, unsigned int count,
void *kbuf, void __user *ubuf)
@@ -64,9 +74,7 @@ int metag_gp_regs_copyout(const struct pt_regs *regs,
if (ret)
goto out;
/* TXSTATUS */
- data = (unsigned long)regs->ctx.Flags;
- if (regs->ctx.SaveMask & TBICTX_CBUF_BIT)
- data |= USER_GP_REGS_STATUS_CATCH_BIT;
+ data = user_txstatus(regs);
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
&data, 4*25, 4*26);
if (ret)
@@ -121,6 +129,7 @@ int metag_gp_regs_copyin(struct pt_regs *regs,
if (ret)
goto out;
/* TXSTATUS */
+ data = user_txstatus(regs);
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
&data, 4*25, 4*26);
if (ret)
@@ -246,6 +255,8 @@ int metag_rp_state_copyin(struct pt_regs *regs,
unsigned long long *ptr;
int ret, i;
+ if (count < 4*13)
+ return -EINVAL;
/* Read the entire pipeline before making any changes */
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
&rp, 0, 4*13);
@@ -305,7 +316,7 @@ static int metag_tls_set(struct task_struct *target,
const void *kbuf, const void __user *ubuf)
{
int ret;
- void __user *tls;
+ void __user *tls = target->thread.tls_ptr;
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &tls, 0, -1);
if (ret)