Module Name: src Committed By: martin Date: Mon May 21 14:15:20 UTC 2012
Modified Files: src/distrib/sets/lists/tests: mi src/lib/libc/sys: _lwp_create.2 src/sys/arch/alpha/alpha: machdep.c src/sys/arch/amd64/amd64: machdep.c netbsd32_machdep.c process_machdep.c src/sys/arch/amd64/include: mcontext.h src/sys/arch/arm/arm: sig_machdep.c src/sys/arch/hppa/hppa: hppa_machdep.c src/sys/arch/i386/i386: machdep.c src/sys/arch/m68k/m68k: sig_machdep.c src/sys/arch/mips/mips: cpu_subr.c netbsd32_machdep.c src/sys/arch/powerpc/powerpc: sig_machdep.c src/sys/arch/sh3/sh3: sh3_machdep.c src/sys/arch/sparc/sparc: machdep.c src/sys/arch/sparc64/sparc64: machdep.c netbsd32_machdep.c src/sys/arch/vax/vax: machdep.c src/sys/compat/netbsd32: netbsd32_lwp.c src/sys/compat/sys: ucontext.h src/sys/kern: sys_lwp.c src/sys/sys: lwp.h ucontext.h src/tests/lib/libc/sys: Makefile Added Files: src/tests/lib/libc/sys: t_lwp_create.c Log Message: 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. To generate a diff of this commit: cvs rdiff -u -r1.468 -r1.469 src/distrib/sets/lists/tests/mi cvs rdiff -u -r1.4 -r1.5 src/lib/libc/sys/_lwp_create.2 cvs rdiff -u -r1.338 -r1.339 src/sys/arch/alpha/alpha/machdep.c cvs rdiff -u -r1.182 -r1.183 src/sys/arch/amd64/amd64/machdep.c cvs rdiff -u -r1.75 -r1.76 src/sys/arch/amd64/amd64/netbsd32_machdep.c cvs rdiff -u -r1.19 -r1.20 src/sys/arch/amd64/amd64/process_machdep.c cvs rdiff -u -r1.14 -r1.15 src/sys/arch/amd64/include/mcontext.h cvs rdiff -u -r1.41 -r1.42 src/sys/arch/arm/arm/sig_machdep.c cvs rdiff -u -r1.27 -r1.28 src/sys/arch/hppa/hppa/hppa_machdep.c cvs rdiff -u -r1.726 -r1.727 src/sys/arch/i386/i386/machdep.c cvs rdiff -u -r1.48 -r1.49 src/sys/arch/m68k/m68k/sig_machdep.c cvs rdiff -u -r1.15 -r1.16 src/sys/arch/mips/mips/cpu_subr.c cvs rdiff -u -r1.8 -r1.9 src/sys/arch/mips/mips/netbsd32_machdep.c cvs rdiff -u -r1.41 -r1.42 src/sys/arch/powerpc/powerpc/sig_machdep.c cvs rdiff -u -r1.98 -r1.99 src/sys/arch/sh3/sh3/sh3_machdep.c cvs rdiff -u -r1.318 -r1.319 src/sys/arch/sparc/sparc/machdep.c cvs rdiff -u -r1.266 -r1.267 src/sys/arch/sparc64/sparc64/machdep.c cvs rdiff -u -r1.97 -r1.98 src/sys/arch/sparc64/sparc64/netbsd32_machdep.c cvs rdiff -u -r1.187 -r1.188 src/sys/arch/vax/vax/machdep.c cvs rdiff -u -r1.12 -r1.13 src/sys/compat/netbsd32/netbsd32_lwp.c cvs rdiff -u -r1.5 -r1.6 src/sys/compat/sys/ucontext.h cvs rdiff -u -r1.53 -r1.54 src/sys/kern/sys_lwp.c cvs rdiff -u -r1.160 -r1.161 src/sys/sys/lwp.h cvs rdiff -u -r1.15 -r1.16 src/sys/sys/ucontext.h cvs rdiff -u -r1.22 -r1.23 src/tests/lib/libc/sys/Makefile cvs rdiff -u -r0 -r1.1 src/tests/lib/libc/sys/t_lwp_create.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/distrib/sets/lists/tests/mi diff -u src/distrib/sets/lists/tests/mi:1.468 src/distrib/sets/lists/tests/mi:1.469 --- src/distrib/sets/lists/tests/mi:1.468 Fri May 18 15:25:25 2012 +++ src/distrib/sets/lists/tests/mi Mon May 21 14:15:16 2012 @@ -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 Index: src/lib/libc/sys/_lwp_create.2 diff -u src/lib/libc/sys/_lwp_create.2:1.4 src/lib/libc/sys/_lwp_create.2:1.5 --- src/lib/libc/sys/_lwp_create.2:1.4 Wed Apr 30 13:10:51 2008 +++ src/lib/libc/sys/_lwp_create.2 Mon May 21 14:15:16 2012 @@ -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 @@ The .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 @@ The LWP ID of the new LWP is stored in t 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 @@ The address pointed to by 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 , Index: src/sys/arch/alpha/alpha/machdep.c diff -u src/sys/arch/alpha/alpha/machdep.c:1.338 src/sys/arch/alpha/alpha/machdep.c:1.339 --- src/sys/arch/alpha/alpha/machdep.c:1.338 Tue Feb 21 17:39:17 2012 +++ src/sys/arch/alpha/alpha/machdep.c Mon May 21 14:15:16 2012 @@ -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 @@ cpu_getmcontext(struct lwp *l, mcontext_ } } +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 @@ cpu_setmcontext(struct lwp *l, const mco 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) Index: src/sys/arch/amd64/amd64/machdep.c diff -u src/sys/arch/amd64/amd64/machdep.c:1.182 src/sys/arch/amd64/amd64/machdep.c:1.183 --- src/sys/arch/amd64/amd64/machdep.c:1.182 Sun Apr 29 21:54:51 2012 +++ src/sys/arch/amd64/amd64/machdep.c Mon May 21 14:15:17 2012 @@ -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 @@ cpu_setmcontext(struct lwp *l, const mco 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 @@ cpu_setmcontext(struct lwp *l, const mco } 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; Index: src/sys/arch/amd64/amd64/netbsd32_machdep.c diff -u src/sys/arch/amd64/amd64/netbsd32_machdep.c:1.75 src/sys/arch/amd64/amd64/netbsd32_machdep.c:1.76 --- src/sys/arch/amd64/amd64/netbsd32_machdep.c:1.75 Sun Feb 19 21:06:01 2012 +++ src/sys/arch/amd64/amd64/netbsd32_machdep.c Mon May 21 14:15:17 2012 @@ -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 @@ static int x86_64_set_mtrr32(struct lwp #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 @@ cpu_setmcontext32(struct lwp *l, const m /* * Check for security violations. */ - error = check_mcontext32(l, mcp); + error = cpu_mcontext32_validate(l, mcp); if (error != 0) return error; @@ -984,8 +983,8 @@ check_sigcontext32(struct lwp *l, const 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; Index: src/sys/arch/amd64/amd64/process_machdep.c diff -u src/sys/arch/amd64/amd64/process_machdep.c:1.19 src/sys/arch/amd64/amd64/process_machdep.c:1.20 --- src/sys/arch/amd64/amd64/process_machdep.c:1.19 Tue Dec 20 13:17:05 2011 +++ src/sys/arch/amd64/amd64/process_machdep.c Mon May 21 14:15:17 2012 @@ -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 @@ process_write_regs(struct lwp *l, const * 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; Index: src/sys/arch/amd64/include/mcontext.h diff -u src/sys/arch/amd64/include/mcontext.h:1.14 src/sys/arch/amd64/include/mcontext.h:1.15 --- src/sys/arch/amd64/include/mcontext.h:1.14 Fri Feb 25 14:07:12 2011 +++ src/sys/arch/amd64/include/mcontext.h Mon May 21 14:15:17 2012 @@ -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 @@ typedef struct { #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__ */ Index: src/sys/arch/arm/arm/sig_machdep.c diff -u src/sys/arch/arm/arm/sig_machdep.c:1.41 src/sys/arch/arm/arm/sig_machdep.c:1.42 --- src/sys/arch/arm/arm/sig_machdep.c:1.41 Wed Jan 25 17:38:09 2012 +++ src/sys/arch/arm/arm/sig_machdep.c Mon May 21 14:15:17 2012 @@ -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 @@ cpu_getmcontext(struct lwp *l, mcontext_ } 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); + if (error) + return error; tf->tf_r0 = gr[_REG_R0]; tf->tf_r1 = gr[_REG_R1]; Index: src/sys/arch/hppa/hppa/hppa_machdep.c diff -u src/sys/arch/hppa/hppa/hppa_machdep.c:1.27 src/sys/arch/hppa/hppa/hppa_machdep.c:1.28 --- src/sys/arch/hppa/hppa/hppa_machdep.c:1.27 Sun Feb 19 21:06:07 2012 +++ src/sys/arch/hppa/hppa/hppa_machdep.c Mon May 21 14:15:17 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: hppa_machdep.c,v 1.27 2012/02/19 21:06:07 rmind Exp $ */ +/* $NetBSD: hppa_machdep.c,v 1.28 2012/05/21 14:15:17 martin Exp $ */ /*- * Copyright (c) 1997 The NetBSD Foundation, Inc. @@ -27,7 +27,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: hppa_machdep.c,v 1.27 2012/02/19 21:06:07 rmind Exp $"); +__KERNEL_RCSID(0, "$NetBSD: hppa_machdep.c,v 1.28 2012/05/21 14:15:17 martin Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -130,45 +130,57 @@ cpu_getmcontext(struct lwp *l, mcontext_ } int -cpu_setmcontext(struct lwp *l, const mcontext_t *mcp, unsigned int flags) +cpu_mcontext_validate(struct lwp *l, const mcontext_t *mcp) { - struct trapframe *tf = l->l_md.md_regs; - struct proc *p = l->l_proc; - struct pmap *pmap = p->p_vmspace->vm_map.pmap; const __greg_t *gr = mcp->__gregs; - if ((flags & _UC_CPU) != 0) { - - if ((gr[_REG_PSW] & (PSW_MBS|PSW_MBZ)) != PSW_MBS) { - return EINVAL; - } + if ((gr[_REG_PSW] & (PSW_MBS|PSW_MBZ)) != PSW_MBS) { + return EINVAL; + } #if 0 - /* - * XXX - * Force the space regs and priviledge bits to - * the right values in the trapframe for now. - */ + /* + * XXX + * Force the space regs and priviledge bits to + * the right values in the trapframe for now. + */ - if (gr[_REG_PCSQH] != pmap_sid(pmap, gr[_REG_PCOQH])) { - return EINVAL; - } + if (gr[_REG_PCSQH] != pmap_sid(pmap, gr[_REG_PCOQH])) { + return EINVAL; + } - if (gr[_REG_PCSQT] != pmap_sid(pmap, gr[_REG_PCOQT])) { - return EINVAL; - } + if (gr[_REG_PCSQT] != pmap_sid(pmap, gr[_REG_PCOQT])) { + return EINVAL; + } - if (gr[_REG_PCOQH] < 0xc0000020 && - (gr[_REG_PCOQH] & HPPA_PC_PRIV_MASK) != HPPA_PC_PRIV_USER) { - return EINVAL; - } + if (gr[_REG_PCOQH] < 0xc0000020 && + (gr[_REG_PCOQH] & HPPA_PC_PRIV_MASK) != HPPA_PC_PRIV_USER) { + return EINVAL; + } - if (gr[_REG_PCOQT] < 0xc0000020 && - (gr[_REG_PCOQT] & HPPA_PC_PRIV_MASK) != HPPA_PC_PRIV_USER) { - return EINVAL; - } + if (gr[_REG_PCOQT] < 0xc0000020 && + (gr[_REG_PCOQT] & HPPA_PC_PRIV_MASK) != HPPA_PC_PRIV_USER) { + return EINVAL; + } #endif + return 0; +} + +int +cpu_setmcontext(struct lwp *l, const mcontext_t *mcp, unsigned int flags) +{ + struct trapframe *tf = l->l_md.md_regs; + struct proc *p = l->l_proc; + struct pmap *pmap = p->p_vmspace->vm_map.pmap; + const __greg_t *gr = mcp->__gregs; + int error; + + if ((flags & _UC_CPU) != 0) { + error = cpu_mcontext_validate(l, mcp); + if (error) + return error; + tf->tf_ipsw = gr[0] | (hppa_cpu_ispa20_p() ? PSW_O : 0); tf->tf_r1 = gr[1]; Index: src/sys/arch/i386/i386/machdep.c diff -u src/sys/arch/i386/i386/machdep.c:1.726 src/sys/arch/i386/i386/machdep.c:1.727 --- src/sys/arch/i386/i386/machdep.c:1.726 Sun Mar 4 20:44:17 2012 +++ src/sys/arch/i386/i386/machdep.c Mon May 21 14:15:17 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: machdep.c,v 1.726 2012/03/04 20:44:17 bouyer Exp $ */ +/* $NetBSD: machdep.c,v 1.727 2012/05/21 14:15:17 martin Exp $ */ /*- * Copyright (c) 1996, 1997, 1998, 2000, 2004, 2006, 2008, 2009 @@ -67,7 +67,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.726 2012/03/04 20:44:17 bouyer Exp $"); +__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.727 2012/05/21 14:15:17 martin Exp $"); #include "opt_beep.h" #include "opt_compat_ibcs2.h" @@ -1764,12 +1764,33 @@ cpu_getmcontext(struct lwp *l, mcontext_ } int +cpu_mcontext_validate(struct lwp *l, const mcontext_t *mcp) +{ + const __greg_t *gr = mcp->__gregs; + struct trapframe *tf = l->l_md.md_regs; + + /* + * Check for security violations. If we're returning + * to protected mode, the CPU will validate the segment + * registers automatically and generate a trap on + * violations. We handle the trap, rather than doing + * all of the checking here. + */ + if (((gr[_REG_EFL] ^ tf->tf_eflags) & PSL_USERSTATIC) || + !USERMODE(gr[_REG_CS], gr[_REG_EFL])) + return EINVAL; + + return 0; +} + +int cpu_setmcontext(struct lwp *l, const mcontext_t *mcp, unsigned int flags) { struct trapframe *tf = l->l_md.md_regs; const __greg_t *gr = mcp->__gregs; struct pcb *pcb = lwp_getpcb(l); struct proc *p = l->l_proc; + int error; /* Restore register context, if any. */ if ((flags & _UC_CPU) != 0) { @@ -1787,20 +1808,10 @@ cpu_setmcontext(struct lwp *l, const mco } else #endif { - /* - * Check for security violations. If we're returning - * to protected mode, the CPU will validate the segment - * registers automatically and generate a trap on - * violations. We handle the trap, rather than doing - * all of the checking here. - */ - if (((gr[_REG_EFL] ^ tf->tf_eflags) & PSL_USERSTATIC) || - !USERMODE(gr[_REG_CS], gr[_REG_EFL])) { - printf("cpu_setmcontext error: uc EFL: 0x%08x" - " tf EFL: 0x%08x uc CS: 0x%x\n", - gr[_REG_EFL], tf->tf_eflags, gr[_REG_CS]); - return (EINVAL); - } + error = cpu_mcontext_validate(l, mcp); + if (error) + return error; + tf->tf_gs = gr[_REG_GS]; tf->tf_fs = gr[_REG_FS]; tf->tf_es = gr[_REG_ES]; Index: src/sys/arch/m68k/m68k/sig_machdep.c diff -u src/sys/arch/m68k/m68k/sig_machdep.c:1.48 src/sys/arch/m68k/m68k/sig_machdep.c:1.49 --- src/sys/arch/m68k/m68k/sig_machdep.c:1.48 Sun Feb 19 21:06:14 2012 +++ src/sys/arch/m68k/m68k/sig_machdep.c Mon May 21 14:15:18 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: sig_machdep.c,v 1.48 2012/02/19 21:06:14 rmind Exp $ */ +/* $NetBSD: sig_machdep.c,v 1.49 2012/05/21 14:15:18 martin Exp $ */ /* * Copyright (c) 1988 University of Utah. @@ -40,7 +40,7 @@ #include "opt_m68k_arch.h" #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: sig_machdep.c,v 1.48 2012/02/19 21:06:14 rmind Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sig_machdep.c,v 1.49 2012/05/21 14:15:18 martin Exp $"); #define __M68K_SIGNAL_PRIVATE @@ -270,17 +270,29 @@ cpu_getmcontext(struct lwp *l, mcontext_ } int +cpu_mcontext_validate(struct lwp *l, const mcontext_t *mcp) +{ + const __greg_t *gr = mcp->__gregs; + + if ((gr[_REG_PS] & (PSL_MBZ|PSL_IPL|PSL_S)) != 0) + return EINVAL; + return 0; +} + +int cpu_setmcontext(struct lwp *l, const mcontext_t *mcp, u_int flags) { const __greg_t *gr = mcp->__gregs; struct frame *frame = (struct frame *)l->l_md.md_regs; unsigned int format = mcp->__mc_pad.__mc_frame.__mcf_format; - int sz; + int sz, error; /* Validate the supplied context */ - if (((flags & _UC_CPU) != 0 && - (gr[_REG_PS] & (PSL_MBZ|PSL_IPL|PSL_S)) != 0)) - return (EINVAL); + if ((flags & _UC_CPU) != 0) { + error = cpu_mcontext_validate(l, mcp); + if (error) + return error; + } /* Restore exception frame information if necessary. */ if ((flags & _UC_M68K_UC_USER) == 0 && format >= FMT4) { Index: src/sys/arch/mips/mips/cpu_subr.c diff -u src/sys/arch/mips/mips/cpu_subr.c:1.15 src/sys/arch/mips/mips/cpu_subr.c:1.16 --- src/sys/arch/mips/mips/cpu_subr.c:1.15 Sun Feb 19 21:06:16 2012 +++ src/sys/arch/mips/mips/cpu_subr.c Mon May 21 14:15:18 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: cpu_subr.c,v 1.15 2012/02/19 21:06:16 rmind Exp $ */ +/* $NetBSD: cpu_subr.c,v 1.16 2012/05/21 14:15:18 martin Exp $ */ /*- * Copyright (c) 2010 The NetBSD Foundation, Inc. @@ -30,7 +30,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: cpu_subr.c,v 1.15 2012/02/19 21:06:16 rmind Exp $"); +__KERNEL_RCSID(0, "$NetBSD: cpu_subr.c,v 1.16 2012/05/21 14:15:18 martin Exp $"); #include "opt_ddb.h" #include "opt_multiprocessor.h" @@ -363,16 +363,28 @@ cpu_getmcontext(struct lwp *l, mcontext_ } int +cpu_mcontext_validate(struct lwp *l, const mcontext_t *mcp) +{ + /* XXX: Do we validate the addresses?? */ + return 0; +} + +int cpu_setmcontext(struct lwp *l, const mcontext_t *mcp, unsigned int flags) { struct trapframe *tf = l->l_md.md_utf; struct proc *p = l->l_proc; const __greg_t *gr = mcp->__gregs; + int error; /* Restore register context, if any. */ if (flags & _UC_CPU) { + error = cpu_mcontext_validate(l, mcp); + if (error) + return error; + /* Save register context. */ - /* XXX: Do we validate the addresses?? */ + #ifdef __mips_n32 CTASSERT(_R_AST == _REG_AT); if (__predict_false(p->p_md.md_abi == _MIPS_BSD_API_O32)) { Index: src/sys/arch/mips/mips/netbsd32_machdep.c diff -u src/sys/arch/mips/mips/netbsd32_machdep.c:1.8 src/sys/arch/mips/mips/netbsd32_machdep.c:1.9 --- src/sys/arch/mips/mips/netbsd32_machdep.c:1.8 Sun Feb 19 21:06:19 2012 +++ src/sys/arch/mips/mips/netbsd32_machdep.c Mon May 21 14:15:18 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: netbsd32_machdep.c,v 1.8 2012/02/19 21:06:19 rmind Exp $ */ +/* $NetBSD: netbsd32_machdep.c,v 1.9 2012/05/21 14:15:18 martin Exp $ */ /*- * Copyright (c) 2009 The NetBSD Foundation, Inc. @@ -30,7 +30,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: netbsd32_machdep.c,v 1.8 2012/02/19 21:06:19 rmind Exp $"); +__KERNEL_RCSID(0, "$NetBSD: netbsd32_machdep.c,v 1.9 2012/05/21 14:15:18 martin Exp $"); #include "opt_compat_netbsd.h" #include "opt_coredump.h" @@ -266,11 +266,23 @@ cpu_getmcontext32(struct lwp *l, mcontex } int +cpu_mcontext32_validate(struct lwp *l, const mcontext32_t *mc32) +{ + return 0; +} + +int cpu_setmcontext32(struct lwp *l, const mcontext32_t *mc32, unsigned int flags) { const mcontext_o32_t * const mco32 = (const mcontext_o32_t *)mc32; mcontext_t mc; - size_t i; + size_t i, error; + + if (flags & _UC_CPU) { + error = cpu_mcontext32_validate(l, mc32); + if (error) + return error; + } if (l->l_proc->p_md.md_abi == _MIPS_BSD_API_N32) return cpu_setmcontext(l, (const mcontext_t *)mc32, flags); Index: src/sys/arch/powerpc/powerpc/sig_machdep.c diff -u src/sys/arch/powerpc/powerpc/sig_machdep.c:1.41 src/sys/arch/powerpc/powerpc/sig_machdep.c:1.42 --- src/sys/arch/powerpc/powerpc/sig_machdep.c:1.41 Mon Jun 20 05:50:39 2011 +++ src/sys/arch/powerpc/powerpc/sig_machdep.c Mon May 21 14:15:18 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: sig_machdep.c,v 1.41 2011/06/20 05:50:39 matt Exp $ */ +/* $NetBSD: sig_machdep.c,v 1.42 2012/05/21 14:15:18 martin Exp $ */ /* * Copyright (C) 1995, 1996 Wolfgang Solfrank. @@ -32,7 +32,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: sig_machdep.c,v 1.41 2011/06/20 05:50:39 matt Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sig_machdep.c,v 1.42 2012/05/21 14:15:18 martin Exp $"); #include "opt_ppcarch.h" #include "opt_altivec.h" @@ -187,13 +187,24 @@ cpu_getmcontext(struct lwp *l, mcontext_ } int +cpu_mcontext_validate(struct lwp *l, const mcontext_t *mcp) +{ + return 0; +} + +int cpu_setmcontext(struct lwp *l, const mcontext_t *mcp, unsigned int flags) { struct trapframe * const tf = l->l_md.md_utf; const __greg_t * const gr = mcp->__gregs; + int error; /* Restore GPR context, if any. */ if (flags & _UC_CPU) { + error = cpu_mcontext_validate(l, mcp); + if (error) + return error; + #ifdef PPC_HAVE_FPU /* * Always save the FP exception mode in the PCB. Index: src/sys/arch/sh3/sh3/sh3_machdep.c diff -u src/sys/arch/sh3/sh3/sh3_machdep.c:1.98 src/sys/arch/sh3/sh3/sh3_machdep.c:1.99 --- src/sys/arch/sh3/sh3/sh3_machdep.c:1.98 Sun Feb 19 21:06:27 2012 +++ src/sys/arch/sh3/sh3/sh3_machdep.c Mon May 21 14:15:18 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: sh3_machdep.c,v 1.98 2012/02/19 21:06:27 rmind Exp $ */ +/* $NetBSD: sh3_machdep.c,v 1.99 2012/05/21 14:15:18 martin Exp $ */ /*- * Copyright (c) 1996, 1997, 1998, 2002 The NetBSD Foundation, Inc. @@ -65,7 +65,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: sh3_machdep.c,v 1.98 2012/02/19 21:06:27 rmind Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sh3_machdep.c,v 1.99 2012/05/21 14:15:18 martin Exp $"); #include "opt_ddb.h" #include "opt_kgdb.h" @@ -439,17 +439,31 @@ cpu_getmcontext(struct lwp *l, mcontext_ } int +cpu_mcontext_validate(struct lwp *l, const mcontext_t *mcp) +{ + struct trapframe *tf = l->l_md.md_regs; + const __greg_t *gr = mcp->__gregs; + + if (((tf->tf_ssr ^ gr[_REG_SR]) & PSL_USERSTATIC) != 0) + return EINVAL; + + return 0; +} + +int cpu_setmcontext(struct lwp *l, const mcontext_t *mcp, unsigned int flags) { struct trapframe *tf = l->l_md.md_regs; const __greg_t *gr = mcp->__gregs; struct proc *p = l->l_proc; + int error; /* Restore register context, if any. */ if ((flags & _UC_CPU) != 0) { /* Check for security violations. */ - if (((tf->tf_ssr ^ gr[_REG_SR]) & PSL_USERSTATIC) != 0) - return (EINVAL); + error = cpu_mcontext_validate(l, mcp); + if (error) + return error; tf->tf_gbr = gr[_REG_GBR]; tf->tf_spc = gr[_REG_PC]; Index: src/sys/arch/sparc/sparc/machdep.c diff -u src/sys/arch/sparc/sparc/machdep.c:1.318 src/sys/arch/sparc/sparc/machdep.c:1.319 --- src/sys/arch/sparc/sparc/machdep.c:1.318 Wed Apr 25 08:19:33 2012 +++ src/sys/arch/sparc/sparc/machdep.c Mon May 21 14:15:18 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: machdep.c,v 1.318 2012/04/25 08:19:33 dholland Exp $ */ +/* $NetBSD: machdep.c,v 1.319 2012/05/21 14:15:18 martin Exp $ */ /*- * Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc. @@ -71,7 +71,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.318 2012/04/25 08:19:33 dholland Exp $"); +__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.319 2012/05/21 14:15:18 martin Exp $"); #include "opt_compat_netbsd.h" #include "opt_compat_sunos.h" @@ -674,6 +674,23 @@ cpu_getmcontext(struct lwp *l, mcontext_ return; } +int +cpu_mcontext_validate(struct lwp *l, const mcontext_t *mc) +{ + const __greg_t *gr = mc->__gregs; + + /* + * Only the icc bits in the psr are used, so it need not be + * verified. pc and npc must be multiples of 4. This is all + * that is required; if it holds, just do it. + */ + if (((gr[_REG_PC] | gr[_REG_nPC]) & 3) != 0 || + gr[_REG_PC] == 0 || gr[_REG_nPC] == 0) + return EINVAL; + + return 0; +} + /* * Set to mcontext specified. * Return to previous pc and psl as specified by @@ -689,6 +706,7 @@ cpu_setmcontext(struct lwp *l, const mco struct trapframe *tf; const __greg_t *r = mcp->__gregs; struct proc *p = l->l_proc; + int error; #ifdef FPU_CONTEXT __fpregset_t *f = &mcp->__fpregs; struct fpstate *fps = l->l_md.md_fpstate; @@ -707,19 +725,14 @@ cpu_setmcontext(struct lwp *l, const mco #endif if (flags & _UC_CPU) { + /* Validate */ + error = cpu_mcontext_validate(l, mcp); + if (error) + return error; + /* Restore register context. */ tf = (struct trapframe *)l->l_md.md_tf; - /* - * Only the icc bits in the psr are used, so it need not be - * verified. pc and npc must be multiples of 4. This is all - * that is required; if it holds, just do it. - */ - if (((r[_REG_PC] | r[_REG_nPC]) & 3) != 0) { - printf("pc or npc are not multiples of 4!\n"); - return (EINVAL); - } - /* take only psr ICC field */ tf->tf_psr = (tf->tf_psr & ~PSR_ICC) | (r[_REG_PSR] & PSR_ICC); Index: src/sys/arch/sparc64/sparc64/machdep.c diff -u src/sys/arch/sparc64/sparc64/machdep.c:1.266 src/sys/arch/sparc64/sparc64/machdep.c:1.267 --- src/sys/arch/sparc64/sparc64/machdep.c:1.266 Sun Feb 19 21:06:31 2012 +++ src/sys/arch/sparc64/sparc64/machdep.c Mon May 21 14:15:18 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: machdep.c,v 1.266 2012/02/19 21:06:31 rmind Exp $ */ +/* $NetBSD: machdep.c,v 1.267 2012/05/21 14:15:18 martin Exp $ */ /*- * Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc. @@ -71,7 +71,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.266 2012/02/19 21:06:31 rmind Exp $"); +__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.267 2012/05/21 14:15:18 martin Exp $"); #include "opt_ddb.h" #include "opt_multiprocessor.h" @@ -2534,11 +2534,29 @@ cpu_getmcontext(struct lwp *l, mcontext_ } int +cpu_mcontext_validate(struct lwp *l, const mcontext_t *mc) +{ + const __greg_t *gr = mc->__gregs; + + /* + * Only the icc bits in the psr are used, so it need not be + * verified. pc and npc must be multiples of 4. This is all + * that is required; if it holds, just do it. + */ + if (((gr[_REG_PC] | gr[_REG_nPC]) & 3) != 0 || + gr[_REG_PC] == 0 || gr[_REG_nPC] == 0) + return EINVAL; + + return 0; +} + +int cpu_setmcontext(struct lwp *l, const mcontext_t *mcp, unsigned int flags) { const __greg_t *gr = mcp->__gregs; struct trapframe64 *tf = l->l_md.md_tf; struct proc *p = l->l_proc; + int error; /* First ensure consistent stack state (see sendsig). */ write_user_windows(); @@ -2548,14 +2566,9 @@ cpu_setmcontext(struct lwp *l, const mco } if ((flags & _UC_CPU) != 0) { - /* - * Only the icc bits in the psr are used, so it need not be - * verified. pc and npc must be multiples of 4. This is all - * that is required; if it holds, just do it. - */ - if (((gr[_REG_PC] | gr[_REG_nPC]) & 3) != 0 || - gr[_REG_PC] == 0 || gr[_REG_nPC] == 0) - return (EINVAL); + error = cpu_mcontext_validate(l, mcp); + if (error) + return error; /* Restore general register context. */ /* take only tstate CCR (and ASI) fields */ @@ -2630,7 +2643,7 @@ cpu_setmcontext(struct lwp *l, const mco l->l_sigstk.ss_flags &= ~SS_ONSTACK; mutex_exit(p->p_lock); - return (0); + return 0; } /* Index: src/sys/arch/sparc64/sparc64/netbsd32_machdep.c diff -u src/sys/arch/sparc64/sparc64/netbsd32_machdep.c:1.97 src/sys/arch/sparc64/sparc64/netbsd32_machdep.c:1.98 --- src/sys/arch/sparc64/sparc64/netbsd32_machdep.c:1.97 Sun Feb 19 21:06:31 2012 +++ src/sys/arch/sparc64/sparc64/netbsd32_machdep.c Mon May 21 14:15:18 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: netbsd32_machdep.c,v 1.97 2012/02/19 21:06:31 rmind Exp $ */ +/* $NetBSD: netbsd32_machdep.c,v 1.98 2012/05/21 14:15:18 martin Exp $ */ /* * Copyright (c) 1998, 2001 Matthew R. Green @@ -27,7 +27,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: netbsd32_machdep.c,v 1.97 2012/02/19 21:06:31 rmind Exp $"); +__KERNEL_RCSID(0, "$NetBSD: netbsd32_machdep.c,v 1.98 2012/05/21 14:15:18 martin Exp $"); #ifdef _KERNEL_OPT #include "opt_compat_netbsd.h" @@ -811,7 +811,6 @@ netbsd32_cpu_getmcontext( #endif } - int netbsd32_cpu_setmcontext(struct lwp *, mcontext_t *, unsigned int); int @@ -1136,6 +1135,22 @@ netbsd32_sysarch(struct lwp *l, const st } } +int +cpu_mcontext32_validate(struct lwp *l, const mcontext32_t *mc) +{ + const __greg32_t *gr = mc->__gregs; + + /* + * Only the icc bits in the psr are used, so it need not be + * verified. pc and npc must be multiples of 4. This is all + * that is required; if it holds, just do it. + */ + if (((gr[_REG32_PC] | gr[_REG32_nPC]) & 3) != 0 || + gr[_REG32_PC] == 0 || gr[_REG32_nPC] == 0) + return EINVAL; + + return 0; +} int cpu_setmcontext32(struct lwp *l, const mcontext32_t *mcp, unsigned int flags) @@ -1143,6 +1158,7 @@ cpu_setmcontext32(struct lwp *l, const m struct trapframe *tf = l->l_md.md_tf; const __greg32_t *gr = mcp->__gregs; struct proc *p = l->l_proc; + int error; /* First ensure consistent stack state (see sendsig). */ write_user_windows(); @@ -1153,14 +1169,9 @@ cpu_setmcontext32(struct lwp *l, const m /* Restore register context, if any. */ if ((flags & _UC_CPU) != 0) { - /* - * Only the icc bits in the psr are used, so it need not be - * verified. pc and npc must be multiples of 4. This is all - * that is required; if it holds, just do it. - */ - if (((gr[_REG32_PC] | gr[_REG32_nPC]) & 3) != 0 || - gr[_REG32_PC] == 0 || gr[_REG32_nPC] == 0) - return (EINVAL); + error = cpu_mcontext32_validate(l, mcp); + if (error) + return error; /* Restore general register context. */ /* take only tstate CCR (and ASI) fields */ @@ -1314,8 +1325,7 @@ startlwp32(void *arg) error = cpu_setmcontext32(l, &uc->uc_mcontext, uc->uc_flags); KASSERT(error == 0); - /* Note: we are freeing ucontext_t, not ucontext32_t. */ - kmem_free(uc, sizeof(ucontext_t)); + kmem_free(uc, sizeof(ucontext32_t)); userret(l, 0, 0); } Index: src/sys/arch/vax/vax/machdep.c diff -u src/sys/arch/vax/vax/machdep.c:1.187 src/sys/arch/vax/vax/machdep.c:1.188 --- src/sys/arch/vax/vax/machdep.c:1.187 Mon Feb 27 15:41:10 2012 +++ src/sys/arch/vax/vax/machdep.c Mon May 21 14:15:19 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: machdep.c,v 1.187 2012/02/27 15:41:10 matt Exp $ */ +/* $NetBSD: machdep.c,v 1.188 2012/05/21 14:15:19 martin Exp $ */ /* * Copyright (c) 1982, 1986, 1990 The Regents of the University of California. @@ -83,7 +83,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.187 2012/02/27 15:41:10 matt Exp $"); +__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.188 2012/05/21 14:15:19 martin Exp $"); #include "opt_ddb.h" #include "opt_compat_netbsd.h" @@ -641,18 +641,31 @@ cpu_getmcontext(struct lwp *l, mcontext_ } int +cpu_mcontext_validate(struct lwp *l, const mcontext_t *mcp) +{ + const __greg_t *gr = mcp->__gregs; + + if ((gr[_REG_PSL] & (PSL_IPL | PSL_IS)) || + ((gr[_REG_PSL] & (PSL_U | PSL_PREVU)) != (PSL_U | PSL_PREVU)) || + (gr[_REG_PSL] & PSL_CM)) + return EINVAL; + + return 0; +} + +int cpu_setmcontext(struct lwp *l, const mcontext_t *mcp, unsigned int flags) { struct trapframe * const tf = l->l_md.md_utf; const __greg_t *gr = mcp->__gregs; + int error; if ((flags & _UC_CPU) == 0) return 0; - if ((gr[_REG_PSL] & (PSL_IPL | PSL_IS)) || - ((gr[_REG_PSL] & (PSL_U | PSL_PREVU)) != (PSL_U | PSL_PREVU)) || - (gr[_REG_PSL] & PSL_CM)) - return (EINVAL); + error = cpu_mcontext_validate(l, mcp); + if (error) + return error; tf->tf_r0 = gr[_REG_R0]; tf->tf_r1 = gr[_REG_R1]; @@ -674,7 +687,6 @@ cpu_setmcontext(struct lwp *l, const mco if (flags & _UC_TLSBASE) { void *tlsbase; - int error; error = copyin((void *)tf->tf_sp, &tlsbase, sizeof(tlsbase)); if (error) { Index: src/sys/compat/netbsd32/netbsd32_lwp.c diff -u src/sys/compat/netbsd32/netbsd32_lwp.c:1.12 src/sys/compat/netbsd32/netbsd32_lwp.c:1.13 --- src/sys/compat/netbsd32/netbsd32_lwp.c:1.12 Sat Feb 5 13:46:44 2011 +++ src/sys/compat/netbsd32/netbsd32_lwp.c Mon May 21 14:15:19 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: netbsd32_lwp.c,v 1.12 2011/02/05 13:46:44 yamt Exp $ */ +/* $NetBSD: netbsd32_lwp.c,v 1.13 2012/05/21 14:15:19 martin Exp $ */ /* * Copyright (c) 2005, 2006, 2007 The NetBSD Foundation. @@ -27,7 +27,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: netbsd32_lwp.c,v 1.12 2011/02/05 13:46:44 yamt Exp $"); +__KERNEL_RCSID(0, "$NetBSD: netbsd32_lwp.c,v 1.13 2012/05/21 14:15:19 martin Exp $"); #include <sys/types.h> #include <sys/param.h> @@ -53,14 +53,40 @@ netbsd32__lwp_create(struct lwp *l, cons syscallarg(netbsd32_u_long) flags; syscallarg(netbsd32_lwpidp) new_lwp; } */ - struct sys__lwp_create_args ua; + struct proc *p = l->l_proc; + ucontext32_t *newuc = NULL; + lwpid_t lid; + int error; - CTASSERT(sizeof(ucontext32_t) <= sizeof(ucontext_t)); - NETBSD32TOP_UAP(ucp, const ucontext_t); /* see startlwp32() */ - NETBSD32TO64_UAP(flags); - NETBSD32TOP_UAP(new_lwp, lwpid_t); + KASSERT(p->p_emul->e_ucsize == sizeof(*newuc)); - return sys__lwp_create(l, &ua, retval); + newuc = kmem_alloc(sizeof(ucontext32_t), KM_SLEEP); + error = copyin(SCARG_P32(uap, ucp), newuc, p->p_emul->e_ucsize); + if (error) + goto fail; + + /* validate the ucontext */ + if ((newuc->uc_flags & _UC_CPU) == 0) { + error = EINVAL; + goto fail; + } + error = cpu_mcontext32_validate(l, &newuc->uc_mcontext); + if (error) + goto fail; + + error = do_lwp_create(l, newuc, SCARG(uap, flags), &lid); + if (error) + goto fail; + + /* + * do not free ucontext in case of an error here, + * the lwp will actually run and access it + */ + return copyout(&lid, SCARG_P32(uap, new_lwp), sizeof(lid)); + +fail: + kmem_free(newuc, sizeof(*newuc)); + return error; } int Index: src/sys/compat/sys/ucontext.h diff -u src/sys/compat/sys/ucontext.h:1.5 src/sys/compat/sys/ucontext.h:1.6 --- src/sys/compat/sys/ucontext.h:1.5 Sun Mar 18 21:48:47 2012 +++ src/sys/compat/sys/ucontext.h Mon May 21 14:15:19 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: ucontext.h,v 1.5 2012/03/18 21:48:47 njoly Exp $ */ +/* $NetBSD: ucontext.h,v 1.6 2012/05/21 14:15:19 martin Exp $ */ /*- * Copyright (c) 1999, 2003 The NetBSD Foundation, Inc. @@ -64,6 +64,7 @@ __CTASSERT(sizeof(ucontext32_t) == __UCO struct lwp; void getucontext32(struct lwp *, ucontext32_t *); int setucontext32(struct lwp *, const ucontext32_t *); +int cpu_mcontext32_validate(struct lwp *, const mcontext32_t *); void cpu_getmcontext32(struct lwp *, mcontext32_t *, unsigned int *); int cpu_setmcontext32(struct lwp *, const mcontext32_t *, unsigned int); #endif /* COMPAT_NETBSD32 */ Index: src/sys/kern/sys_lwp.c diff -u src/sys/kern/sys_lwp.c:1.53 src/sys/kern/sys_lwp.c:1.54 --- src/sys/kern/sys_lwp.c:1.53 Sun Feb 19 21:06:56 2012 +++ src/sys/kern/sys_lwp.c Mon May 21 14:15:19 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: sys_lwp.c,v 1.53 2012/02/19 21:06:56 rmind Exp $ */ +/* $NetBSD: sys_lwp.c,v 1.54 2012/05/21 14:15:19 martin Exp $ */ /*- * Copyright (c) 2001, 2006, 2007, 2008 The NetBSD Foundation, Inc. @@ -35,7 +35,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: sys_lwp.c,v 1.53 2012/02/19 21:06:56 rmind Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sys_lwp.c,v 1.54 2012/05/21 14:15:19 martin Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -70,51 +70,28 @@ lwp_sys_init(void) } int -sys__lwp_create(struct lwp *l, const struct sys__lwp_create_args *uap, - register_t *retval) +do_lwp_create(lwp_t *l, void *arg, u_long flags, lwpid_t *new_lwp) { - /* { - syscallarg(const ucontext_t *) ucp; - syscallarg(u_long) flags; - syscallarg(lwpid_t *) new_lwp; - } */ struct proc *p = l->l_proc; struct lwp *l2; struct schedstate_percpu *spc; vaddr_t uaddr; - ucontext_t *newuc; - int error, lid; - - newuc = kmem_alloc(sizeof(ucontext_t), KM_SLEEP); - error = copyin(SCARG(uap, ucp), newuc, p->p_emul->e_ucsize); - if (error) { - kmem_free(newuc, sizeof(ucontext_t)); - return error; - } + int error; /* XXX check against resource limits */ uaddr = uvm_uarea_alloc(); - if (__predict_false(uaddr == 0)) { - kmem_free(newuc, sizeof(ucontext_t)); + if (__predict_false(uaddr == 0)) return ENOMEM; - } - error = lwp_create(l, p, uaddr, SCARG(uap, flags) & LWP_DETACHED, - NULL, 0, p->p_emul->e_startlwp, newuc, &l2, l->l_class); + error = lwp_create(l, p, uaddr, flags & LWP_DETACHED, + NULL, 0, p->p_emul->e_startlwp, arg, &l2, l->l_class); if (__predict_false(error)) { uvm_uarea_free(uaddr); - kmem_free(newuc, sizeof(ucontext_t)); return error; } - lid = l2->l_lid; - error = copyout(&lid, SCARG(uap, new_lwp), sizeof(lid)); - if (error) { - lwp_exit(l2); - kmem_free(newuc, sizeof(ucontext_t)); - return error; - } + *new_lwp = l2->l_lid; /* * Set the new LWP running, unless the caller has requested that @@ -124,7 +101,7 @@ sys__lwp_create(struct lwp *l, const str mutex_enter(p->p_lock); lwp_lock(l2); spc = &l2->l_cpu->ci_schedstate; - if ((SCARG(uap, flags) & LWP_SUSPENDED) == 0 && + if ((flags & LWP_SUSPENDED) == 0 && (l->l_flag & (LW_WREBOOT | LW_WSUSPEND | LW_WEXIT)) == 0) { if (p->p_stat == SSTOP || (p->p_sflag & PS_STOPPING) != 0) { KASSERT(l2->l_wchan == NULL); @@ -148,6 +125,49 @@ sys__lwp_create(struct lwp *l, const str } int +sys__lwp_create(struct lwp *l, const struct sys__lwp_create_args *uap, + register_t *retval) +{ + /* { + syscallarg(const ucontext_t *) ucp; + syscallarg(u_long) flags; + syscallarg(lwpid_t *) new_lwp; + } */ + struct proc *p = l->l_proc; + ucontext_t *newuc = NULL; + lwpid_t lid; + int error; + + newuc = kmem_alloc(sizeof(ucontext_t), KM_SLEEP); + error = copyin(SCARG(uap, ucp), newuc, p->p_emul->e_ucsize); + if (error) + goto fail; + + /* validate the ucontext */ + if ((newuc->uc_flags & _UC_CPU) == 0) { + error = EINVAL; + goto fail; + } + error = cpu_mcontext_validate(l, &newuc->uc_mcontext); + if (error) + goto fail; + + error = do_lwp_create(l, newuc, SCARG(uap, flags), &lid); + if (error) + goto fail; + + /* + * do not free ucontext in case of an error here, + * the lwp will actually run and access it + */ + return copyout(&lid, SCARG(uap, new_lwp), sizeof(lid)); + +fail: + kmem_free(newuc, sizeof(ucontext_t)); + return error; +} + +int sys__lwp_exit(struct lwp *l, const void *v, register_t *retval) { Index: src/sys/sys/lwp.h diff -u src/sys/sys/lwp.h:1.160 src/sys/sys/lwp.h:1.161 --- src/sys/sys/lwp.h:1.160 Sun Feb 19 21:06:58 2012 +++ src/sys/sys/lwp.h Mon May 21 14:15:19 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: lwp.h,v 1.160 2012/02/19 21:06:58 rmind Exp $ */ +/* $NetBSD: lwp.h,v 1.161 2012/05/21 14:15:19 martin Exp $ */ /*- * Copyright (c) 2001, 2006, 2007, 2008, 2009, 2010 @@ -325,6 +325,7 @@ void lwp_need_userret(lwp_t *); void lwp_free(lwp_t *, bool, bool); uint64_t lwp_pctr(void); int lwp_setprivate(lwp_t *, void *); +int do_lwp_create(lwp_t *, void *, u_long, lwpid_t *); void lwpinit_specificdata(void); int lwp_specific_key_create(specificdata_key_t *, specificdata_dtor_t); Index: src/sys/sys/ucontext.h diff -u src/sys/sys/ucontext.h:1.15 src/sys/sys/ucontext.h:1.16 --- src/sys/sys/ucontext.h:1.15 Sun Mar 18 17:59:57 2012 +++ src/sys/sys/ucontext.h Mon May 21 14:15:19 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: ucontext.h,v 1.15 2012/03/18 17:59:57 tsutsui Exp $ */ +/* $NetBSD: ucontext.h,v 1.16 2012/05/21 14:15:19 martin Exp $ */ /*- * Copyright (c) 1999, 2003 The NetBSD Foundation, Inc. @@ -85,6 +85,7 @@ void getucontext(struct lwp *, ucontext_ int setucontext(struct lwp *, const ucontext_t *); void cpu_getmcontext(struct lwp *, mcontext_t *, unsigned int *); int cpu_setmcontext(struct lwp *, const mcontext_t *, unsigned int); +int cpu_mcontext_validate(struct lwp *, const mcontext_t *); #endif /* _KERNEL */ #endif /* !_SYS_UCONTEXT_H_ */ Index: src/tests/lib/libc/sys/Makefile diff -u src/tests/lib/libc/sys/Makefile:1.22 src/tests/lib/libc/sys/Makefile:1.23 --- src/tests/lib/libc/sys/Makefile:1.22 Fri Apr 20 12:11:29 2012 +++ src/tests/lib/libc/sys/Makefile Mon May 21 14:15:19 2012 @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.22 2012/04/20 12:11:29 jruoho Exp $ +# $NetBSD: Makefile,v 1.23 2012/05/21 14:15:19 martin Exp $ MKMAN= no @@ -29,6 +29,7 @@ TESTS_C+= t_kill TESTS_C+= t_link TESTS_C+= t_listen TESTS_C+= t_lwp_ctl +TESTS_C+= t_lwp_create TESTS_C+= t_mincore TESTS_C+= t_mkdir TESTS_C+= t_mkfifo Added files: Index: src/tests/lib/libc/sys/t_lwp_create.c diff -u /dev/null src/tests/lib/libc/sys/t_lwp_create.c:1.1 --- /dev/null Mon May 21 14:15:20 2012 +++ src/tests/lib/libc/sys/t_lwp_create.c Mon May 21 14:15:19 2012 @@ -0,0 +1,247 @@ +/* $NetBSD: t_lwp_create.c,v 1.1 2012/05/21 14:15:19 martin Exp $ */ + +/*- + * Copyright (c) 2012 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * This code is partly based on code by Joel Sing <joel at sing.id.au> + */ + +#include <atf-c.h> +#include <lwp.h> +#include <stdio.h> +#include <stdlib.h> +#include <ucontext.h> +#include <inttypes.h> +#include <errno.h> + +#ifdef __alpha__ +#include <machine/alpha_cpu.h> +#endif +#ifdef __amd64__ +#include <machine/vmparam.h> +#include <machine/psl.h> +#endif +#ifdef __hppa__ +#include <machine/psl.h> +#endif +#ifdef __i386__ +#include <machine/segments.h> +#include <machine/psl.h> +#endif +#if defined(__m68k__) || defined(__sh3__) || defined __vax__ +#include <machine/psl.h> +#endif + +volatile lwpid_t the_lwp_id = 0; + +static void lwp_main_func(void* arg) +{ + the_lwp_id = _lwp_self(); + _lwp_exit(); +} + +/* + * Hard to docment - see usage examples below + */ +#define INVALID_UCONTEXT(ARCH,NAME,DESC) \ +static void ARCH##_##NAME(ucontext_t *); \ +ATF_TC(lwp_create_##ARCH##_fail_##NAME); \ +ATF_TC_HEAD(lwp_create_##ARCH##_fail_##NAME, tc) \ +{ \ + atf_tc_set_md_var(tc, "descr", "verify rejection of invalid ucontext " \ + "on " #ARCH " due to " DESC); \ +} \ + \ +ATF_TC_BODY(lwp_create_##ARCH##_fail_##NAME, tc) \ +{ \ + ucontext_t uc; \ + lwpid_t lid; \ + int error; \ + \ + getcontext(&uc); \ + uc.uc_flags = _UC_CPU; \ + ARCH##_##NAME(&uc); \ + \ + error = _lwp_create(&uc, 0, &lid); \ + ATF_REQUIRE(error != 0 && errno == EINVAL); \ +} \ +static void ARCH##_##NAME(ucontext_t *uc) \ +{ + + +ATF_TC(lwp_create_works); +ATF_TC_HEAD(lwp_create_works, tc) +{ + atf_tc_set_md_var(tc, "descr", "Verify creation of a lwp and waiting" + " for it to finish"); +} + +ATF_TC_BODY(lwp_create_works, tc) +{ + ucontext_t uc; + lwpid_t lid; + int error; + void *stack; + static const size_t ssize = 16*1024; + + stack = malloc(ssize); + _lwp_makecontext(&uc, lwp_main_func, NULL, NULL, stack, ssize); + + error = _lwp_create(&uc, 0, &lid); + ATF_REQUIRE(error == 0); + + error = _lwp_wait(lid, NULL); + ATF_REQUIRE(error == 0); + ATF_REQUIRE(lid == the_lwp_id); +} + +INVALID_UCONTEXT(generic, no_uc_cpu, "not setting cpu registers") + uc->uc_flags &= ~_UC_CPU; +} + +#ifdef __alpha__ +INVALID_UCONTEXT(alpha, pslset, "trying to clear the USERMODE flag") + uc->uc_mcontext.__gregs[_REG_PS] &= ~ALPHA_PSL_USERMODE; +} +INVALID_UCONTEXT(alpha, pslclr, "trying to set a 'must be zero' flag") + uc->uc_mcontext.__gregs[_REG_PS] |= ALPHA_PSL_IPL_HIGH; +} +#endif +#ifdef __amd64__ +INVALID_UCONTEXT(amd64, untouchable_rflags, "forbidden rflags changed") + uc->uc_mcontext.__gregs[_REG_RFLAGS] |= PSL_MBZ; +} +/* + * XXX: add invalid GS/DS selector tests + */ +INVALID_UCONTEXT(amd64, pc_too_high, + "instruction pointer outside userland address space") + uc->uc_mcontext.__gregs[_REG_RIP] = VM_MAXUSER_ADDRESS; +} +#endif +#ifdef __arm__ +INVALID_UCONTEXT(arm, invalid_mode, "psr or r15 set to non-user-mode") + uc->uc_mcontext.__gregs[_REG_PC] |= 0x1f /*PSR_SYS32_MODE*/; + uc->uc_mcontext.__gregs[_REG_CPSR] |= 0x03 /*R15_MODE_SVC*/; +} +#endif +#ifdef __hppa__ +INVALID_UCONTEXT(hppa, invalid_1, "set illegal bits in psw") + uc->uc_mcontext.__gregs[_REG_PSW] |= PSW_MBZ; +} +INVALID_UCONTEXT(hppa, invalid_0, "clear illegal bits in psw") + uc->uc_mcontext.__gregs[_REG_PSW] &= ~PSW_MBS; +} +#endif +#ifdef __i386__ +INVALID_UCONTEXT(i386, untouchable_eflags, "changing forbidden eflags") + uc->uc_mcontext.__gregs[_REG_EFL] |= PSL_IOPL; +} +INVALID_UCONTEXT(i386, priv_escalation, "modifying priviledge level") + uc->uc_mcontext.__gregs[_REG_CS] &= ~SEL_RPL; +} +#endif +#ifdef __m68k__ +INVALID_UCONTEXT(m68k, invalid_ps_bits, + "setting forbidden bits in the ps register") + uc->uc_mcontext.__gregs[_REG_PS] |= (PSL_MBZ|PSL_IPL|PSL_S); +} +#endif +#ifdef __sh3__ +INVALID_UCONTEXT(sh3, modify_userstatic, + "modifying illegal bits in the status register") + uc->uc_mcontext.__gregs[_REG_SR] |= PSL_MD; +} +#endif +#ifdef __sparc__ +INVALID_UCONTEXT(sparc, pc_odd, "mis-aligned instruction pointer") + uc->uc_mcontext.__gregs[_REG_PC] = 0x100002; +} +INVALID_UCONTEXT(sparc, npc_odd, "mis-aligned next instruction pointer") + uc->uc_mcontext.__gregs[_REG_nPC] = 0x100002; +} +INVALID_UCONTEXT(sparc, pc_null, "NULL instruction pointer") + uc->uc_mcontext.__gregs[_REG_PC] = 0; +} +INVALID_UCONTEXT(sparc, npc_null, "NULL next instruction pointer") + uc->uc_mcontext.__gregs[_REG_nPC] = 0; +} +#endif +#ifdef __vax__ +INVALID_UCONTEXT(vax, psl_0, "clearing forbidden bits in psl") + uc->uc_mcontext.__gregs[_REG_PSL] &= ~(PSL_U | PSL_PREVU); +} +INVALID_UCONTEXT(vax, psl_1, "setting forbidden bits in psl") + uc->uc_mcontext.__gregs[_REG_PSL] |= PSL_IPL | PSL_IS; +} +INVALID_UCONTEXT(vax, psl_cm, "setting CM bit in psl") + uc->uc_mcontext.__gregs[_REG_PSL] |= PSL_CM; +} +#endif + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, lwp_create_works); + ATF_TP_ADD_TC(tp, lwp_create_generic_fail_no_uc_cpu); +#ifdef __alpha__ + ATF_TP_ADD_TC(tp, lwp_create_alpha_fail_pslset); + ATF_TP_ADD_TC(tp, lwp_create_alpha_fail_pslclr); +#endif +#ifdef __amd64__ + ATF_TP_ADD_TC(tp, lwp_create_amd64_fail_untouchable_rflags); + ATF_TP_ADD_TC(tp, lwp_create_amd64_fail_pc_too_high); +#endif +#ifdef __arm__ + ATF_TP_ADD_TC(tp, lwp_create_arm_fail_invalid_mode); +#endif +#ifdef __hppa__ + ATF_TP_ADD_TC(tp, lwp_create_hppa_fail_invalid_1); + ATF_TP_ADD_TC(tp, lwp_create_hppa_fail_invalid_0); +#endif +#ifdef __i386__ + ATF_TP_ADD_TC(tp, lwp_create_i386_fail_untouchable_eflags); + ATF_TP_ADD_TC(tp, lwp_create_i386_fail_priv_escalation); +#endif +#ifdef __m68k__ + ATF_TP_ADD_TC(tp, lwp_create_m68k_fail_invalid_ps_bits); +#endif +#ifdef __sh3__ + ATF_TP_ADD_TC(tp, lwp_create_sh3_fail_modify_userstatic); +#endif +#ifdef __sparc__ + ATF_TP_ADD_TC(tp, lwp_create_sparc_fail_pc_odd); + ATF_TP_ADD_TC(tp, lwp_create_sparc_fail_npc_odd); + ATF_TP_ADD_TC(tp, lwp_create_sparc_fail_pc_null); + ATF_TP_ADD_TC(tp, lwp_create_sparc_fail_npc_null); +#endif +#ifdef __vax__ + ATF_TP_ADD_TC(tp, lwp_create_vax_fail_psl_0); + ATF_TP_ADD_TC(tp, lwp_create_vax_fail_psl_1); + ATF_TP_ADD_TC(tp, lwp_create_vax_fail_psl_cm); +#endif + return atf_no_error(); +}