Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src Calling _lwp_create() with a bogus ucontext could trigger a ...



details:   https://anonhg.NetBSD.org/src/rev/cc06828721a3
branches:  trunk
changeset: 779346:cc06828721a3
user:      martin <martin%NetBSD.org@localhost>
date:      Mon May 21 14:15:16 2012 +0000

description:
Calling _lwp_create() with a bogus ucontext could trigger a kernel
assertion failure (and thus a crash in DIAGNOSTIC kernels). Independently
discovered by YAMAMOTO Takashi and Joel Sing.

To avoid this, introduce a cpu_mcontext_validate() function and move all
sanity checks from cpu_setmcontext() there. Also untangle the netbsd32
compat mess slightly and add a cpu_mcontext32_validate() cousin there.

Add an exhaustive atf test case, based partly on code from Joel Sing.

Should finally fix the remaining open part of PR kern/43903.

diffstat:

 distrib/sets/lists/tests/mi                 |    4 +-
 lib/libc/sys/_lwp_create.2                  |   11 +-
 sys/arch/alpha/alpha/machdep.c              |   22 +-
 sys/arch/amd64/amd64/machdep.c              |    9 +-
 sys/arch/amd64/amd64/netbsd32_machdep.c     |   11 +-
 sys/arch/amd64/amd64/process_machdep.c      |    6 +-
 sys/arch/amd64/include/mcontext.h           |    6 +-
 sys/arch/arm/arm/sig_machdep.c              |   22 +-
 sys/arch/hppa/hppa/hppa_machdep.c           |   76 ++++---
 sys/arch/i386/i386/machdep.c                |   43 +++-
 sys/arch/m68k/m68k/sig_machdep.c            |   24 ++-
 sys/arch/mips/mips/cpu_subr.c               |   18 +-
 sys/arch/mips/mips/netbsd32_machdep.c       |   18 +-
 sys/arch/powerpc/powerpc/sig_machdep.c      |   15 +-
 sys/arch/sh3/sh3/sh3_machdep.c              |   22 ++-
 sys/arch/sparc/sparc/machdep.c              |   37 ++-
 sys/arch/sparc64/sparc64/machdep.c          |   35 ++-
 sys/arch/sparc64/sparc64/netbsd32_machdep.c |   36 ++-
 sys/arch/vax/vax/machdep.c                  |   26 ++-
 sys/compat/netbsd32/netbsd32_lwp.c          |   42 +++-
 sys/compat/sys/ucontext.h                   |    3 +-
 sys/kern/sys_lwp.c                          |   84 +++++---
 sys/sys/lwp.h                               |    3 +-
 sys/sys/ucontext.h                          |    3 +-
 tests/lib/libc/sys/Makefile                 |    3 +-
 tests/lib/libc/sys/t_lwp_create.c           |  247 ++++++++++++++++++++++++++++
 26 files changed, 642 insertions(+), 184 deletions(-)

diffs (truncated from 1541 to 300 lines):

diff -r 122f01689cfa -r cc06828721a3 distrib/sets/lists/tests/mi
--- a/distrib/sets/lists/tests/mi       Mon May 21 08:14:58 2012 +0000
+++ b/distrib/sets/lists/tests/mi       Mon May 21 14:15:16 2012 +0000
@@ -1,4 +1,4 @@
-# $NetBSD: mi,v 1.468 2012/05/18 15:25:25 jruoho Exp $
+# $NetBSD: mi,v 1.469 2012/05/21 14:15:16 martin Exp $
 #
 # Note: don't delete entries from here - mark them as "obsolete" instead.
 #
@@ -545,6 +545,7 @@
 ./usr/libdata/debug/usr/tests/lib/libc/sys/t_link.debug                        tests-lib-debug         debug,atf
 ./usr/libdata/debug/usr/tests/lib/libc/sys/t_listen.debug              tests-lib-debug         debug,atf
 ./usr/libdata/debug/usr/tests/lib/libc/sys/t_lwp_ctl.debug             tests-lib-debug         debug,atf
