diff options
author | Paul Mackerras <paulus@samba.org> | 2006-06-09 13:02:59 +1000 |
---|---|---|
committer | Chris Wright <chrisw@sous-sol.org> | 2006-06-20 01:54:52 -0700 |
commit | ad325de56677938d8c58b376e1d7813b50527263 (patch) | |
tree | 16474885b5902f99f60ce6790dd3b4fe30747259 | |
parent | a3a5ab881318c2d7b6df3d176cdabacd1d16e5e6 (diff) |
[PATCH] powerpc: Fix machine check problem on 32-bit kernels (CVE-2006-2448)
This fixes a bug found by Dave Jones that means that it is possible
for userspace to provoke a machine check on 32-bit kernels. This
also fixes a couple of other places where I found similar problems
by inspection.
Signed-off-by: Paul Mackerras <paulus@samba.org>
Signed-off-by: Chris Wright <chrisw@sous-sol.org>
-rw-r--r-- | arch/powerpc/kernel/signal_32.c | 11 | ||||
-rw-r--r-- | arch/powerpc/kernel/signal_64.c | 2 |
2 files changed, 12 insertions, 1 deletions
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c index d7a4e814974d..7fb9ff6538bc 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c @@ -802,10 +802,13 @@ static int do_setcontext(struct ucontext __user *ucp, struct pt_regs *regs, int if (__get_user(cmcp, &ucp->uc_regs)) return -EFAULT; mcp = (struct mcontext __user *)(u64)cmcp; + /* no need to check access_ok(mcp), since mcp < 4GB */ } #else if (__get_user(mcp, &ucp->uc_regs)) return -EFAULT; + if (!access_ok(VERIFY_READ, mcp, sizeof(*mcp))) + return -EFAULT; #endif restore_sigmask(&set); if (restore_user_regs(regs, mcp, sig)) @@ -907,13 +910,14 @@ int sys_debug_setcontext(struct ucontext __user *ctx, { struct sig_dbg_op op; int i; + unsigned char tmp; unsigned long new_msr = regs->msr; #if defined(CONFIG_4xx) || defined(CONFIG_BOOKE) unsigned long new_dbcr0 = current->thread.dbcr0; #endif for (i=0; i<ndbg; i++) { - if (__copy_from_user(&op, dbg, sizeof(op))) + if (copy_from_user(&op, dbg + i, sizeof(op))) return -EFAULT; switch (op.dbg_type) { case SIG_DBG_SINGLE_STEPPING: @@ -958,6 +962,11 @@ int sys_debug_setcontext(struct ucontext __user *ctx, current->thread.dbcr0 = new_dbcr0; #endif + if (!access_ok(VERIFY_READ, ctx, sizeof(*ctx)) + || __get_user(tmp, (u8 __user *) ctx) + || __get_user(tmp, (u8 __user *) (ctx + 1) - 1)) + return -EFAULT; + /* * If we get a fault copying the context into the kernel's * image of the user's registers, we can't just return -EFAULT diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c index 096dfdc7890e..f1715f3023fe 100644 --- a/arch/powerpc/kernel/signal_64.c +++ b/arch/powerpc/kernel/signal_64.c @@ -183,6 +183,8 @@ static long restore_sigcontext(struct pt_regs *regs, sigset_t *set, int sig, err |= __get_user(msr, &sc->gp_regs[PT_MSR]); if (err) return err; + if (v_regs && !access_ok(VERIFY_READ, v_regs, 34 * sizeof(vector128))) + return -EFAULT; /* Copy 33 vec registers (vr0..31 and vscr) from the stack */ if (v_regs != 0 && (msr & MSR_VEC) != 0) err |= __copy_from_user(current->thread.vr, v_regs, |