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();
+}

Reply via email to