+./usr/libdata/debug/usr/tests/lib/libc/sys/t_lwp_create.debug          tests-lib-debug         debug,atf
 ./usr/libdata/debug/usr/tests/lib/libc/sys/t_mincore.debug             tests-lib-debug         debug,atf
 ./usr/libdata/debug/usr/tests/lib/libc/sys/t_mkdir.debug               tests-lib-debug         debug,atf
 ./usr/libdata/debug/usr/tests/lib/libc/sys/t_mkfifo.debug              tests-lib-debug         debug,atf
@@ -2444,6 +2445,7 @@
 ./usr/tests/lib/libc/sys/t_link                        tests-lib-tests         atf
 ./usr/tests/lib/libc/sys/t_listen              tests-lib-tests         atf
 ./usr/tests/lib/libc/sys/t_lwp_ctl             tests-lib-tests         atf
+./usr/tests/lib/libc/sys/t_lwp_create          tests-lib-tests         atf
 ./usr/tests/lib/libc/sys/t_mincore             tests-lib-tests         atf
 ./usr/tests/lib/libc/sys/t_mkdir               tests-lib-tests         atf
 ./usr/tests/lib/libc/sys/t_mkfifo              tests-lib-tests         atf
diff -r 122f01689cfa -r cc06828721a3 lib/libc/sys/_lwp_create.2
--- a/lib/libc/sys/_lwp_create.2        Mon May 21 08:14:58 2012 +0000
+++ b/lib/libc/sys/_lwp_create.2        Mon May 21 14:15:16 2012 +0000
@@ -1,4 +1,4 @@
-.\"    $NetBSD: _lwp_create.2,v 1.4 2008/04/30 13:10:51 martin Exp $
+.\"    $NetBSD: _lwp_create.2,v 1.5 2012/05/21 14:15:16 martin Exp $
 .\"
 .\" Copyright (c) 2003 The NetBSD Foundation, Inc.
 .\" All rights reserved.
@@ -47,6 +47,10 @@
 .Fa context
 argument specifies the initial execution context for the new LWP including
 signal mask, stack, and machine registers.
+If this context specifies invalid register values (for example priviledge
+escalation by setting machine dependend bits forbidden for user processes),
+or does not specify cpu register values (uc_flags does not have the
+_UC_CPU bit set), the call will fail and errno will be set to EINVAL.
 .Pp
 The following flags affect the creation of the new LWP:
 .Bl -tag -width LWP_SUSPENDED
@@ -70,7 +74,8 @@
 Upon successful completion,
 .Fn _lwp_create
 returns a value of 0.
-Otherwise, an error code is returned to indicate the error.
+Otherwise, a value of -1 is returned and errno is set to one of the values
+documented below.
 .Sh ERRORS
 .Fn _lwp_create
 will fail and no LWP will be created if:
@@ -87,6 +92,8 @@
 or
 .Fa new_lwp
 is outside the process's allocated address space.
+.It Bq Er EINVAL
+The ucontext_t passed is invalid.
 .El
 .Sh SEE ALSO
 .Xr _lwp_continue 2 ,
diff -r 122f01689cfa -r cc06828721a3 sys/arch/alpha/alpha/machdep.c
--- a/sys/arch/alpha/alpha/machdep.c    Mon May 21 08:14:58 2012 +0000
+++ b/sys/arch/alpha/alpha/machdep.c    Mon May 21 14:15:16 2012 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: machdep.c,v 1.338 2012/02/21 17:39:17 para Exp $ */
+/* $NetBSD: machdep.c,v 1.339 2012/05/21 14:15:16 martin Exp $ */
 
 /*-
  * Copyright (c) 1998, 1999, 2000 The NetBSD Foundation, Inc.
@@ -68,7 +68,7 @@
 
 #include <sys/cdefs.h>                 /* RCS ID & Copyright macro defns */
 
-__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.338 2012/02/21 17:39:17 para Exp $");
+__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.339 2012/05/21 14:15:16 martin Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -1803,6 +1803,17 @@
        }
 }
 
+int
+cpu_mcontext_validate(struct lwp *l, const mcontext_t *mcp)
+{
+       const __greg_t *gr = mcp->__gregs;
+
+       if ((gr[_REG_PS] & ALPHA_PSL_USERSET) != ALPHA_PSL_USERSET ||
+           (gr[_REG_PS] & ALPHA_PSL_USERCLR) != 0)
+               return EINVAL;
+
+       return 0;
+}
 
 int
 cpu_setmcontext(struct lwp *l, const mcontext_t *mcp, unsigned int flags)
