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.
This commit is contained in:
martin 2012-05-21 14:15:16 +00:00
parent f5ab9e9aed
commit 6c3cc552c2
26 changed files with 644 additions and 186 deletions

View File

@ -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

View File

@ -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 the location pointed to by
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 ,

View File

@ -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_t *mcp, unsigned int *flags)
}
}
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 mcontext_t *mcp, unsigned int flags)
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)

View File

@ -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 mcontext_t *mcp, unsigned int flags)
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 mcontext_t *mcp, unsigned int flags)
}
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;

View File

@ -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 *, void *, register_t *);
#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 mcontext32_t *mcp, unsigned int flags)
/*
* 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 struct netbsd32_sigcontext *scp)
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;

View File

@ -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 struct reg *regp)
* 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;

View File

@ -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__ */

View File

@ -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>
@ -204,18 +204,30 @@ cpu_getmcontext(struct lwp *l, mcontext_t *mcp, unsigned int *flags)
*flags |= _UC_TLSBASE;
}
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];

View File

@ -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>
@ -129,6 +129,44 @@ cpu_getmcontext(struct lwp *l, mcontext_t *mcp, unsigned int *flags)
*flags |= _UC_FPU;
}
int
cpu_mcontext_validate(struct lwp *l, const mcontext_t *mcp)
{
const __greg_t *gr = mcp->__gregs;
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.
*/
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_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;
}
#endif
return 0;
}
int
cpu_setmcontext(struct lwp *l, const mcontext_t *mcp, unsigned int flags)
{
@ -136,38 +174,12 @@ cpu_setmcontext(struct lwp *l, const mcontext_t *mcp, unsigned int flags)
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) {
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.
*/
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_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;
}
#endif
error = cpu_mcontext_validate(l, mcp);
if (error)
return error;
tf->tf_ipsw = gr[0] |
(hppa_cpu_ispa20_p() ? PSW_O : 0);

View File

@ -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"
@ -1763,6 +1763,26 @@ cpu_getmcontext(struct lwp *l, mcontext_t *mcp, unsigned int *flags)
}
}
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)
{
@ -1770,6 +1790,7 @@ cpu_setmcontext(struct lwp *l, const mcontext_t *mcp, unsigned int flags)
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 mcontext_t *mcp, unsigned int flags)
} 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];

View File

@ -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
@ -269,18 +269,30 @@ cpu_getmcontext(struct lwp *l, mcontext_t *mcp, u_int *flags)
}
}
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) {

View File

@ -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"
@ -362,17 +362,29 @@ cpu_getmcontext(struct lwp *l, mcontext_t *mcp, unsigned int *flags)
}
}
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)) {

View File

@ -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"
@ -265,12 +265,24 @@ cpu_getmcontext32(struct lwp *l, mcontext32_t *mc32, unsigned int *flagsp)
*flagsp |= _UC_TLSBASE;
}
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);

View File

@ -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"
@ -186,14 +186,25 @@ cpu_getmcontext(struct lwp *l, mcontext_t *mcp, unsigned int *flagp)
memset(&mcp->__vrf, 0, sizeof (mcp->__vrf));
}
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.

View File

@ -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"
@ -438,18 +438,32 @@ cpu_getmcontext(struct lwp *l, mcontext_t *mcp, unsigned int *flags)
memset(&mcp->__fpregs, 0, sizeof (mcp->__fpregs));
}
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];

View File

@ -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_t *mcp, unsigned int *flags)
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 mcontext_t *mcp, unsigned int flags)
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 mcontext_t *mcp, unsigned int flags)
#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);

View File

@ -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"
@ -2533,12 +2533,30 @@ cpu_getmcontext(struct lwp *l, mcontext_t *mcp, unsigned int *flags)
mcp->__xrs.__xrs_id = 0; /* Solaris extension? */
}
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 mcontext_t *mcp, unsigned int flags)
}
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 mcontext_t *mcp, unsigned int flags)
l->l_sigstk.ss_flags &= ~SS_ONSTACK;
mutex_exit(p->p_lock);
return (0);
return 0;
}
/*

View File

@ -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 struct netbsd32_sysarch_args *uap, registe
}
}
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 mcontext32_t *mcp, unsigned int flags)
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 mcontext32_t *mcp, unsigned int flags)
/* 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);
}

View File

@ -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_t *mcp, unsigned int *flags)
}
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 * const tf = l->l_md.md_utf;
const __greg_t *gr = mcp->__gregs;
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);
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;
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 mcontext_t *mcp, unsigned int flags)
if (flags & _UC_TLSBASE) {
void *tlsbase;
int error;
error = copyin((void *)tf->tf_sp, &tlsbase, sizeof(tlsbase));
if (error) {

View File

@ -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, const struct netbsd32__lwp_create_args *uap,
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

View File

@ -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) == __UCONTEXT32_SIZE);
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 */

View File

@ -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 struct sys__lwp_create_args *uap,
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);
@ -147,6 +124,49 @@ sys__lwp_create(struct lwp *l, const struct sys__lwp_create_args *uap,
return 0;
}
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)
{

View File

@ -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);

View File

@ -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_t *);
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_ */

View File

@ -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

View File

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