@@ -1810,13 +1821,14 @@
        struct trapframe *frame = l->l_md.md_tf;
        struct pcb *pcb = lwp_getpcb(l);
        const __greg_t *gr = mcp->__gregs;
+       int error;
 
        /* Restore register context, if any. */
        if (flags & _UC_CPU) {
                /* Check for security violations first. */
-               if ((gr[_REG_PS] & ALPHA_PSL_USERSET) != ALPHA_PSL_USERSET ||
-                   (gr[_REG_PS] & ALPHA_PSL_USERCLR) != 0)
-                       return (EINVAL);
+               error = cpu_mcontext_validate(l, mcp);
+               if (error)
+                       return error;
 
                regtoframe((const struct reg *)gr, l->l_md.md_tf);
                if (l == curlwp)
diff -r 122f01689cfa -r cc06828721a3 sys/arch/amd64/amd64/machdep.c
--- a/sys/arch/amd64/amd64/machdep.c    Mon May 21 08:14:58 2012 +0000
+++ b/sys/arch/amd64/amd64/machdep.c    Mon May 21 14:15:16 2012 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: machdep.c,v 1.182 2012/04/29 21:54:51 christos Exp $   */
+/*     $NetBSD: machdep.c,v 1.183 2012/05/21 14:15:17 martin Exp $     */
 
 /*-
  * Copyright (c) 1996, 1997, 1998, 2000, 2006, 2007, 2008, 2011
@@ -111,7 +111,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.182 2012/04/29 21:54:51 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.183 2012/05/21 14:15:17 martin Exp $");
 
 /* #define XENDEBUG_LOW  */
 
@@ -2011,7 +2011,7 @@
        int64_t rflags;
 
        if ((flags & _UC_CPU) != 0) {
-               error = check_mcontext(l, mcp, tf);
+               error = cpu_mcontext_validate(l, mcp);
                if (error != 0)
                        return error;
                /*
@@ -2068,13 +2068,14 @@
 }
 
 int
-check_mcontext(struct lwp *l, const mcontext_t *mcp, struct trapframe *tf)
+cpu_mcontext_validate(struct lwp *l, const mcontext_t *mcp)
 {
        const __greg_t *gr;
        uint16_t sel;
        int error;
        struct pmap *pmap = l->l_proc->p_vmspace->vm_map.pmap;
        struct proc *p = l->l_proc;
+       struct trapframe *tf = l->l_md.md_regs;
 
        gr = mcp->__gregs;
 
diff -r 122f01689cfa -r cc06828721a3 sys/arch/amd64/amd64/netbsd32_machdep.c
--- a/sys/arch/amd64/amd64/netbsd32_machdep.c   Mon May 21 08:14:58 2012 +0000
+++ b/sys/arch/amd64/amd64/netbsd32_machdep.c   Mon May 21 14:15:16 2012 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: netbsd32_machdep.c,v 1.75 2012/02/19 21:06:01 rmind Exp $      */
+/*     $NetBSD: netbsd32_machdep.c,v 1.76 2012/05/21 14:15:17 martin Exp $     */
 
 /*
  * Copyright (c) 2001 Wasabi Systems, Inc.
@@ -36,7 +36,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: netbsd32_machdep.c,v 1.75 2012/02/19 21:06:01 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: netbsd32_machdep.c,v 1.76 2012/05/21 14:15:17 martin Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_compat_netbsd.h"
@@ -94,7 +94,6 @@
 #endif
 
 static int check_sigcontext32(struct lwp *, const struct netbsd32_sigcontext *);
-static int check_mcontext32(struct lwp *, const mcontext32_t *);
 
 #ifdef EXEC_AOUT
 /*
@@ -834,7 +833,7 @@
                /*
                 * Check for security violations.
                 */
-               error = check_mcontext32(l, mcp);
+               error = cpu_mcontext32_validate(l, mcp);
                if (error != 0)
                        return error;
 
@@ -984,8 +983,8 @@
        return 0;
 }
 
-static int
-check_mcontext32(struct lwp *l, const mcontext32_t *mcp)
+int
+cpu_mcontext32_validate(struct lwp *l, const mcontext32_t *mcp)
 {
        const __greg32_t *gr;
        struct trapframe *tf;
diff -r 122f01689cfa -r cc06828721a3 sys/arch/amd64/amd64/process_machdep.c
--- a/sys/arch/amd64/amd64/process_machdep.c    Mon May 21 08:14:58 2012 +0000
+++ b/sys/arch/amd64/amd64/process_machdep.c    Mon May 21 14:15:16 2012 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: process_machdep.c,v 1.19 2011/12/20 13:17:05 jmcneill Exp $    */
+/*     $NetBSD: process_machdep.c,v 1.20 2012/05/21 14:15:17 martin Exp $      */
 
 /*-
  * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
@@ -53,7 +53,7 @@
 
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: process_machdep.c,v 1.19 2011/12/20 13:17:05 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: process_machdep.c,v 1.20 2012/05/21 14:15:17 martin Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -146,7 +146,7 @@
         * Note that struct regs is compatible with
         * the __gregs array in mcontext_t.
         */
-       error = check_mcontext(l, (const mcontext_t *)regs, tf);
+       error = cpu_mcontext_validate(l, (const mcontext_t *)regs);
        if (error != 0)
                return error;
 
diff -r 122f01689cfa -r cc06828721a3 sys/arch/amd64/include/mcontext.h
--- a/sys/arch/amd64/include/mcontext.h Mon May 21 08:14:58 2012 +0000
+++ b/sys/arch/amd64/include/mcontext.h Mon May 21 14:15:16 2012 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: mcontext.h,v 1.14 2011/02/25 14:07:12 joerg Exp $      */
+/*     $NetBSD: mcontext.h,v 1.15 2012/05/21 14:15:17 martin Exp $     */
 
 /*-
  * Copyright (c) 1999 The NetBSD Foundation, Inc.
@@ -156,10 +156,6 @@
 #define        _UC_MACHINE32_PAD       4
 #define        __UCONTEXT32_SIZE       776
 
-struct trapframe;
-struct lwp;
-int check_mcontext(struct lwp *, const mcontext_t *, struct trapframe *);
-
 #endif /* _KERNEL */
 
 #else  /*      __x86_64__      */
diff -r 122f01689cfa -r cc06828721a3 sys/arch/arm/arm/sig_machdep.c
--- a/sys/arch/arm/arm/sig_machdep.c    Mon May 21 08:14:58 2012 +0000
+++ b/sys/arch/arm/arm/sig_machdep.c    Mon May 21 14:15:16 2012 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: sig_machdep.c,v 1.41 2012/01/25 17:38:09 tsutsui Exp $ */
+/*     $NetBSD: sig_machdep.c,v 1.42 2012/05/21 14:15:17 martin Exp $  */
 
 /*
  * Copyright (c) 1994-1998 Mark Brinicombe.
@@ -44,7 +44,7 @@
 
 #include <sys/param.h>
 
-__KERNEL_RCSID(0, "$NetBSD: sig_machdep.c,v 1.41 2012/01/25 17:38:09 tsutsui Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sig_machdep.c,v 1.42 2012/05/21 14:15:17 martin Exp $");
 
 #include <sys/mount.h>         /* XXX only needed by syscallargs.h */
 #include <sys/proc.h>
@@ -205,17 +205,29 @@
 }
 
 int
+cpu_mcontext_validate(struct lwp *l, const mcontext_t *mcp)
+{
+       const __greg_t *gr = mcp->__gregs;
+
+       /* Make sure the processor mode has not been tampered with. */
+       if (!VALID_R15_PSR(gr[_REG_PC], gr[_REG_CPSR]))
+               return EINVAL;
+       return 0;
+}
+
+int
 cpu_setmcontext(struct lwp *l, const mcontext_t *mcp, unsigned int flags)
 {
        struct trapframe *tf = process_frame(l);
        const __greg_t *gr = mcp->__gregs;
        struct proc *p = l->l_proc;
+       int error;
 
        if ((flags & _UC_CPU) != 0) {
                /* Restore General Register context. */
-               /* Make sure the processor mode has not been tampered with. */
-               if (!VALID_R15_PSR(gr[_REG_PC], gr[_REG_CPSR]))
-                       return EINVAL;
+               error = cpu_mcontext_validate(l, mcp);



Home | Main Index | Thread Index | Old Index