2008-03-22 00:54:58 +03:00
|
|
|
/* $NetBSD: kern_exec.c,v 1.270 2008/03/21 21:55:00 ad Exp $ */
|
1994-06-29 10:29:24 +04:00
|
|
|
|
|
|
|
/*-
|
1996-10-01 03:18:43 +04:00
|
|
|
* Copyright (C) 1993, 1994, 1996 Christopher G. Demetriou
|
1994-06-29 10:29:24 +04:00
|
|
|
* Copyright (C) 1992 Wolfgang Solfrank.
|
|
|
|
* Copyright (C) 1992 TooLs GmbH.
|
|
|
|
* 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.
|
|
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
|
|
* must display the following acknowledgement:
|
|
|
|
* This product includes software developed by TooLs GmbH.
|
|
|
|
* 4. The name of TooLs GmbH may not be used to endorse or promote products
|
|
|
|
* derived from this software without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``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 TOOLS GMBH 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.
|
|
|
|
*/
|
|
|
|
|
2001-11-12 18:25:01 +03:00
|
|
|
#include <sys/cdefs.h>
|
2008-03-22 00:54:58 +03:00
|
|
|
__KERNEL_RCSID(0, "$NetBSD: kern_exec.c,v 1.270 2008/03/21 21:55:00 ad Exp $");
|
2001-11-12 18:25:01 +03:00
|
|
|
|
1998-06-26 01:17:15 +04:00
|
|
|
#include "opt_ktrace.h"
|
2000-11-21 03:37:49 +03:00
|
|
|
#include "opt_syscall_debug.h"
|
2003-09-15 04:33:35 +04:00
|
|
|
#include "opt_compat_netbsd.h"
|
2006-07-26 13:33:57 +04:00
|
|
|
#include "veriexec.h"
|
2006-11-22 05:02:51 +03:00
|
|
|
#include "opt_pax.h"
|
1998-02-10 17:08:44 +03:00
|
|
|
|
1994-06-29 10:29:24 +04:00
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/systm.h>
|
|
|
|
#include <sys/filedesc.h>
|
|
|
|
#include <sys/kernel.h>
|
|
|
|
#include <sys/proc.h>
|
|
|
|
#include <sys/mount.h>
|
|
|
|
#include <sys/malloc.h>
|
2008-01-02 22:44:36 +03:00
|
|
|
#include <sys/kmem.h>
|
1994-06-29 10:29:24 +04:00
|
|
|
#include <sys/namei.h>
|
|
|
|
#include <sys/vnode.h>
|
|
|
|
#include <sys/file.h>
|
|
|
|
#include <sys/acct.h>
|
|
|
|
#include <sys/exec.h>
|
|
|
|
#include <sys/ktrace.h>
|
|
|
|
#include <sys/resourcevar.h>
|
|
|
|
#include <sys/wait.h>
|
|
|
|
#include <sys/mman.h>
|
2002-08-28 11:16:33 +04:00
|
|
|
#include <sys/ras.h>
|
1994-06-29 10:29:24 +04:00
|
|
|
#include <sys/signalvar.h>
|
|
|
|
#include <sys/stat.h>
|
2000-11-21 03:37:49 +03:00
|
|
|
#include <sys/syscall.h>
|
2006-05-15 01:15:11 +04:00
|
|
|
#include <sys/kauth.h>
|
2007-11-13 02:11:58 +03:00
|
|
|
#include <sys/lwpctl.h>
|
2007-12-27 01:11:47 +03:00
|
|
|
#include <sys/pax.h>
|
2007-12-31 18:31:24 +03:00
|
|
|
#include <sys/cpu.h>
|
1994-06-29 10:29:24 +04:00
|
|
|
|
1994-10-20 07:22:35 +03:00
|
|
|
#include <sys/syscallargs.h>
|
2006-07-22 14:34:26 +04:00
|
|
|
#if NVERIEXEC > 0
|
2005-04-20 17:44:45 +04:00
|
|
|
#include <sys/verified_exec.h>
|
2006-07-22 14:34:26 +04:00
|
|
|
#endif /* NVERIEXEC > 0 */
|
1994-10-20 07:22:35 +03:00
|
|
|
|
1998-02-05 10:59:28 +03:00
|
|
|
#include <uvm/uvm_extern.h>
|
|
|
|
|
1994-06-29 10:29:24 +04:00
|
|
|
#include <machine/reg.h>
|
|
|
|
|
2007-04-22 12:29:55 +04:00
|
|
|
#include <compat/common/compat_util.h>
|
|
|
|
|
2003-08-24 21:52:28 +04:00
|
|
|
static int exec_sigcode_map(struct proc *, const struct emul *);
|
|
|
|
|
2001-07-16 00:49:40 +04:00
|
|
|
#ifdef DEBUG_EXEC
|
|
|
|
#define DPRINTF(a) uprintf a
|
|
|
|
#else
|
|
|
|
#define DPRINTF(a)
|
|
|
|
#endif /* DEBUG_EXEC */
|
|
|
|
|
2000-12-08 22:42:11 +03:00
|
|
|
/*
|
|
|
|
* Exec function switch:
|
|
|
|
*
|
|
|
|
* Note that each makecmds function is responsible for loading the
|
|
|
|
* exec package with the necessary functions for any exec-type-specific
|
|
|
|
* handling.
|
|
|
|
*
|
|
|
|
* Functions for specific exec types should be defined in their own
|
|
|
|
* header file.
|
|
|
|
*/
|
2001-02-26 23:43:25 +03:00
|
|
|
extern const struct execsw execsw_builtin[];
|
|
|
|
extern int nexecs_builtin;
|
|
|
|
static const struct execsw **execsw = NULL;
|
|
|
|
static int nexecs;
|
|
|
|
|
2002-08-26 01:18:15 +04:00
|
|
|
u_int exec_maxhdrsz; /* must not be static - netbsd32 needs it */
|
2000-12-08 22:42:11 +03:00
|
|
|
|
|
|
|
#ifdef LKM
|
|
|
|
/* list of supported emulations */
|
|
|
|
static
|
|
|
|
LIST_HEAD(emlist_head, emul_entry) el_head = LIST_HEAD_INITIALIZER(el_head);
|
|
|
|
struct emul_entry {
|
2001-02-26 23:43:25 +03:00
|
|
|
LIST_ENTRY(emul_entry) el_list;
|
|
|
|
const struct emul *el_emul;
|
|
|
|
int ro_entry;
|
2000-12-08 22:42:11 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
/* list of dynamically loaded execsw entries */
|
|
|
|
static
|
|
|
|
LIST_HEAD(execlist_head, exec_entry) ex_head = LIST_HEAD_INITIALIZER(ex_head);
|
|
|
|
struct exec_entry {
|
2001-02-26 23:43:25 +03:00
|
|
|
LIST_ENTRY(exec_entry) ex_list;
|
|
|
|
const struct execsw *es;
|
2000-12-08 22:42:11 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
/* structure used for building execw[] */
|
|
|
|
struct execsw_entry {
|
2001-02-26 23:43:25 +03:00
|
|
|
struct execsw_entry *next;
|
|
|
|
const struct execsw *es;
|
2000-12-08 22:42:11 +03:00
|
|
|
};
|
|
|
|
#endif /* LKM */
|
|
|
|
|
2000-11-21 03:37:49 +03:00
|
|
|
#ifdef SYSCALL_DEBUG
|
|
|
|
extern const char * const syscallnames[];
|
|
|
|
#endif
|
|
|
|
|
2004-03-26 20:13:37 +03:00
|
|
|
#ifdef COMPAT_16
|
2003-09-10 20:43:34 +04:00
|
|
|
extern char sigcode[], esigcode[];
|
2003-08-24 21:52:28 +04:00
|
|
|
struct uvm_object *emul_netbsd_object;
|
2003-09-10 20:43:34 +04:00
|
|
|
#endif
|
2003-08-24 21:52:28 +04:00
|
|
|
|
2005-07-10 08:20:34 +04:00
|
|
|
#ifndef __HAVE_SYSCALL_INTERN
|
|
|
|
void syscall(void);
|
|
|
|
#endif
|
|
|
|
|
2003-09-10 20:43:34 +04:00
|
|
|
/* NetBSD emul struct */
|
2000-11-21 03:37:49 +03:00
|
|
|
const struct emul emul_netbsd = {
|
|
|
|
"netbsd",
|
2000-12-01 15:28:30 +03:00
|
|
|
NULL, /* emulation path */
|
2000-12-11 08:28:59 +03:00
|
|
|
#ifndef __HAVE_MINIMAL_EMUL
|
2001-05-07 13:55:12 +04:00
|
|
|
EMUL_HAS_SYS___syscall,
|
2000-11-21 03:37:49 +03:00
|
|
|
NULL,
|
|
|
|
SYS_syscall,
|
2002-11-01 22:27:05 +03:00
|
|
|
SYS_NSYSENT,
|
2000-12-11 08:28:59 +03:00
|
|
|
#endif
|
2000-11-21 03:37:49 +03:00
|
|
|
sysent,
|
|
|
|
#ifdef SYSCALL_DEBUG
|
|
|
|
syscallnames,
|
|
|
|
#else
|
|
|
|
NULL,
|
|
|
|
#endif
|
2000-12-11 08:28:59 +03:00
|
|
|
sendsig,
|
2001-06-18 06:00:48 +04:00
|
|
|
trapsignal,
|
2003-12-20 22:01:29 +03:00
|
|
|
NULL,
|
2004-03-26 20:13:37 +03:00
|
|
|
#ifdef COMPAT_16
|
2000-11-21 03:37:49 +03:00
|
|
|
sigcode,
|
|
|
|
esigcode,
|
2003-08-24 21:52:28 +04:00
|
|
|
&emul_netbsd_object,
|
2003-09-10 20:43:34 +04:00
|
|
|
#else
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
#endif
|
2001-09-18 23:36:32 +04:00
|
|
|
setregs,
|
2000-12-01 22:41:49 +03:00
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
2003-12-20 21:22:16 +03:00
|
|
|
NULL,
|
|
|
|
NULL,
|
2000-12-11 08:28:59 +03:00
|
|
|
#ifdef __HAVE_SYSCALL_INTERN
|
|
|
|
syscall_intern,
|
|
|
|
#else
|
|
|
|
syscall,
|
|
|
|
#endif
|
- Introduce a e_fault field in struct proc to provide emulation specific
memory fault handler. IRIX uses irix_vm_fault, and all other emulation
use NULL, which means to use uvm_fault.
- While we are there, explicitely set to NULL the uninitialized fields in
struct emul: e_fault and e_sysctl on most ports
- e_fault is used by the trap handler, for now only on mips. In order to avoid
intrusive modifications in UVM, the function pointed by e_fault does not
has exactly the same protoype as uvm_fault:
int uvm_fault __P((struct vm_map *, vaddr_t, vm_fault_t, vm_prot_t));
int e_fault __P((struct proc *, vaddr_t, vm_fault_t, vm_prot_t));
- In IRIX share groups, all the VM space is shared, except one page.
This bounds us to have different VM spaces and synchronize modifications
to the VM space accross share group members. We need an IRIX specific hook
to the page fault handler in order to propagate VM space modifications
caused by page faults.
2002-09-22 01:14:54 +04:00
|
|
|
NULL,
|
|
|
|
NULL,
|
2005-03-26 08:12:34 +03:00
|
|
|
|
|
|
|
uvm_default_mapaddr,
|
2006-03-30 03:02:31 +04:00
|
|
|
NULL,
|
2007-02-10 00:55:00 +03:00
|
|
|
sizeof(ucontext_t),
|
2007-02-19 18:10:02 +03:00
|
|
|
startlwp,
|
2000-11-21 03:37:49 +03:00
|
|
|
};
|
|
|
|
|
2001-11-24 01:02:39 +03:00
|
|
|
#ifdef LKM
|
2000-12-08 22:42:11 +03:00
|
|
|
/*
|
|
|
|
* Exec lock. Used to control access to execsw[] structures.
|
|
|
|
* This must not be static so that netbsd32 can access it, too.
|
|
|
|
*/
|
2007-02-10 00:55:00 +03:00
|
|
|
krwlock_t exec_lock;
|
2004-03-05 14:30:50 +03:00
|
|
|
|
2001-02-26 23:43:25 +03:00
|
|
|
static void link_es(struct execsw_entry **, const struct execsw *);
|
2000-12-08 22:42:11 +03:00
|
|
|
#endif /* LKM */
|
|
|
|
|
2007-12-26 19:01:34 +03:00
|
|
|
static kmutex_t sigobject_lock;
|
|
|
|
|
1994-06-29 10:29:24 +04:00
|
|
|
/*
|
|
|
|
* check exec:
|
|
|
|
* given an "executable" described in the exec package's namei info,
|
|
|
|
* see what we can do with it.
|
|
|
|
*
|
|
|
|
* ON ENTRY:
|
|
|
|
* exec package with appropriate namei info
|
2005-12-11 15:16:03 +03:00
|
|
|
* lwp pointer of exec'ing lwp
|
1994-06-29 10:29:24 +04:00
|
|
|
* NO SELF-LOCKED VNODES
|
|
|
|
*
|
|
|
|
* ON EXIT:
|
|
|
|
* error: nothing held, etc. exec header still allocated.
|
1996-10-01 03:18:43 +04:00
|
|
|
* ok: filled exec package, executable's vnode (unlocked).
|
1994-06-29 10:29:24 +04:00
|
|
|
*
|
|
|
|
* EXEC SWITCH ENTRY:
|
|
|
|
* Locked vnode to check, exec package, proc.
|
|
|
|
*
|
|
|
|
* EXEC SWITCH EXIT:
|
1996-10-01 03:18:43 +04:00
|
|
|
* ok: return 0, filled exec package, executable's vnode (unlocked).
|
1994-06-29 10:29:24 +04:00
|
|
|
* error: destructive:
|
|
|
|
* everything deallocated execept exec header.
|
1996-09-27 03:34:46 +04:00
|
|
|
* non-destructive:
|
1996-10-01 03:18:43 +04:00
|
|
|
* error code, executable's vnode (unlocked),
|
1996-09-27 03:34:46 +04:00
|
|
|
* exec header unmodified.
|
1994-06-29 10:29:24 +04:00
|
|
|
*/
|
|
|
|
int
|
2005-07-17 02:47:18 +04:00
|
|
|
/*ARGSUSED*/
|
2006-12-20 14:35:29 +03:00
|
|
|
check_exec(struct lwp *l, struct exec_package *epp)
|
1994-06-29 10:29:24 +04:00
|
|
|
{
|
2001-02-26 23:43:25 +03:00
|
|
|
int error, i;
|
|
|
|
struct vnode *vp;
|
1994-06-29 10:29:24 +04:00
|
|
|
struct nameidata *ndp;
|
2001-02-26 23:43:25 +03:00
|
|
|
size_t resid;
|
1994-06-29 10:29:24 +04:00
|
|
|
|
|
|
|
ndp = epp->ep_ndp;
|
|
|
|
ndp->ni_cnd.cn_nameiop = LOOKUP;
|
2007-04-22 12:29:55 +04:00
|
|
|
ndp->ni_cnd.cn_flags = FOLLOW | LOCKLEAF | SAVENAME | TRYEMULROOT;
|
1994-06-29 10:29:24 +04:00
|
|
|
/* first get the vnode */
|
1996-02-04 05:15:01 +03:00
|
|
|
if ((error = namei(ndp)) != 0)
|
1994-06-29 10:29:24 +04:00
|
|
|
return error;
|
|
|
|
epp->ep_vp = vp = ndp->ni_vp;
|
|
|
|
|
1997-05-08 20:19:43 +04:00
|
|
|
/* check access and type */
|
1994-06-29 10:29:24 +04:00
|
|
|
if (vp->v_type != VREG) {
|
1997-04-10 23:45:40 +04:00
|
|
|
error = EACCES;
|
1994-06-29 10:29:24 +04:00
|
|
|
goto bad1;
|
|
|
|
}
|
2007-11-26 22:01:26 +03:00
|
|
|
if ((error = VOP_ACCESS(vp, VEXEC, l->l_cred)) != 0)
|
1997-05-08 20:19:43 +04:00
|
|
|
goto bad1;
|
1994-06-29 10:29:24 +04:00
|
|
|
|
|
|
|
/* get attributes */
|
2007-11-26 22:01:26 +03:00
|
|
|
if ((error = VOP_GETATTR(vp, epp->ep_vap, l->l_cred)) != 0)
|
1994-06-29 10:29:24 +04:00
|
|
|
goto bad1;
|
|
|
|
|
|
|
|
/* Check mount point */
|
|
|
|
if (vp->v_mount->mnt_flag & MNT_NOEXEC) {
|
|
|
|
error = EACCES;
|
|
|
|
goto bad1;
|
|
|
|
}
|
2001-06-15 21:24:19 +04:00
|
|
|
if (vp->v_mount->mnt_flag & MNT_NOSUID)
|
1997-05-08 14:19:10 +04:00
|
|
|
epp->ep_vap->va_mode &= ~(S_ISUID | S_ISGID);
|
1994-06-29 10:29:24 +04:00
|
|
|
|
|
|
|
/* try to open it */
|
2007-11-26 22:01:26 +03:00
|
|
|
if ((error = VOP_OPEN(vp, FREAD, l->l_cred)) != 0)
|
1994-06-29 10:29:24 +04:00
|
|
|
goto bad1;
|
|
|
|
|
1999-02-27 02:38:55 +03:00
|
|
|
/* unlock vp, since we need it unlocked from here on out. */
|
1998-03-01 05:20:01 +03:00
|
|
|
VOP_UNLOCK(vp, 0);
|
1996-10-01 03:18:43 +04:00
|
|
|
|
2006-07-22 14:34:26 +04:00
|
|
|
#if NVERIEXEC > 0
|
2007-02-08 03:26:50 +03:00
|
|
|
error = veriexec_verify(l, vp, ndp->ni_cnd.cn_pnbuf,
|
2006-12-20 14:35:29 +03:00
|
|
|
epp->ep_flags & EXEC_INDIR ? VERIEXEC_INDIRECT : VERIEXEC_DIRECT,
|
2007-02-08 03:26:50 +03:00
|
|
|
NULL);
|
|
|
|
if (error)
|
2006-12-23 20:23:51 +03:00
|
|
|
goto bad2;
|
2006-07-22 14:34:26 +04:00
|
|
|
#endif /* NVERIEXEC > 0 */
|
2002-10-29 15:31:20 +03:00
|
|
|
|
2006-11-22 05:02:51 +03:00
|
|
|
#ifdef PAX_SEGVGUARD
|
2007-02-22 09:34:42 +03:00
|
|
|
error = pax_segvguard(l, vp, ndp->ni_cnd.cn_pnbuf, false);
|
2006-12-23 20:23:51 +03:00
|
|
|
if (error)
|
|
|
|
goto bad2;
|
2006-11-22 05:02:51 +03:00
|
|
|
#endif /* PAX_SEGVGUARD */
|
|
|
|
|
1994-06-29 10:29:24 +04:00
|
|
|
/* now we have the file, get the exec header */
|
1996-02-04 05:15:01 +03:00
|
|
|
error = vn_rdwr(UIO_READ, vp, epp->ep_hdr, epp->ep_hdrlen, 0,
|
2006-07-24 02:06:03 +04:00
|
|
|
UIO_SYSSPACE, 0, l->l_cred, &resid, NULL);
|
1996-02-04 05:15:01 +03:00
|
|
|
if (error)
|
1994-06-29 10:29:24 +04:00
|
|
|
goto bad2;
|
|
|
|
epp->ep_hdrvalid = epp->ep_hdrlen - resid;
|
|
|
|
|
2001-02-14 21:21:42 +03:00
|
|
|
/*
|
|
|
|
* Set up default address space limits. Can be overridden
|
|
|
|
* by individual exec packages.
|
2004-03-05 14:30:50 +03:00
|
|
|
*
|
2007-02-05 17:34:29 +03:00
|
|
|
* XXX probably should be all done in the exec packages.
|
2001-02-14 21:21:42 +03:00
|
|
|
*/
|
|
|
|
epp->ep_vm_minaddr = VM_MIN_ADDRESS;
|
|
|
|
epp->ep_vm_maxaddr = VM_MAXUSER_ADDRESS;
|
1994-06-29 10:29:24 +04:00
|
|
|
/*
|
|
|
|
* set up the vmcmds for creation of the process
|
|
|
|
* address space
|
|
|
|
*/
|
|
|
|
error = ENOEXEC;
|
2007-04-22 12:29:55 +04:00
|
|
|
for (i = 0; i < nexecs; i++) {
|
1995-05-02 02:36:45 +04:00
|
|
|
int newerror;
|
|
|
|
|
2000-12-08 22:42:11 +03:00
|
|
|
epp->ep_esch = execsw[i];
|
2005-12-11 15:16:03 +03:00
|
|
|
newerror = (*execsw[i]->es_makecmds)(l, epp);
|
2007-04-22 12:29:55 +04:00
|
|
|
|
|
|
|
if (!newerror) {
|
|
|
|
/* Seems ok: check that entry point is sane */
|
|
|
|
if (epp->ep_entry > VM_MAXUSER_ADDRESS) {
|
|
|
|
error = ENOEXEC;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check limits */
|
|
|
|
if ((epp->ep_tsize > MAXTSIZ) ||
|
|
|
|
(epp->ep_dsize > (u_quad_t)l->l_proc->p_rlimit
|
|
|
|
[RLIMIT_DATA].rlim_cur)) {
|
|
|
|
error = ENOMEM;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (epp->ep_emul_root != NULL) {
|
|
|
|
vrele(epp->ep_emul_root);
|
|
|
|
epp->ep_emul_root = NULL;
|
|
|
|
}
|
|
|
|
if (epp->ep_interp != NULL) {
|
|
|
|
vrele(epp->ep_interp);
|
|
|
|
epp->ep_interp = NULL;
|
|
|
|
}
|
|
|
|
|
1995-05-02 02:36:45 +04:00
|
|
|
/* make sure the first "interesting" error code is saved. */
|
2007-04-22 12:29:55 +04:00
|
|
|
if (error == ENOEXEC)
|
1995-05-02 02:36:45 +04:00
|
|
|
error = newerror;
|
2000-11-21 03:37:49 +03:00
|
|
|
|
2007-04-22 12:29:55 +04:00
|
|
|
if (epp->ep_flags & EXEC_DESTR)
|
|
|
|
/* Error from "#!" code, tidied up by recursive call */
|
1994-06-29 10:29:24 +04:00
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
2007-10-02 16:01:17 +04:00
|
|
|
/* not found, error */
|
|
|
|
|
1994-06-29 10:29:24 +04:00
|
|
|
/*
|
|
|
|
* free any vmspace-creation commands,
|
|
|
|
* and release their references
|
|
|
|
*/
|
|
|
|
kill_vmcmds(&epp->ep_vmcmds);
|
|
|
|
|
|
|
|
bad2:
|
|
|
|
/*
|
1999-02-27 02:38:55 +03:00
|
|
|
* close and release the vnode, restore the old one, free the
|
1994-06-29 10:29:24 +04:00
|
|
|
* pathname buf, and punt.
|
|
|
|
*/
|
1999-02-27 02:38:55 +03:00
|
|
|
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
|
2007-11-26 22:01:26 +03:00
|
|
|
VOP_CLOSE(vp, FREAD, l->l_cred);
|
1999-02-27 02:38:55 +03:00
|
|
|
vput(vp);
|
2000-08-04 00:41:05 +04:00
|
|
|
PNBUF_PUT(ndp->ni_cnd.cn_pnbuf);
|
1994-06-29 10:29:24 +04:00
|
|
|
return error;
|
|
|
|
|
|
|
|
bad1:
|
|
|
|
/*
|
|
|
|
* free the namei pathname buffer, and put the vnode
|
|
|
|
* (which we don't yet have open).
|
|
|
|
*/
|
1996-10-01 03:18:43 +04:00
|
|
|
vput(vp); /* was still locked */
|
2000-08-04 00:41:05 +04:00
|
|
|
PNBUF_PUT(ndp->ni_cnd.cn_pnbuf);
|
1994-06-29 10:29:24 +04:00
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
2004-07-19 01:29:26 +04:00
|
|
|
#ifdef __MACHINE_STACK_GROWS_UP
|
|
|
|
#define STACK_PTHREADSPACE NBPG
|
|
|
|
#else
|
|
|
|
#define STACK_PTHREADSPACE 0
|
|
|
|
#endif
|
|
|
|
|
2005-07-12 00:15:26 +04:00
|
|
|
static int
|
|
|
|
execve_fetch_element(char * const *array, size_t index, char **value)
|
|
|
|
{
|
|
|
|
return copyin(array + index, value, sizeof(*value));
|
|
|
|
}
|
|
|
|
|
1994-06-29 10:29:24 +04:00
|
|
|
/*
|
|
|
|
* exec system call
|
|
|
|
*/
|
|
|
|
/* ARGSUSED */
|
1996-02-09 21:59:18 +03:00
|
|
|
int
|
2007-12-21 02:02:38 +03:00
|
|
|
sys_execve(struct lwp *l, const struct sys_execve_args *uap, register_t *retval)
|
1995-09-20 01:40:36 +04:00
|
|
|
{
|
2007-12-21 02:02:38 +03:00
|
|
|
/* {
|
2001-02-26 23:43:25 +03:00
|
|
|
syscallarg(const char *) path;
|
|
|
|
syscallarg(char * const *) argp;
|
|
|
|
syscallarg(char * const *) envp;
|
2007-12-21 02:02:38 +03:00
|
|
|
} */
|
2005-07-12 00:15:26 +04:00
|
|
|
|
|
|
|
return execve1(l, SCARG(uap, path), SCARG(uap, argp),
|
|
|
|
SCARG(uap, envp), execve_fetch_element);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
execve1(struct lwp *l, const char *path, char * const *args,
|
|
|
|
char * const *envs, execve_fetch_element_t fetch_element)
|
|
|
|
{
|
2002-08-26 01:18:15 +04:00
|
|
|
int error;
|
2001-02-26 23:43:25 +03:00
|
|
|
struct exec_package pack;
|
|
|
|
struct nameidata nid;
|
|
|
|
struct vattr attr;
|
2003-01-18 13:06:22 +03:00
|
|
|
struct proc *p;
|
2001-02-26 23:43:25 +03:00
|
|
|
char *argp;
|
|
|
|
char *dp, *sp;
|
|
|
|
long argc, envc;
|
2007-09-21 00:51:38 +04:00
|
|
|
size_t i, len;
|
2001-02-26 23:43:25 +03:00
|
|
|
char *stack;
|
|
|
|
struct ps_strings arginfo;
|
2006-02-09 22:18:56 +03:00
|
|
|
struct ps_strings *aip = &arginfo;
|
2001-02-26 23:43:25 +03:00
|
|
|
struct vmspace *vm;
|
2008-01-02 22:44:36 +03:00
|
|
|
struct exec_fakearg *tmpfap;
|
2001-02-26 23:43:25 +03:00
|
|
|
int szsigcode;
|
|
|
|
struct exec_vmcmd *base_vcp;
|
2007-02-10 00:55:00 +03:00
|
|
|
ksiginfo_t ksi;
|
|
|
|
ksiginfoq_t kq;
|
2007-12-27 01:11:47 +03:00
|
|
|
char *pathbuf;
|
2005-06-26 23:58:29 +04:00
|
|
|
size_t pathbuflen;
|
2001-02-26 23:43:25 +03:00
|
|
|
|
2003-01-18 13:06:22 +03:00
|
|
|
p = l->l_proc;
|
2007-02-10 00:55:00 +03:00
|
|
|
|
2008-02-25 00:46:04 +03:00
|
|
|
/*
|
|
|
|
* Check if we have exceeded our number of processes limit.
|
|
|
|
* This is so that we handle the case where a root daemon
|
|
|
|
* forked, ran setuid to become the desired user and is trying
|
|
|
|
* to exec. The obvious place to do the reference counting check
|
|
|
|
* is setuid(), but we don't do the reference counting check there
|
|
|
|
* like other OS's do because then all the programs that use setuid()
|
|
|
|
* must be modified to check the return code of setuid() and exit().
|
|
|
|
* It is dangerous to make setuid() fail, because it fails open and
|
|
|
|
* the program will continue to run as root. If we make it succeed
|
|
|
|
* and return an error code, again we are not enforcing the limit.
|
|
|
|
* The best place to enforce the limit is here, when the process tries
|
|
|
|
* to execute a new image, because eventually the process will need
|
|
|
|
* to call exec in order to do something useful.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if ((p->p_flag & PK_SUGID) &&
|
|
|
|
chgproccnt(kauth_cred_getuid(p->p_cred), 0) >
|
|
|
|
p->p_rlimit[RLIMIT_NPROC].rlim_cur)
|
|
|
|
return EAGAIN;
|
|
|
|
|
2002-01-12 00:16:27 +03:00
|
|
|
/*
|
2007-02-10 00:55:00 +03:00
|
|
|
* Drain existing references and forbid new ones. The process
|
|
|
|
* should be left alone until we're done here. This is necessary
|
|
|
|
* to avoid race conditions - e.g. in ptrace() - that might allow
|
|
|
|
* a local user to illicitly obtain elevated privileges.
|
2002-01-12 00:16:27 +03:00
|
|
|
*/
|
2007-11-07 03:23:13 +03:00
|
|
|
rw_enter(&p->p_reflock, RW_WRITER);
|
2002-01-12 00:16:27 +03:00
|
|
|
|
2001-02-26 23:43:25 +03:00
|
|
|
base_vcp = NULL;
|
2000-12-07 19:14:35 +03:00
|
|
|
/*
|
|
|
|
* Init the namei data to point the file user's program name.
|
|
|
|
* This is done here rather than in check_exec(), so that it's
|
|
|
|
* possible to override this settings if any of makecmd/probe
|
|
|
|
* functions call check_exec() recursively - for example,
|
|
|
|
* see exec_script_makecmds().
|
|
|
|
*/
|
2007-12-27 01:11:47 +03:00
|
|
|
pathbuf = PNBUF_GET();
|
|
|
|
error = copyinstr(path, pathbuf, MAXPATHLEN, &pathbuflen);
|
2007-09-21 00:51:38 +04:00
|
|
|
if (error) {
|
|
|
|
DPRINTF(("execve: copyinstr path %d", error));
|
2005-06-26 23:58:29 +04:00
|
|
|
goto clrflg;
|
2007-09-21 00:51:38 +04:00
|
|
|
}
|
2005-06-26 23:58:29 +04:00
|
|
|
|
2007-12-08 22:29:36 +03:00
|
|
|
NDINIT(&nid, LOOKUP, NOFOLLOW | TRYEMULROOT, UIO_SYSSPACE, pathbuf);
|
1994-06-29 10:29:24 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* initialize the fields of the exec package.
|
|
|
|
*/
|
2005-07-12 00:15:26 +04:00
|
|
|
pack.ep_name = path;
|
2008-01-02 22:44:36 +03:00
|
|
|
pack.ep_hdr = kmem_alloc(exec_maxhdrsz, KM_SLEEP);
|
1994-06-29 10:29:24 +04:00
|
|
|
pack.ep_hdrlen = exec_maxhdrsz;
|
|
|
|
pack.ep_hdrvalid = 0;
|
|
|
|
pack.ep_ndp = &nid;
|
1995-04-22 23:42:47 +04:00
|
|
|
pack.ep_emul_arg = NULL;
|
1994-06-29 10:29:24 +04:00
|
|
|
pack.ep_vmcmds.evs_cnt = 0;
|
|
|
|
pack.ep_vmcmds.evs_used = 0;
|
|
|
|
pack.ep_vap = &attr;
|
|
|
|
pack.ep_flags = 0;
|
2007-04-22 12:29:55 +04:00
|
|
|
pack.ep_emul_root = NULL;
|
|
|
|
pack.ep_interp = NULL;
|
|
|
|
pack.ep_esch = NULL;
|
1994-06-29 10:29:24 +04:00
|
|
|
|
2001-11-24 01:02:39 +03:00
|
|
|
#ifdef LKM
|
2007-02-10 00:55:00 +03:00
|
|
|
rw_enter(&exec_lock, RW_READER);
|
2001-11-24 01:02:39 +03:00
|
|
|
#endif
|
2000-12-08 22:42:11 +03:00
|
|
|
|
1994-06-29 10:29:24 +04:00
|
|
|
/* see if we can run it. */
|
2007-09-21 00:51:38 +04:00
|
|
|
if ((error = check_exec(l, &pack)) != 0) {
|
2007-12-27 01:49:19 +03:00
|
|
|
if (error != ENOENT) {
|
2007-12-27 01:11:47 +03:00
|
|
|
DPRINTF(("execve: check exec failed %d\n", error));
|
2007-12-27 01:49:19 +03:00
|
|
|
}
|
1994-06-29 10:29:24 +04:00
|
|
|
goto freehdr;
|
2007-09-21 00:51:38 +04:00
|
|
|
}
|
1994-06-29 10:29:24 +04:00
|
|
|
|
|
|
|
/* XXX -- THE FOLLOWING SECTION NEEDS MAJOR CLEANUP */
|
|
|
|
|
|
|
|
/* allocate an argument buffer */
|
2005-04-01 15:59:21 +04:00
|
|
|
argp = (char *) uvm_km_alloc(exec_map, NCARGS, 0,
|
|
|
|
UVM_KMF_PAGEABLE|UVM_KMF_WAITVA);
|
1994-06-29 10:29:24 +04:00
|
|
|
#ifdef DIAGNOSTIC
|
2005-08-05 15:14:32 +04:00
|
|
|
if (argp == NULL)
|
1994-06-29 10:29:24 +04:00
|
|
|
panic("execve: argp == NULL");
|
|
|
|
#endif
|
|
|
|
dp = argp;
|
|
|
|
argc = 0;
|
|
|
|
|
|
|
|
/* copy the fake args list, if there's one, freeing it as we go */
|
|
|
|
if (pack.ep_flags & EXEC_HASARGL) {
|
|
|
|
tmpfap = pack.ep_fa;
|
2008-01-02 22:44:36 +03:00
|
|
|
while (tmpfap->fa_arg != NULL) {
|
|
|
|
const char *cp;
|
1994-06-29 10:29:24 +04:00
|
|
|
|
2008-01-02 22:44:36 +03:00
|
|
|
cp = tmpfap->fa_arg;
|
1994-06-29 10:29:24 +04:00
|
|
|
while (*cp)
|
|
|
|
*dp++ = *cp++;
|
1996-02-04 05:15:01 +03:00
|
|
|
dp++;
|
1994-06-29 10:29:24 +04:00
|
|
|
|
2008-01-02 22:44:36 +03:00
|
|
|
kmem_free(tmpfap->fa_arg, tmpfap->fa_len);
|
1994-06-29 10:29:24 +04:00
|
|
|
tmpfap++; argc++;
|
|
|
|
}
|
2008-01-02 22:44:36 +03:00
|
|
|
kmem_free(pack.ep_fa, pack.ep_fa_len);
|
1994-06-29 10:29:24 +04:00
|
|
|
pack.ep_flags &= ~EXEC_HASARGL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now get argv & environment */
|
2005-07-12 00:15:26 +04:00
|
|
|
if (args == NULL) {
|
2007-09-21 00:51:38 +04:00
|
|
|
DPRINTF(("execve: null args\n"));
|
1994-06-29 10:29:24 +04:00
|
|
|
error = EINVAL;
|
|
|
|
goto bad;
|
|
|
|
}
|
2005-07-12 00:15:26 +04:00
|
|
|
/* 'i' will index the argp/envp element to be retrieved */
|
|
|
|
i = 0;
|
1994-06-29 10:29:24 +04:00
|
|
|
if (pack.ep_flags & EXEC_SKIPARG)
|
2005-07-12 00:15:26 +04:00
|
|
|
i++;
|
1994-06-29 10:29:24 +04:00
|
|
|
|
|
|
|
while (1) {
|
|
|
|
len = argp + ARG_MAX - dp;
|
2007-09-21 00:51:38 +04:00
|
|
|
if ((error = (*fetch_element)(args, i, &sp)) != 0) {
|
|
|
|
DPRINTF(("execve: fetch_element args %d\n", error));
|
1994-06-29 10:29:24 +04:00
|
|
|
goto bad;
|
2007-09-21 00:51:38 +04:00
|
|
|
}
|
1994-06-29 10:29:24 +04:00
|
|
|
if (!sp)
|
|
|
|
break;
|
1996-02-04 05:15:01 +03:00
|
|
|
if ((error = copyinstr(sp, dp, len, &len)) != 0) {
|
2007-09-21 00:51:38 +04:00
|
|
|
DPRINTF(("execve: copyinstr args %d\n", error));
|
1994-06-29 10:29:24 +04:00
|
|
|
if (error == ENAMETOOLONG)
|
|
|
|
error = E2BIG;
|
|
|
|
goto bad;
|
|
|
|
}
|
2007-08-15 16:07:23 +04:00
|
|
|
ktrexecarg(dp, len - 1);
|
1994-06-29 10:29:24 +04:00
|
|
|
dp += len;
|
2005-07-12 00:15:26 +04:00
|
|
|
i++;
|
1994-06-29 10:29:24 +04:00
|
|
|
argc++;
|
|
|
|
}
|
|
|
|
|
|
|
|
envc = 0;
|
1996-02-04 05:15:01 +03:00
|
|
|
/* environment need not be there */
|
2005-07-12 00:15:26 +04:00
|
|
|
if (envs != NULL) {
|
|
|
|
i = 0;
|
1994-06-29 10:29:24 +04:00
|
|
|
while (1) {
|
|
|
|
len = argp + ARG_MAX - dp;
|
2007-09-21 00:51:38 +04:00
|
|
|
if ((error = (*fetch_element)(envs, i, &sp)) != 0) {
|
|
|
|
DPRINTF(("execve: fetch_element env %d\n", error));
|
1994-06-29 10:29:24 +04:00
|
|
|
goto bad;
|
2007-09-21 00:51:38 +04:00
|
|
|
}
|
1994-06-29 10:29:24 +04:00
|
|
|
if (!sp)
|
|
|
|
break;
|
1996-02-04 05:15:01 +03:00
|
|
|
if ((error = copyinstr(sp, dp, len, &len)) != 0) {
|
2007-09-21 00:51:38 +04:00
|
|
|
DPRINTF(("execve: copyinstr env %d\n", error));
|
1994-06-29 10:29:24 +04:00
|
|
|
if (error == ENAMETOOLONG)
|
|
|
|
error = E2BIG;
|
|
|
|
goto bad;
|
|
|
|
}
|
2007-08-15 16:07:23 +04:00
|
|
|
ktrexecenv(dp, len - 1);
|
1994-06-29 10:29:24 +04:00
|
|
|
dp += len;
|
2005-07-12 00:15:26 +04:00
|
|
|
i++;
|
1994-06-29 10:29:24 +04:00
|
|
|
envc++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1995-02-22 04:39:56 +03:00
|
|
|
dp = (char *) ALIGN(dp);
|
|
|
|
|
2007-04-22 12:29:55 +04:00
|
|
|
szsigcode = pack.ep_esch->es_emul->e_esigcode -
|
|
|
|
pack.ep_esch->es_emul->e_sigcode;
|
1995-04-08 02:33:23 +04:00
|
|
|
|
2008-01-20 13:15:50 +03:00
|
|
|
#ifdef __MACHINE_STACK_GROWS_UP
|
|
|
|
/* See big comment lower down */
|
|
|
|
#define RTLD_GAP 32
|
|
|
|
#else
|
|
|
|
#define RTLD_GAP 0
|
|
|
|
#endif
|
|
|
|
|
1994-06-29 10:29:24 +04:00
|
|
|
/* Now check if args & environ fit into new stack */
|
1999-12-30 18:59:26 +03:00
|
|
|
if (pack.ep_flags & EXEC_32)
|
2007-04-22 12:29:55 +04:00
|
|
|
len = ((argc + envc + 2 + pack.ep_esch->es_arglen) *
|
2008-01-20 13:15:50 +03:00
|
|
|
sizeof(int) + sizeof(int) + dp + RTLD_GAP +
|
2004-07-19 01:29:26 +04:00
|
|
|
szsigcode + sizeof(struct ps_strings) + STACK_PTHREADSPACE)
|
|
|
|
- argp;
|
1999-12-30 18:59:26 +03:00
|
|
|
else
|
2007-04-22 12:29:55 +04:00
|
|
|
len = ((argc + envc + 2 + pack.ep_esch->es_arglen) *
|
2008-01-20 13:15:50 +03:00
|
|
|
sizeof(char *) + sizeof(int) + dp + RTLD_GAP +
|
2004-07-19 01:29:26 +04:00
|
|
|
szsigcode + sizeof(struct ps_strings) + STACK_PTHREADSPACE)
|
|
|
|
- argp;
|
1995-04-22 23:42:47 +04:00
|
|
|
|
2007-12-28 20:14:50 +03:00
|
|
|
#ifdef PAX_ASLR
|
|
|
|
if (pax_aslr_active(l))
|
|
|
|
len += (arc4random() % PAGE_SIZE);
|
|
|
|
#endif /* PAX_ASLR */
|
|
|
|
|
2007-03-10 01:25:56 +03:00
|
|
|
#ifdef STACKLALIGN /* arm, etc. */
|
|
|
|
len = STACKALIGN(len); /* make the stack "safely" aligned */
|
|
|
|
#else
|
1994-06-29 10:29:24 +04:00
|
|
|
len = ALIGN(len); /* make the stack "safely" aligned */
|
2007-03-10 01:25:56 +03:00
|
|
|
#endif
|
1994-06-29 10:29:24 +04:00
|
|
|
|
|
|
|
if (len > pack.ep_ssize) { /* in effect, compare to initial limit */
|
2007-09-21 00:51:38 +04:00
|
|
|
DPRINTF(("execve: stack limit exceeded %zu\n", len));
|
1994-06-29 10:29:24 +04:00
|
|
|
error = ENOMEM;
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
|
2007-02-10 00:55:00 +03:00
|
|
|
/* Get rid of other LWPs. */
|
|
|
|
if (p->p_nlwps > 1) {
|
|
|
|
mutex_enter(&p->p_smutex);
|
|
|
|
exit_lwps(l);
|
|
|
|
mutex_exit(&p->p_smutex);
|
|
|
|
}
|
2003-01-18 13:06:22 +03:00
|
|
|
KDASSERT(p->p_nlwps == 1);
|
|
|
|
|
2007-11-13 02:11:58 +03:00
|
|
|
/* Destroy any lwpctl info. */
|
|
|
|
if (p->p_lwpctl != NULL)
|
|
|
|
lwp_ctl_exit();
|
|
|
|
|
2003-01-18 13:06:22 +03:00
|
|
|
/* This is now LWP 1 */
|
|
|
|
l->l_lid = 1;
|
|
|
|
p->p_nlwpid = 1;
|
|
|
|
|
|
|
|
/* Remove POSIX timers */
|
|
|
|
timers_free(p, TIMERS_POSIX);
|
|
|
|
|
1994-06-29 10:29:24 +04:00
|
|
|
/* adjust "active stack depth" for process VSZ */
|
|
|
|
pack.ep_ssize = len; /* maybe should go elsewhere, but... */
|
|
|
|
|
1997-12-31 10:47:41 +03:00
|
|
|
/*
|
|
|
|
* Do whatever is necessary to prepare the address space
|
|
|
|
* for remapping. Note that this might replace the current
|
|
|
|
* vmspace with another!
|
|
|
|
*/
|
2003-01-18 13:06:22 +03:00
|
|
|
uvmspace_exec(l, pack.ep_vm_minaddr, pack.ep_vm_maxaddr);
|
1994-06-29 10:29:24 +04:00
|
|
|
|
2004-06-27 04:41:03 +04:00
|
|
|
/* record proc's vnode, for use by procfs and others */
|
|
|
|
if (p->p_textvp)
|
|
|
|
vrele(p->p_textvp);
|
|
|
|
VREF(pack.ep_vp);
|
|
|
|
p->p_textvp = pack.ep_vp;
|
|
|
|
|
1994-06-29 10:29:24 +04:00
|
|
|
/* Now map address space */
|
1997-12-31 10:47:41 +03:00
|
|
|
vm = p->p_vmspace;
|
2007-03-05 07:59:19 +03:00
|
|
|
vm->vm_taddr = (void *)pack.ep_taddr;
|
1994-06-29 10:29:24 +04:00
|
|
|
vm->vm_tsize = btoc(pack.ep_tsize);
|
2007-03-05 07:59:19 +03:00
|
|
|
vm->vm_daddr = (void*)pack.ep_daddr;
|
1994-06-29 10:29:24 +04:00
|
|
|
vm->vm_dsize = btoc(pack.ep_dsize);
|
|
|
|
vm->vm_ssize = btoc(pack.ep_ssize);
|
2007-03-05 07:59:19 +03:00
|
|
|
vm->vm_maxsaddr = (void *)pack.ep_maxsaddr;
|
|
|
|
vm->vm_minsaddr = (void *)pack.ep_minsaddr;
|
1994-06-29 10:29:24 +04:00
|
|
|
|
2007-12-27 01:11:47 +03:00
|
|
|
#ifdef PAX_ASLR
|
|
|
|
pax_aslr_init(l, vm);
|
|
|
|
#endif /* PAX_ASLR */
|
|
|
|
|
1994-06-29 10:29:24 +04:00
|
|
|
/* create the new process's VM space by running the vmcmds */
|
|
|
|
#ifdef DIAGNOSTIC
|
|
|
|
if (pack.ep_vmcmds.evs_used == 0)
|
|
|
|
panic("execve: no vmcmds");
|
|
|
|
#endif
|
|
|
|
for (i = 0; i < pack.ep_vmcmds.evs_used && !error; i++) {
|
|
|
|
struct exec_vmcmd *vcp;
|
|
|
|
|
|
|
|
vcp = &pack.ep_vmcmds.evs_cmds[i];
|
2000-07-13 05:24:04 +04:00
|
|
|
if (vcp->ev_flags & VMCMD_RELATIVE) {
|
|
|
|
#ifdef DIAGNOSTIC
|
|
|
|
if (base_vcp == NULL)
|
|
|
|
panic("execve: relative vmcmd with no base");
|
|
|
|
if (vcp->ev_flags & VMCMD_BASE)
|
|
|
|
panic("execve: illegal base & relative vmcmd");
|
|
|
|
#endif
|
|
|
|
vcp->ev_addr += base_vcp->ev_addr;
|
|
|
|
}
|
2005-12-11 15:16:03 +03:00
|
|
|
error = (*vcp->ev_proc)(l, vcp);
|
2001-07-16 00:49:40 +04:00
|
|
|
#ifdef DEBUG_EXEC
|
2000-06-21 09:43:33 +04:00
|
|
|
if (error) {
|
2007-09-21 00:51:38 +04:00
|
|
|
size_t j;
|
2001-07-16 00:49:40 +04:00
|
|
|
struct exec_vmcmd *vp = &pack.ep_vmcmds.evs_cmds[0];
|
|
|
|
for (j = 0; j <= i; j++)
|
|
|
|
uprintf(
|
2007-09-21 00:51:38 +04:00
|
|
|
"vmcmd[%zu] = %#lx/%#lx fd@%#lx prot=0%o flags=%d\n",
|
2001-07-16 00:49:40 +04:00
|
|
|
j, vp[j].ev_addr, vp[j].ev_len,
|
|
|
|
vp[j].ev_offset, vp[j].ev_prot,
|
|
|
|
vp[j].ev_flags);
|
2000-06-21 09:43:33 +04:00
|
|
|
}
|
2001-07-16 00:49:40 +04:00
|
|
|
#endif /* DEBUG_EXEC */
|
2000-07-13 05:24:04 +04:00
|
|
|
if (vcp->ev_flags & VMCMD_BASE)
|
|
|
|
base_vcp = vcp;
|
1994-06-29 10:29:24 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* free the vmspace-creation commands, and release their references */
|
|
|
|
kill_vmcmds(&pack.ep_vmcmds);
|
|
|
|
|
2004-06-27 04:41:03 +04:00
|
|
|
vn_lock(pack.ep_vp, LK_EXCLUSIVE | LK_RETRY);
|
2007-11-26 22:01:26 +03:00
|
|
|
VOP_CLOSE(pack.ep_vp, FREAD, l->l_cred);
|
2004-06-27 04:41:03 +04:00
|
|
|
vput(pack.ep_vp);
|
|
|
|
|
1994-06-29 10:29:24 +04:00
|
|
|
/* if an error happened, deallocate and punt */
|
2000-06-21 09:43:33 +04:00
|
|
|
if (error) {
|
2007-09-21 00:51:38 +04:00
|
|
|
DPRINTF(("execve: vmcmd %zu failed: %d\n", i - 1, error));
|
1994-06-29 10:29:24 +04:00
|
|
|
goto exec_abort;
|
2000-06-21 09:43:33 +04:00
|
|
|
}
|
1994-06-29 10:29:24 +04:00
|
|
|
|
|
|
|
/* remember information about the process */
|
|
|
|
arginfo.ps_nargvstr = argc;
|
|
|
|
arginfo.ps_nenvstr = envc;
|
|
|
|
|
2007-12-03 05:06:57 +03:00
|
|
|
/* set command name & other accounting info */
|
|
|
|
i = min(nid.ni_cnd.cn_namelen, MAXCOMLEN);
|
|
|
|
(void)memcpy(p->p_comm, nid.ni_cnd.cn_nameptr, i);
|
|
|
|
p->p_comm[i] = '\0';
|
|
|
|
|
|
|
|
dp = PNBUF_GET();
|
|
|
|
/*
|
|
|
|
* If the path starts with /, we don't need to do any work.
|
|
|
|
* This handles the majority of the cases.
|
|
|
|
* In the future perhaps we could canonicalize it?
|
|
|
|
*/
|
|
|
|
if (pathbuf[0] == '/')
|
|
|
|
(void)strlcpy(pack.ep_path = dp, pathbuf, MAXPATHLEN);
|
|
|
|
#ifdef notyet
|
|
|
|
/*
|
|
|
|
* Although this works most of the time [since the entry was just
|
|
|
|
* entered in the cache] we don't use it because it theoretically
|
|
|
|
* can fail and it is not the cleanest interface, because there
|
|
|
|
* could be races. When the namei cache is re-written, this can
|
|
|
|
* be changed to use the appropriate function.
|
|
|
|
*/
|
|
|
|
else if (!(error = vnode_to_path(dp, MAXPATHLEN, p->p_textvp, l, p)))
|
|
|
|
pack.ep_path = dp;
|
|
|
|
#endif
|
|
|
|
else {
|
2007-12-03 05:20:24 +03:00
|
|
|
#ifdef notyet
|
2007-12-03 05:06:57 +03:00
|
|
|
printf("Cannot get path for pid %d [%s] (error %d)",
|
|
|
|
(int)p->p_pid, p->p_comm, error);
|
|
|
|
#endif
|
|
|
|
pack.ep_path = NULL;
|
|
|
|
PNBUF_PUT(dp);
|
|
|
|
}
|
|
|
|
|
2002-11-18 01:53:46 +03:00
|
|
|
stack = (char *)STACK_ALLOC(STACK_GROW(vm->vm_minsaddr,
|
2004-07-19 01:29:26 +04:00
|
|
|
STACK_PTHREADSPACE + sizeof(struct ps_strings) + szsigcode),
|
2002-11-18 01:53:46 +03:00
|
|
|
len - (sizeof(struct ps_strings) + szsigcode));
|
2008-01-20 13:15:50 +03:00
|
|
|
|
2002-11-18 01:53:46 +03:00
|
|
|
#ifdef __MACHINE_STACK_GROWS_UP
|
|
|
|
/*
|
|
|
|
* The copyargs call always copies into lower addresses
|
|
|
|
* first, moving towards higher addresses, starting with
|
2004-03-05 14:30:50 +03:00
|
|
|
* the stack pointer that we give. When the stack grows
|
|
|
|
* down, this puts argc/argv/envp very shallow on the
|
2008-01-20 13:15:50 +03:00
|
|
|
* stack, right at the first user stack pointer.
|
|
|
|
* When the stack grows up, the situation is reversed.
|
2002-11-18 01:53:46 +03:00
|
|
|
*
|
|
|
|
* Normally, this is no big deal. But the ld_elf.so _rtld()
|
2004-03-05 14:30:50 +03:00
|
|
|
* function expects to be called with a single pointer to
|
|
|
|
* a region that has a few words it can stash values into,
|
2002-11-18 01:53:46 +03:00
|
|
|
* followed by argc/argv/envp. When the stack grows down,
|
|
|
|
* it's easy to decrement the stack pointer a little bit to
|
|
|
|
* allocate the space for these few words and pass the new
|
|
|
|
* stack pointer to _rtld. When the stack grows up, however,
|
2003-08-24 21:52:28 +04:00
|
|
|
* a few words before argc is part of the signal trampoline, XXX
|
2002-11-18 01:53:46 +03:00
|
|
|
* so we have a problem.
|
|
|
|
*
|
2004-03-05 14:30:50 +03:00
|
|
|
* Instead of changing how _rtld works, we take the easy way
|
2008-01-20 13:15:50 +03:00
|
|
|
* out and steal 32 bytes before we call copyargs.
|
|
|
|
* This extra space was allowed for when 'len' was calculated.
|
2002-11-18 01:53:46 +03:00
|
|
|
*/
|
2008-01-20 13:15:50 +03:00
|
|
|
stack += RTLD_GAP;
|
2002-11-18 01:53:46 +03:00
|
|
|
#endif /* __MACHINE_STACK_GROWS_UP */
|
|
|
|
|
1995-04-22 23:42:47 +04:00
|
|
|
/* Now copy argc, args & environ to new stack */
|
2007-04-22 12:29:55 +04:00
|
|
|
error = (*pack.ep_esch->es_copyargs)(l, &pack, &arginfo, &stack, argp);
|
2007-12-03 05:06:57 +03:00
|
|
|
if (pack.ep_path) {
|
|
|
|
PNBUF_PUT(pack.ep_path);
|
|
|
|
pack.ep_path = NULL;
|
|
|
|
}
|
2001-07-30 01:22:42 +04:00
|
|
|
if (error) {
|
|
|
|
DPRINTF(("execve: copyargs failed %d\n", error));
|
1994-06-29 10:29:24 +04:00
|
|
|
goto exec_abort;
|
2000-06-21 09:43:33 +04:00
|
|
|
}
|
2001-07-30 01:22:42 +04:00
|
|
|
/* Move the stack back to original point */
|
2002-11-18 01:53:46 +03:00
|
|
|
stack = (char *)STACK_GROW(vm->vm_minsaddr, len);
|
1994-06-29 10:29:24 +04:00
|
|
|
|
2000-09-28 23:05:06 +04:00
|
|
|
/* fill process ps_strings info */
|
2004-07-19 01:29:26 +04:00
|
|
|
p->p_psstr = (struct ps_strings *)
|
|
|
|
STACK_ALLOC(STACK_GROW(vm->vm_minsaddr, STACK_PTHREADSPACE),
|
2002-11-18 01:53:46 +03:00
|
|
|
sizeof(struct ps_strings));
|
2000-09-28 23:05:06 +04:00
|
|
|
p->p_psargv = offsetof(struct ps_strings, ps_argvstr);
|
|
|
|
p->p_psnargv = offsetof(struct ps_strings, ps_nargvstr);
|
|
|
|
p->p_psenv = offsetof(struct ps_strings, ps_envstr);
|
|
|
|
p->p_psnenv = offsetof(struct ps_strings, ps_nenvstr);
|
|
|
|
|
1994-06-29 10:29:24 +04:00
|
|
|
/* copy out the process's ps_strings structure */
|
2006-02-09 22:18:56 +03:00
|
|
|
if ((error = copyout(aip, (char *)p->p_psstr,
|
2001-07-30 01:22:42 +04:00
|
|
|
sizeof(arginfo))) != 0) {
|
2001-07-16 00:49:40 +04:00
|
|
|
DPRINTF(("execve: ps_strings copyout %p->%p size %ld failed\n",
|
2006-02-09 22:18:56 +03:00
|
|
|
aip, (char *)p->p_psstr, (long)sizeof(arginfo)));
|
1994-06-29 10:29:24 +04:00
|
|
|
goto exec_abort;
|
2000-06-21 09:43:33 +04:00
|
|
|
}
|
1994-06-29 10:29:24 +04:00
|
|
|
|
2008-03-22 00:54:58 +03:00
|
|
|
fd_closeexec(); /* handle close on exec */
|
1994-06-29 10:29:24 +04:00
|
|
|
execsigs(p); /* reset catched signals */
|
2004-03-05 14:30:50 +03:00
|
|
|
|
2003-01-18 13:06:22 +03:00
|
|
|
l->l_ctxlink = NULL; /* reset ucontext link */
|
1994-06-29 10:29:24 +04:00
|
|
|
|
|
|
|
|
2007-12-03 05:06:57 +03:00
|
|
|
p->p_acflag &= ~AFORK;
|
2007-12-26 19:01:34 +03:00
|
|
|
mutex_enter(&p->p_mutex);
|
2007-02-18 01:31:36 +03:00
|
|
|
p->p_flag |= PK_EXEC;
|
2007-12-26 19:01:34 +03:00
|
|
|
mutex_exit(&p->p_mutex);
|
2007-02-10 00:55:00 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Stop profiling.
|
|
|
|
*/
|
|
|
|
if ((p->p_stflag & PST_PROFIL) != 0) {
|
|
|
|
mutex_spin_enter(&p->p_stmutex);
|
|
|
|
stopprofclock(p);
|
|
|
|
mutex_spin_exit(&p->p_stmutex);
|
1994-06-29 10:29:24 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2007-02-10 00:55:00 +03:00
|
|
|
* It's OK to test PS_PPWAIT unlocked here, as other LWPs have
|
|
|
|
* exited and exec()/exit() are the only places it will be cleared.
|
1994-06-29 10:29:24 +04:00
|
|
|
*/
|
2007-02-10 00:55:00 +03:00
|
|
|
if ((p->p_sflag & PS_PPWAIT) != 0) {
|
2007-03-09 17:11:22 +03:00
|
|
|
mutex_enter(&proclist_lock);
|
2007-02-10 00:55:00 +03:00
|
|
|
mutex_enter(&p->p_smutex);
|
|
|
|
p->p_sflag &= ~PS_PPWAIT;
|
|
|
|
cv_broadcast(&p->p_pptr->p_waitcv);
|
|
|
|
mutex_exit(&p->p_smutex);
|
2007-03-09 17:11:22 +03:00
|
|
|
mutex_exit(&proclist_lock);
|
2007-02-10 00:55:00 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Deal with set[ug]id. MNT_NOSUID has already been used to disable
|
|
|
|
* s[ug]id. It's OK to check for PSL_TRACED here as we have blocked
|
|
|
|
* out additional references on the process for the moment.
|
|
|
|
*/
|
|
|
|
if ((p->p_slflag & PSL_TRACED) == 0 &&
|
2001-06-15 21:24:19 +04:00
|
|
|
|
|
|
|
(((attr.va_mode & S_ISUID) != 0 &&
|
2006-07-20 01:11:37 +04:00
|
|
|
kauth_cred_geteuid(l->l_cred) != attr.va_uid) ||
|
2001-06-15 21:24:19 +04:00
|
|
|
|
|
|
|
((attr.va_mode & S_ISGID) != 0 &&
|
2006-07-20 01:11:37 +04:00
|
|
|
kauth_cred_getegid(l->l_cred) != attr.va_gid))) {
|
2001-06-15 21:24:19 +04:00
|
|
|
/*
|
|
|
|
* Mark the process as SUGID before we do
|
|
|
|
* anything that might block.
|
|
|
|
*/
|
2007-02-10 00:55:00 +03:00
|
|
|
proc_crmod_enter();
|
2007-02-22 09:34:42 +03:00
|
|
|
proc_crmod_leave(NULL, NULL, true);
|
2001-06-15 21:24:19 +04:00
|
|
|
|
2002-04-23 19:11:25 +04:00
|
|
|
/* Make sure file descriptors 0..2 are in use. */
|
2008-03-22 00:54:58 +03:00
|
|
|
if ((error = fd_checkstd()) != 0) {
|
2005-08-19 06:04:02 +04:00
|
|
|
DPRINTF(("execve: fdcheckstd failed %d\n", error));
|
2002-04-23 19:11:25 +04:00
|
|
|
goto exec_abort;
|
2005-08-19 06:04:02 +04:00
|
|
|
}
|
2002-04-23 19:11:25 +04:00
|
|
|
|
2006-07-17 19:29:06 +04:00
|
|
|
/*
|
|
|
|
* Copy the credential so other references don't see our
|
|
|
|
* changes.
|
|
|
|
*/
|
2006-07-20 01:11:37 +04:00
|
|
|
l->l_cred = kauth_cred_copy(l->l_cred);
|
1994-06-29 10:29:24 +04:00
|
|
|
#ifdef KTRACE
|
|
|
|
/*
|
2008-02-02 23:42:18 +03:00
|
|
|
* If the persistent trace flag isn't set, turn off.
|
1994-06-29 10:29:24 +04:00
|
|
|
*/
|
2007-02-10 00:55:00 +03:00
|
|
|
if (p->p_tracep) {
|
2007-08-15 16:07:23 +04:00
|
|
|
mutex_enter(&ktrace_lock);
|
2008-02-02 23:42:18 +03:00
|
|
|
if (!(p->p_traceflag & KTRFAC_PERSISTENT))
|
2007-02-10 00:55:00 +03:00
|
|
|
ktrderef(p);
|
2007-08-15 16:07:23 +04:00
|
|
|
mutex_exit(&ktrace_lock);
|
2007-02-10 00:55:00 +03:00
|
|
|
}
|
1994-06-29 10:29:24 +04:00
|
|
|
#endif
|
1997-05-08 14:19:10 +04:00
|
|
|
if (attr.va_mode & S_ISUID)
|
2006-07-20 01:11:37 +04:00
|
|
|
kauth_cred_seteuid(l->l_cred, attr.va_uid);
|
1997-05-08 14:19:10 +04:00
|
|
|
if (attr.va_mode & S_ISGID)
|
2006-07-20 01:11:37 +04:00
|
|
|
kauth_cred_setegid(l->l_cred, attr.va_gid);
|
2005-10-31 07:31:58 +03:00
|
|
|
} else {
|
2006-07-20 01:11:37 +04:00
|
|
|
if (kauth_cred_geteuid(l->l_cred) ==
|
|
|
|
kauth_cred_getuid(l->l_cred) &&
|
|
|
|
kauth_cred_getegid(l->l_cred) ==
|
|
|
|
kauth_cred_getgid(l->l_cred))
|
2007-02-18 01:31:36 +03:00
|
|
|
p->p_flag &= ~PK_SUGID;
|
2005-10-31 07:31:58 +03:00
|
|
|
}
|
2006-07-17 19:29:06 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Copy the credential so other references don't see our changes.
|
|
|
|
* Test to see if this is necessary first, since in the common case
|
|
|
|
* we won't need a private reference.
|
|
|
|
*/
|
2006-07-20 01:11:37 +04:00
|
|
|
if (kauth_cred_geteuid(l->l_cred) != kauth_cred_getsvuid(l->l_cred) ||
|
|
|
|
kauth_cred_getegid(l->l_cred) != kauth_cred_getsvgid(l->l_cred)) {
|
|
|
|
l->l_cred = kauth_cred_copy(l->l_cred);
|
|
|
|
kauth_cred_setsvuid(l->l_cred, kauth_cred_geteuid(l->l_cred));
|
|
|
|
kauth_cred_setsvgid(l->l_cred, kauth_cred_getegid(l->l_cred));
|
2006-07-17 19:29:06 +04:00
|
|
|
}
|
1994-06-29 10:29:24 +04:00
|
|
|
|
2006-07-20 01:11:37 +04:00
|
|
|
/* Update the master credentials. */
|
2006-07-31 01:58:11 +04:00
|
|
|
if (l->l_cred != p->p_cred) {
|
|
|
|
kauth_cred_t ocred;
|
|
|
|
|
|
|
|
kauth_cred_hold(l->l_cred);
|
2007-02-10 00:55:00 +03:00
|
|
|
mutex_enter(&p->p_mutex);
|
2006-07-31 01:58:11 +04:00
|
|
|
ocred = p->p_cred;
|
|
|
|
p->p_cred = l->l_cred;
|
2007-02-10 00:55:00 +03:00
|
|
|
mutex_exit(&p->p_mutex);
|
2006-07-31 01:58:11 +04:00
|
|
|
kauth_cred_free(ocred);
|
|
|
|
}
|
2006-07-20 01:11:37 +04:00
|
|
|
|
2002-08-28 11:16:33 +04:00
|
|
|
#if defined(__HAVE_RAS)
|
|
|
|
/*
|
|
|
|
* Remove all RASs from the address space.
|
|
|
|
*/
|
2007-10-24 18:50:38 +04:00
|
|
|
ras_purgeall();
|
2002-08-28 11:16:33 +04:00
|
|
|
#endif
|
|
|
|
|
2000-01-25 04:15:14 +03:00
|
|
|
doexechooks(p);
|
|
|
|
|
2005-04-01 15:59:21 +04:00
|
|
|
uvm_km_free(exec_map, (vaddr_t) argp, NCARGS, UVM_KMF_PAGEABLE);
|
1994-06-29 10:29:24 +04:00
|
|
|
|
2000-08-04 00:41:05 +04:00
|
|
|
PNBUF_PUT(nid.ni_cnd.cn_pnbuf);
|
1994-06-29 10:29:24 +04:00
|
|
|
|
2002-10-23 13:10:23 +04:00
|
|
|
/* notify others that we exec'd */
|
|
|
|
KNOTE(&p->p_klist, NOTE_EXEC);
|
|
|
|
|
1994-06-29 10:29:24 +04:00
|
|
|
/* setup new registers and do misc. setup. */
|
2007-04-22 12:29:55 +04:00
|
|
|
(*pack.ep_esch->es_emul->e_setregs)(l, &pack, (u_long) stack);
|
|
|
|
if (pack.ep_esch->es_setregs)
|
|
|
|
(*pack.ep_esch->es_setregs)(l, &pack, (u_long) stack);
|
1994-06-29 10:29:24 +04:00
|
|
|
|
2003-08-24 21:52:28 +04:00
|
|
|
/* map the process's signal trampoline code */
|
2007-04-22 12:29:55 +04:00
|
|
|
if (exec_sigcode_map(p, pack.ep_esch->es_emul)) {
|
2005-08-19 06:04:02 +04:00
|
|
|
DPRINTF(("execve: map sigcode failed %d\n", error));
|
2003-08-24 21:52:28 +04:00
|
|
|
goto exec_abort;
|
2005-08-19 06:04:02 +04:00
|
|
|
}
|
2003-08-24 21:52:28 +04:00
|
|
|
|
2008-01-02 22:44:36 +03:00
|
|
|
kmem_free(pack.ep_hdr, pack.ep_hdrlen);
|
1995-07-19 19:19:08 +04:00
|
|
|
|
2007-04-22 12:29:55 +04:00
|
|
|
/* The emulation root will usually have been found when we looked
|
|
|
|
* for the elf interpreter (or similar), if not look now. */
|
|
|
|
if (pack.ep_esch->es_emul->e_path != NULL && pack.ep_emul_root == NULL)
|
|
|
|
emul_find_root(l, &pack);
|
|
|
|
|
|
|
|
/* Any old emulation root got removed by fdcloseexec */
|
2007-12-26 19:01:34 +03:00
|
|
|
rw_enter(&p->p_cwdi->cwdi_lock, RW_WRITER);
|
2007-04-22 12:29:55 +04:00
|
|
|
p->p_cwdi->cwdi_edir = pack.ep_emul_root;
|
2007-12-26 19:01:34 +03:00
|
|
|
rw_exit(&p->p_cwdi->cwdi_lock);
|
2007-04-22 12:29:55 +04:00
|
|
|
pack.ep_emul_root = NULL;
|
|
|
|
if (pack.ep_interp != NULL)
|
|
|
|
vrele(pack.ep_interp);
|
|
|
|
|
2000-11-07 15:41:52 +03:00
|
|
|
/*
|
2005-02-18 03:21:37 +03:00
|
|
|
* Call emulation specific exec hook. This can setup per-process
|
2000-11-07 15:41:52 +03:00
|
|
|
* p->p_emuldata or do any other per-process stuff an emulation needs.
|
|
|
|
*
|
|
|
|
* If we are executing process of different emulation than the
|
|
|
|
* original forked process, call e_proc_exit() of the old emulation
|
|
|
|
* first, then e_proc_exec() of new emulation. If the emulation is
|
|
|
|
* same, the exec hook code should deallocate any old emulation
|
|
|
|
* resources held previously by this process.
|
|
|
|
*/
|
2000-11-21 03:37:49 +03:00
|
|
|
if (p->p_emul && p->p_emul->e_proc_exit
|
2007-04-22 12:29:55 +04:00
|
|
|
&& p->p_emul != pack.ep_esch->es_emul)
|
2000-11-07 15:41:52 +03:00
|
|
|
(*p->p_emul->e_proc_exit)(p);
|
|
|
|
|
2000-11-16 23:04:33 +03:00
|
|
|
/*
|
|
|
|
* Call exec hook. Emulation code may NOT store reference to anything
|
|
|
|
* from &pack.
|
|
|
|
*/
|
2007-04-22 12:29:55 +04:00
|
|
|
if (pack.ep_esch->es_emul->e_proc_exec)
|
|
|
|
(*pack.ep_esch->es_emul->e_proc_exec)(p, &pack);
|
2000-11-07 15:41:52 +03:00
|
|
|
|
|
|
|
/* update p_emul, the old value is no longer needed */
|
2007-04-22 12:29:55 +04:00
|
|
|
p->p_emul = pack.ep_esch->es_emul;
|
2001-12-08 03:35:25 +03:00
|
|
|
|
|
|
|
/* ...and the same for p_execsw */
|
2007-04-22 12:29:55 +04:00
|
|
|
p->p_execsw = pack.ep_esch;
|
2001-12-08 03:35:25 +03:00
|
|
|
|
2000-12-11 08:28:59 +03:00
|
|
|
#ifdef __HAVE_SYSCALL_INTERN
|
|
|
|
(*p->p_emul->e_syscall_intern)(p);
|
|
|
|
#endif
|
2007-08-15 16:07:23 +04:00
|
|
|
ktremul();
|
1997-09-12 03:01:44 +04:00
|
|
|
|
2007-11-07 03:23:13 +03:00
|
|
|
/* Allow new references from the debugger/procfs. */
|
|
|
|
rw_exit(&p->p_reflock);
|
2001-11-24 01:02:39 +03:00
|
|
|
#ifdef LKM
|
2007-02-10 00:55:00 +03:00
|
|
|
rw_exit(&exec_lock);
|
2001-11-24 01:02:39 +03:00
|
|
|
#endif
|
2002-11-07 03:22:28 +03:00
|
|
|
|
2007-02-10 00:55:00 +03:00
|
|
|
mutex_enter(&proclist_mutex);
|
2002-11-07 03:22:28 +03:00
|
|
|
|
2007-02-10 00:55:00 +03:00
|
|
|
if ((p->p_slflag & (PSL_TRACED|PSL_SYSCALL)) == PSL_TRACED) {
|
|
|
|
KSI_INIT_EMPTY(&ksi);
|
|
|
|
ksi.ksi_signo = SIGTRAP;
|
|
|
|
ksi.ksi_lid = l->l_lid;
|
|
|
|
kpsignal(p, &ksi, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (p->p_sflag & PS_STOPEXEC) {
|
|
|
|
KERNEL_UNLOCK_ALL(l, &l->l_biglocks);
|
2003-11-13 00:07:37 +03:00
|
|
|
p->p_pptr->p_nstopchild++;
|
2007-02-10 00:55:00 +03:00
|
|
|
p->p_pptr->p_waited = 0;
|
|
|
|
mutex_enter(&p->p_smutex);
|
|
|
|
ksiginfo_queue_init(&kq);
|
|
|
|
sigclearall(p, &contsigmask, &kq);
|
|
|
|
lwp_lock(l);
|
2003-01-18 13:06:22 +03:00
|
|
|
l->l_stat = LSSTOP;
|
2007-02-10 00:55:00 +03:00
|
|
|
p->p_stat = SSTOP;
|
2003-01-18 13:06:22 +03:00
|
|
|
p->p_nrlwps--;
|
2007-02-10 00:55:00 +03:00
|
|
|
mutex_exit(&p->p_smutex);
|
|
|
|
mutex_exit(&proclist_mutex);
|
2007-05-17 18:51:11 +04:00
|
|
|
mi_switch(l);
|
2007-02-10 00:55:00 +03:00
|
|
|
ksiginfo_queue_drain(&kq);
|
|
|
|
KERNEL_LOCK(l->l_biglocks, l);
|
|
|
|
} else {
|
|
|
|
mutex_exit(&proclist_mutex);
|
2002-11-07 03:22:28 +03:00
|
|
|
}
|
|
|
|
|
2007-12-27 01:11:47 +03:00
|
|
|
PNBUF_PUT(pathbuf);
|
1997-09-12 03:01:44 +04:00
|
|
|
return (EJUSTRETURN);
|
1994-06-29 10:29:24 +04:00
|
|
|
|
2001-02-26 23:43:25 +03:00
|
|
|
bad:
|
1994-06-29 10:29:24 +04:00
|
|
|
/* free the vmspace-creation commands, and release their references */
|
|
|
|
kill_vmcmds(&pack.ep_vmcmds);
|
|
|
|
/* kill any opened file descriptor, if necessary */
|
|
|
|
if (pack.ep_flags & EXEC_HASFD) {
|
|
|
|
pack.ep_flags &= ~EXEC_HASFD;
|
2008-03-22 00:54:58 +03:00
|
|
|
fd_close(pack.ep_fd);
|
1994-06-29 10:29:24 +04:00
|
|
|
}
|
|
|
|
/* close and put the exec'd file */
|
1999-02-27 02:38:55 +03:00
|
|
|
vn_lock(pack.ep_vp, LK_EXCLUSIVE | LK_RETRY);
|
2007-11-26 22:01:26 +03:00
|
|
|
VOP_CLOSE(pack.ep_vp, FREAD, l->l_cred);
|
1999-02-27 02:38:55 +03:00
|
|
|
vput(pack.ep_vp);
|
2000-08-04 00:41:05 +04:00
|
|
|
PNBUF_PUT(nid.ni_cnd.cn_pnbuf);
|
2005-04-01 15:59:21 +04:00
|
|
|
uvm_km_free(exec_map, (vaddr_t) argp, NCARGS, UVM_KMF_PAGEABLE);
|
1994-06-29 10:29:24 +04:00
|
|
|
|
2001-02-26 23:43:25 +03:00
|
|
|
freehdr:
|
2008-01-02 22:44:36 +03:00
|
|
|
kmem_free(pack.ep_hdr, pack.ep_hdrlen);
|
2007-04-22 12:29:55 +04:00
|
|
|
if (pack.ep_emul_root != NULL)
|
|
|
|
vrele(pack.ep_emul_root);
|
|
|
|
if (pack.ep_interp != NULL)
|
|
|
|
vrele(pack.ep_interp);
|
2005-06-26 23:58:29 +04:00
|
|
|
|
|
|
|
clrflg:
|
2007-12-27 01:11:47 +03:00
|
|
|
PNBUF_PUT(pathbuf);
|
2007-11-07 03:23:13 +03:00
|
|
|
rw_exit(&p->p_reflock);
|
2001-11-24 01:02:39 +03:00
|
|
|
#ifdef LKM
|
2007-02-10 00:55:00 +03:00
|
|
|
rw_exit(&exec_lock);
|
2001-11-24 01:02:39 +03:00
|
|
|
#endif
|
2000-12-08 22:42:11 +03:00
|
|
|
|
1994-06-29 10:29:24 +04:00
|
|
|
return error;
|
|
|
|
|
2001-02-26 23:43:25 +03:00
|
|
|
exec_abort:
|
2007-12-27 01:11:47 +03:00
|
|
|
PNBUF_PUT(pathbuf);
|
2007-11-07 03:23:13 +03:00
|
|
|
rw_exit(&p->p_reflock);
|
2001-11-24 01:02:39 +03:00
|
|
|
#ifdef LKM
|
2007-02-10 00:55:00 +03:00
|
|
|
rw_exit(&exec_lock);
|
2001-11-24 01:02:39 +03:00
|
|
|
#endif
|
2000-12-08 22:42:11 +03:00
|
|
|
|
1994-06-29 10:29:24 +04:00
|
|
|
/*
|
|
|
|
* the old process doesn't exist anymore. exit gracefully.
|
|
|
|
* get rid of the (new) address space we have created, if any, get rid
|
|
|
|
* of our namei data and vnode, and exit noting failure
|
|
|
|
*/
|
1998-02-05 10:59:28 +03:00
|
|
|
uvm_deallocate(&vm->vm_map, VM_MIN_ADDRESS,
|
|
|
|
VM_MAXUSER_ADDRESS - VM_MIN_ADDRESS);
|
1995-12-09 07:11:00 +03:00
|
|
|
if (pack.ep_emul_arg)
|
2000-11-21 03:37:49 +03:00
|
|
|
FREE(pack.ep_emul_arg, M_TEMP);
|
2000-08-04 00:41:05 +04:00
|
|
|
PNBUF_PUT(nid.ni_cnd.cn_pnbuf);
|
2005-04-01 15:59:21 +04:00
|
|
|
uvm_km_free(exec_map, (vaddr_t) argp, NCARGS, UVM_KMF_PAGEABLE);
|
2008-01-02 22:44:36 +03:00
|
|
|
kmem_free(pack.ep_hdr, pack.ep_hdrlen);
|
2007-04-22 12:29:55 +04:00
|
|
|
if (pack.ep_emul_root != NULL)
|
|
|
|
vrele(pack.ep_emul_root);
|
|
|
|
if (pack.ep_interp != NULL)
|
|
|
|
vrele(pack.ep_interp);
|
2007-02-10 00:55:00 +03:00
|
|
|
|
2007-11-07 03:23:13 +03:00
|
|
|
/* Acquire the sched-state mutex (exit1() will release it). */
|
2008-01-02 14:48:20 +03:00
|
|
|
KERNEL_LOCK(1, NULL); /* XXXSMP */
|
2007-02-10 00:55:00 +03:00
|
|
|
mutex_enter(&p->p_smutex);
|
2003-01-18 13:06:22 +03:00
|
|
|
exit1(l, W_EXITCODE(error, SIGABRT));
|
1994-06-29 10:29:24 +04:00
|
|
|
|
|
|
|
/* NOTREACHED */
|
|
|
|
return 0;
|
|
|
|
}
|
1995-04-22 23:42:47 +04:00
|
|
|
|
|
|
|
|
2001-07-30 01:22:42 +04:00
|
|
|
int
|
2006-11-01 13:17:58 +03:00
|
|
|
copyargs(struct lwp *l, struct exec_package *pack, struct ps_strings *arginfo,
|
|
|
|
char **stackp, void *argp)
|
1995-04-22 23:42:47 +04:00
|
|
|
{
|
2001-02-26 23:43:25 +03:00
|
|
|
char **cpp, *dp, *sp;
|
|
|
|
size_t len;
|
|
|
|
void *nullp;
|
|
|
|
long argc, envc;
|
2001-07-30 01:22:42 +04:00
|
|
|
int error;
|
2001-02-26 23:43:25 +03:00
|
|
|
|
2001-07-30 01:22:42 +04:00
|
|
|
cpp = (char **)*stackp;
|
2001-02-26 23:43:25 +03:00
|
|
|
nullp = NULL;
|
|
|
|
argc = arginfo->ps_nargvstr;
|
|
|
|
envc = arginfo->ps_nenvstr;
|
2001-07-30 01:22:42 +04:00
|
|
|
if ((error = copyout(&argc, cpp++, sizeof(argc))) != 0)
|
|
|
|
return error;
|
1995-04-22 23:42:47 +04:00
|
|
|
|
2007-04-22 12:29:55 +04:00
|
|
|
dp = (char *) (cpp + argc + envc + 2 + pack->ep_esch->es_arglen);
|
1995-04-22 23:42:47 +04:00
|
|
|
sp = argp;
|
|
|
|
|
|
|
|
/* XXX don't copy them out, remap them! */
|
1995-05-16 18:19:03 +04:00
|
|
|
arginfo->ps_argvstr = cpp; /* remember location of argv for later */
|
1995-04-22 23:42:47 +04:00
|
|
|
|
|
|
|
for (; --argc >= 0; sp += len, dp += len)
|
2001-07-30 01:22:42 +04:00
|
|
|
if ((error = copyout(&dp, cpp++, sizeof(dp))) != 0 ||
|
|
|
|
(error = copyoutstr(sp, dp, ARG_MAX, &len)) != 0)
|
|
|
|
return error;
|
1995-04-22 23:42:47 +04:00
|
|
|
|
2001-07-30 01:22:42 +04:00
|
|
|
if ((error = copyout(&nullp, cpp++, sizeof(nullp))) != 0)
|
|
|
|
return error;
|
1995-04-22 23:42:47 +04:00
|
|
|
|
1995-05-16 18:19:03 +04:00
|
|
|
arginfo->ps_envstr = cpp; /* remember location of envp for later */
|
1995-04-22 23:42:47 +04:00
|
|
|
|
|
|
|
for (; --envc >= 0; sp += len, dp += len)
|
2001-07-30 01:22:42 +04:00
|
|
|
if ((error = copyout(&dp, cpp++, sizeof(dp))) != 0 ||
|
|
|
|
(error = copyoutstr(sp, dp, ARG_MAX, &len)) != 0)
|
|
|
|
return error;
|
1995-04-22 23:42:47 +04:00
|
|
|
|
2001-07-30 01:22:42 +04:00
|
|
|
if ((error = copyout(&nullp, cpp++, sizeof(nullp))) != 0)
|
|
|
|
return error;
|
1995-04-22 23:42:47 +04:00
|
|
|
|
2001-07-30 01:22:42 +04:00
|
|
|
*stackp = (char *)cpp;
|
|
|
|
return 0;
|
1995-04-22 23:42:47 +04:00
|
|
|
}
|
2000-12-08 22:42:11 +03:00
|
|
|
|
|
|
|
#ifdef LKM
|
|
|
|
/*
|
|
|
|
* Find an emulation of given name in list of emulations.
|
2002-04-03 00:18:06 +04:00
|
|
|
* Needs to be called with the exec_lock held.
|
2000-12-08 22:42:11 +03:00
|
|
|
*/
|
2002-04-03 00:18:06 +04:00
|
|
|
const struct emul *
|
2001-02-26 23:43:25 +03:00
|
|
|
emul_search(const char *name)
|
2000-12-08 22:42:11 +03:00
|
|
|
{
|
|
|
|
struct emul_entry *it;
|
|
|
|
|
|
|
|
LIST_FOREACH(it, &el_head, el_list) {
|
|
|
|
if (strcmp(name, it->el_emul->e_name) == 0)
|
|
|
|
return it->el_emul;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Add an emulation to list, if it's not there already.
|
|
|
|
*/
|
|
|
|
int
|
2001-02-26 23:43:25 +03:00
|
|
|
emul_register(const struct emul *emul, int ro_entry)
|
2000-12-08 22:42:11 +03:00
|
|
|
{
|
2001-02-26 23:43:25 +03:00
|
|
|
struct emul_entry *ee;
|
|
|
|
int error;
|
2000-12-08 22:42:11 +03:00
|
|
|
|
2001-02-26 23:43:25 +03:00
|
|
|
error = 0;
|
2007-02-10 00:55:00 +03:00
|
|
|
rw_enter(&exec_lock, RW_WRITER);
|
2000-12-08 22:42:11 +03:00
|
|
|
|
|
|
|
if (emul_search(emul->e_name)) {
|
|
|
|
error = EEXIST;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2008-01-03 17:36:57 +03:00
|
|
|
ee = kmem_alloc(sizeof(*ee), KM_SLEEP);
|
2000-12-08 22:42:11 +03:00
|
|
|
ee->el_emul = emul;
|
|
|
|
ee->ro_entry = ro_entry;
|
|
|
|
LIST_INSERT_HEAD(&el_head, ee, el_list);
|
|
|
|
|
2001-02-26 23:43:25 +03:00
|
|
|
out:
|
2007-02-10 00:55:00 +03:00
|
|
|
rw_exit(&exec_lock);
|
2000-12-08 22:42:11 +03:00
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Remove emulation with name 'name' from list of supported emulations.
|
|
|
|
*/
|
|
|
|
int
|
2001-02-26 23:43:25 +03:00
|
|
|
emul_unregister(const char *name)
|
2000-12-08 22:42:11 +03:00
|
|
|
{
|
|
|
|
const struct proclist_desc *pd;
|
2001-02-26 23:43:25 +03:00
|
|
|
struct emul_entry *it;
|
|
|
|
int i, error;
|
|
|
|
struct proc *ptmp;
|
2000-12-08 22:42:11 +03:00
|
|
|
|
2001-02-26 23:43:25 +03:00
|
|
|
error = 0;
|
2007-02-10 00:55:00 +03:00
|
|
|
rw_enter(&exec_lock, RW_WRITER);
|
2000-12-08 22:42:11 +03:00
|
|
|
|
|
|
|
LIST_FOREACH(it, &el_head, el_list) {
|
|
|
|
if (strcmp(it->el_emul->e_name, name) == 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!it) {
|
|
|
|
error = ENOENT;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (it->ro_entry) {
|
|
|
|
error = EBUSY;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* test if any execw[] entry is still using this */
|
2000-12-10 15:42:30 +03:00
|
|
|
for(i=0; i < nexecs; i++) {
|
2000-12-08 22:42:11 +03:00
|
|
|
if (execsw[i]->es_emul == it->el_emul) {
|
|
|
|
error = EBUSY;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Test if any process is running under this emulation - since
|
|
|
|
* emul_unregister() is running quite sendomly, it's better
|
|
|
|
* to do expensive check here than to use any locking.
|
|
|
|
*/
|
2007-03-09 17:11:22 +03:00
|
|
|
mutex_enter(&proclist_lock);
|
2000-12-08 22:42:11 +03:00
|
|
|
for (pd = proclists; pd->pd_list != NULL && !error; pd++) {
|
2004-10-01 20:30:52 +04:00
|
|
|
PROCLIST_FOREACH(ptmp, pd->pd_list) {
|
2000-12-08 22:42:11 +03:00
|
|
|
if (ptmp->p_emul == it->el_emul) {
|
|
|
|
error = EBUSY;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2007-03-09 17:11:22 +03:00
|
|
|
mutex_exit(&proclist_lock);
|
2004-03-05 14:30:50 +03:00
|
|
|
|
2000-12-08 22:42:11 +03:00
|
|
|
if (error)
|
|
|
|
goto out;
|
|
|
|
|
2004-03-05 14:30:50 +03:00
|
|
|
|
2000-12-08 22:42:11 +03:00
|
|
|
/* entry is not used, remove it */
|
|
|
|
LIST_REMOVE(it, el_list);
|
2008-01-03 17:36:57 +03:00
|
|
|
kmem_free(it, sizeof(*it));
|
2000-12-08 22:42:11 +03:00
|
|
|
|
2001-02-26 23:43:25 +03:00
|
|
|
out:
|
2007-02-10 00:55:00 +03:00
|
|
|
rw_exit(&exec_lock);
|
2000-12-08 22:42:11 +03:00
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Add execsw[] entry.
|
|
|
|
*/
|
|
|
|
int
|
2001-02-26 23:43:25 +03:00
|
|
|
exec_add(struct execsw *esp, const char *e_name)
|
2000-12-08 22:42:11 +03:00
|
|
|
{
|
2001-02-26 23:43:25 +03:00
|
|
|
struct exec_entry *it;
|
|
|
|
int error;
|
2000-12-08 22:42:11 +03:00
|
|
|
|
2001-02-26 23:43:25 +03:00
|
|
|
error = 0;
|
2007-02-10 00:55:00 +03:00
|
|
|
rw_enter(&exec_lock, RW_WRITER);
|
2000-12-08 22:42:11 +03:00
|
|
|
|
|
|
|
if (!esp->es_emul) {
|
|
|
|
esp->es_emul = emul_search(e_name);
|
|
|
|
if (!esp->es_emul) {
|
|
|
|
error = ENOENT;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
LIST_FOREACH(it, &ex_head, ex_list) {
|
|
|
|
/* assume tuple (makecmds, probe_func, emulation) is unique */
|
2004-02-06 11:02:58 +03:00
|
|
|
if (it->es->es_makecmds == esp->es_makecmds
|
2000-12-08 22:42:11 +03:00
|
|
|
&& it->es->u.elf_probe_func == esp->u.elf_probe_func
|
|
|
|
&& it->es->es_emul == esp->es_emul) {
|
|
|
|
error = EEXIST;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if we got here, the entry doesn't exist yet */
|
2008-01-03 17:36:57 +03:00
|
|
|
it = kmem_alloc(sizeof(*it), KM_SLEEP);
|
2000-12-08 22:42:11 +03:00
|
|
|
it->es = esp;
|
|
|
|
LIST_INSERT_HEAD(&ex_head, it, ex_list);
|
|
|
|
|
|
|
|
/* update execsw[] */
|
|
|
|
exec_init(0);
|
|
|
|
|
2001-02-26 23:43:25 +03:00
|
|
|
out:
|
2007-02-10 00:55:00 +03:00
|
|
|
rw_exit(&exec_lock);
|
2000-12-08 22:42:11 +03:00
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Remove execsw[] entry.
|
|
|
|
*/
|
|
|
|
int
|
2001-02-26 23:43:25 +03:00
|
|
|
exec_remove(const struct execsw *esp)
|
2000-12-08 22:42:11 +03:00
|
|
|
{
|
2001-02-26 23:43:25 +03:00
|
|
|
struct exec_entry *it;
|
|
|
|
int error;
|
2000-12-08 22:42:11 +03:00
|
|
|
|
2001-02-26 23:43:25 +03:00
|
|
|
error = 0;
|
2007-02-10 00:55:00 +03:00
|
|
|
rw_enter(&exec_lock, RW_WRITER);
|
2000-12-08 22:42:11 +03:00
|
|
|
|
|
|
|
LIST_FOREACH(it, &ex_head, ex_list) {
|
|
|
|
/* assume tuple (makecmds, probe_func, emulation) is unique */
|
2004-02-06 11:02:58 +03:00
|
|
|
if (it->es->es_makecmds == esp->es_makecmds
|
2000-12-08 22:42:11 +03:00
|
|
|
&& it->es->u.elf_probe_func == esp->u.elf_probe_func
|
|
|
|
&& it->es->es_emul == esp->es_emul)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!it) {
|
|
|
|
error = ENOENT;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* remove item from list and free resources */
|
|
|
|
LIST_REMOVE(it, ex_list);
|
2008-01-03 17:36:57 +03:00
|
|
|
kmem_free(it, sizeof(*it));
|
2000-12-08 22:42:11 +03:00
|
|
|
|
|
|
|
/* update execsw[] */
|
|
|
|
exec_init(0);
|
|
|
|
|
2001-02-26 23:43:25 +03:00
|
|
|
out:
|
2007-02-10 00:55:00 +03:00
|
|
|
rw_exit(&exec_lock);
|
2000-12-08 22:42:11 +03:00
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2001-02-26 23:43:25 +03:00
|
|
|
link_es(struct execsw_entry **listp, const struct execsw *esp)
|
2000-12-08 22:42:11 +03:00
|
|
|
{
|
|
|
|
struct execsw_entry *et, *e1;
|
|
|
|
|
2006-03-22 04:14:46 +03:00
|
|
|
et = (struct execsw_entry *) malloc(sizeof(struct execsw_entry),
|
2000-12-08 22:42:11 +03:00
|
|
|
M_TEMP, M_WAITOK);
|
|
|
|
et->next = NULL;
|
|
|
|
et->es = esp;
|
|
|
|
if (*listp == NULL) {
|
|
|
|
*listp = et;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch(et->es->es_prio) {
|
|
|
|
case EXECSW_PRIO_FIRST:
|
|
|
|
/* put new entry as the first */
|
|
|
|
et->next = *listp;
|
|
|
|
*listp = et;
|
|
|
|
break;
|
|
|
|
case EXECSW_PRIO_ANY:
|
|
|
|
/* put new entry after all *_FIRST and *_ANY entries */
|
|
|
|
for(e1 = *listp; e1->next
|
|
|
|
&& e1->next->es->es_prio != EXECSW_PRIO_LAST;
|
|
|
|
e1 = e1->next);
|
|
|
|
et->next = e1->next;
|
|
|
|
e1->next = et;
|
|
|
|
break;
|
|
|
|
case EXECSW_PRIO_LAST:
|
|
|
|
/* put new entry as the last one */
|
|
|
|
for(e1 = *listp; e1->next; e1 = e1->next);
|
|
|
|
e1->next = et;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
#ifdef DIAGNOSTIC
|
2002-09-27 19:35:29 +04:00
|
|
|
panic("execw[] entry with unknown priority %d found",
|
2000-12-08 22:42:11 +03:00
|
|
|
et->es->es_prio);
|
2006-04-15 03:54:21 +04:00
|
|
|
#else
|
|
|
|
free(et, M_TEMP);
|
2000-12-08 22:42:11 +03:00
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialize exec structures. If init_boot is true, also does necessary
|
|
|
|
* one-time initialization (it's called from main() that way).
|
2001-11-24 01:02:39 +03:00
|
|
|
* Once system is multiuser, this should be called with exec_lock held,
|
2000-12-08 22:42:11 +03:00
|
|
|
* i.e. via exec_{add|remove}().
|
|
|
|
*/
|
|
|
|
int
|
2001-02-26 23:43:25 +03:00
|
|
|
exec_init(int init_boot)
|
2000-12-08 22:42:11 +03:00
|
|
|
{
|
2001-02-26 23:43:25 +03:00
|
|
|
const struct execsw **new_es, * const *old_es;
|
|
|
|
struct execsw_entry *list, *e1;
|
|
|
|
struct exec_entry *e2;
|
|
|
|
int i, es_sz;
|
2000-12-08 22:42:11 +03:00
|
|
|
|
|
|
|
if (init_boot) {
|
|
|
|
/* do one-time initializations */
|
2007-02-10 00:55:00 +03:00
|
|
|
rw_init(&exec_lock);
|
2007-12-26 19:01:34 +03:00
|
|
|
mutex_init(&sigobject_lock, MUTEX_DEFAULT, IPL_NONE);
|
2000-12-08 22:42:11 +03:00
|
|
|
|
|
|
|
/* register compiled-in emulations */
|
|
|
|
for(i=0; i < nexecs_builtin; i++) {
|
|
|
|
if (execsw_builtin[i].es_emul)
|
|
|
|
emul_register(execsw_builtin[i].es_emul, 1);
|
|
|
|
}
|
|
|
|
#ifdef DIAGNOSTIC
|
|
|
|
if (i == 0)
|
2002-09-27 19:35:29 +04:00
|
|
|
panic("no emulations found in execsw_builtin[]");
|
2000-12-08 22:42:11 +03:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Build execsw[] array from builtin entries and entries added
|
|
|
|
* at runtime.
|
|
|
|
*/
|
|
|
|
list = NULL;
|
|
|
|
for(i=0; i < nexecs_builtin; i++)
|
|
|
|
link_es(&list, &execsw_builtin[i]);
|
|
|
|
|
|
|
|
/* Add dynamically loaded entries */
|
|
|
|
es_sz = nexecs_builtin;
|
|
|
|
LIST_FOREACH(e2, &ex_head, ex_list) {
|
|
|
|
link_es(&list, e2->es);
|
|
|
|
es_sz++;
|
|
|
|
}
|
2004-03-05 14:30:50 +03:00
|
|
|
|
2000-12-08 22:42:11 +03:00
|
|
|
/*
|
|
|
|
* Now that we have sorted all execw entries, create new execsw[]
|
|
|
|
* and free no longer needed memory in the process.
|
|
|
|
*/
|
2008-01-03 17:36:57 +03:00
|
|
|
new_es = kmem_alloc(es_sz * sizeof(struct execsw *), KM_SLEEP);
|
2000-12-08 22:42:11 +03:00
|
|
|
for(i=0; list; i++) {
|
|
|
|
new_es[i] = list->es;
|
|
|
|
e1 = list->next;
|
2006-03-22 04:14:46 +03:00
|
|
|
free(list, M_TEMP);
|
2000-12-08 22:42:11 +03:00
|
|
|
list = e1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* New execsw[] array built, now replace old execsw[] and free
|
|
|
|
* used memory.
|
|
|
|
*/
|
|
|
|
old_es = execsw;
|
|
|
|
if (old_es)
|
2005-05-30 02:24:14 +04:00
|
|
|
/*XXXUNCONST*/
|
2008-01-03 17:36:57 +03:00
|
|
|
kmem_free(__UNCONST(old_es), nexecs * sizeof(struct execsw *));
|
|
|
|
execsw = new_es;
|
|
|
|
nexecs = es_sz;
|
2000-12-08 22:42:11 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Figure out the maximum size of an exec header.
|
2004-03-05 14:30:50 +03:00
|
|
|
*/
|
2000-12-08 22:42:11 +03:00
|
|
|
exec_maxhdrsz = 0;
|
|
|
|
for (i = 0; i < nexecs; i++) {
|
|
|
|
if (execsw[i]->es_hdrsz > exec_maxhdrsz)
|
|
|
|
exec_maxhdrsz = execsw[i]->es_hdrsz;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef LKM
|
|
|
|
/*
|
|
|
|
* Simplified exec_init() for kernels without LKMs. Only initialize
|
|
|
|
* exec_maxhdrsz and execsw[].
|
|
|
|
*/
|
|
|
|
int
|
2001-02-26 23:43:25 +03:00
|
|
|
exec_init(int init_boot)
|
2000-12-08 22:42:11 +03:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
#ifdef DIAGNOSTIC
|
|
|
|
if (!init_boot)
|
|
|
|
panic("exec_init(): called with init_boot == 0");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* do one-time initializations */
|
|
|
|
nexecs = nexecs_builtin;
|
2008-01-03 17:36:57 +03:00
|
|
|
execsw = kmem_alloc(nexecs * sizeof(struct execsw *), KM_SLEEP);
|
2000-12-08 22:42:11 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Fill in execsw[] and figure out the maximum size of an exec header.
|
|
|
|
*/
|
|
|
|
exec_maxhdrsz = 0;
|
|
|
|
for(i=0; i < nexecs; i++) {
|
|
|
|
execsw[i] = &execsw_builtin[i];
|
|
|
|
if (execsw_builtin[i].es_hdrsz > exec_maxhdrsz)
|
|
|
|
exec_maxhdrsz = execsw_builtin[i].es_hdrsz;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
#endif /* !LKM */
|
2003-08-24 21:52:28 +04:00
|
|
|
|
|
|
|
static int
|
|
|
|
exec_sigcode_map(struct proc *p, const struct emul *e)
|
|
|
|
{
|
|
|
|
vaddr_t va;
|
|
|
|
vsize_t sz;
|
|
|
|
int error;
|
|
|
|
struct uvm_object *uobj;
|
|
|
|
|
2004-03-25 21:29:24 +03:00
|
|
|
sz = (vaddr_t)e->e_esigcode - (vaddr_t)e->e_sigcode;
|
|
|
|
|
|
|
|
if (e->e_sigobject == NULL || sz == 0) {
|
2003-08-24 21:52:28 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If we don't have a sigobject for this emulation, create one.
|
|
|
|
*
|
|
|
|
* sigobject is an anonymous memory object (just like SYSV shared
|
|
|
|
* memory) that we keep a permanent reference to and that we map
|
|
|
|
* in all processes that need this sigcode. The creation is simple,
|
|
|
|
* we create an object, add a permanent reference to it, map it in
|
|
|
|
* kernel space, copy out the sigcode to it and unmap it.
|
2004-09-10 10:09:15 +04:00
|
|
|
* We map it with PROT_READ|PROT_EXEC into the process just
|
|
|
|
* the way sys_mmap() would map it.
|
2003-08-24 21:52:28 +04:00
|
|
|
*/
|
|
|
|
|
|
|
|
uobj = *e->e_sigobject;
|
|
|
|
if (uobj == NULL) {
|
2007-12-26 19:01:34 +03:00
|
|
|
mutex_enter(&sigobject_lock);
|
|
|
|
if ((uobj = *e->e_sigobject) == NULL) {
|
|
|
|
uobj = uao_create(sz, 0);
|
|
|
|
(*uobj->pgops->pgo_reference)(uobj);
|
|
|
|
va = vm_map_min(kernel_map);
|
|
|
|
if ((error = uvm_map(kernel_map, &va, round_page(sz),
|
|
|
|
uobj, 0, 0,
|
|
|
|
UVM_MAPFLAG(UVM_PROT_RW, UVM_PROT_RW,
|
|
|
|
UVM_INH_SHARE, UVM_ADV_RANDOM, 0)))) {
|
|
|
|
printf("kernel mapping failed %d\n", error);
|
|
|
|
(*uobj->pgops->pgo_detach)(uobj);
|
|
|
|
mutex_exit(&sigobject_lock);
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
memcpy((void *)va, e->e_sigcode, sz);
|
2003-08-24 21:52:28 +04:00
|
|
|
#ifdef PMAP_NEED_PROCWR
|
2007-12-26 19:01:34 +03:00
|
|
|
pmap_procwr(&proc0, va, sz);
|
2003-08-24 21:52:28 +04:00
|
|
|
#endif
|
2007-12-26 19:01:34 +03:00
|
|
|
uvm_unmap(kernel_map, va, va + round_page(sz));
|
|
|
|
*e->e_sigobject = uobj;
|
|
|
|
}
|
|
|
|
mutex_exit(&sigobject_lock);
|
2003-08-24 21:52:28 +04:00
|
|
|
}
|
|
|
|
|
2003-08-29 17:29:32 +04:00
|
|
|
/* Just a hint to uvm_map where to put it. */
|
2005-03-26 08:12:34 +03:00
|
|
|
va = e->e_vm_default_addr(p, (vaddr_t)p->p_vmspace->vm_daddr,
|
|
|
|
round_page(sz));
|
2004-06-27 04:55:08 +04:00
|
|
|
|
|
|
|
#ifdef __alpha__
|
|
|
|
/*
|
|
|
|
* Tru64 puts /sbin/loader at the end of user virtual memory,
|
|
|
|
* which causes the above calculation to put the sigcode at
|
|
|
|
* an invalid address. Put it just below the text instead.
|
|
|
|
*/
|
2005-02-12 12:38:25 +03:00
|
|
|
if (va == (vaddr_t)vm_map_max(&p->p_vmspace->vm_map)) {
|
2004-06-27 04:55:08 +04:00
|
|
|
va = (vaddr_t)p->p_vmspace->vm_taddr - round_page(sz);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2003-08-24 21:52:28 +04:00
|
|
|
(*uobj->pgops->pgo_reference)(uobj);
|
|
|
|
error = uvm_map(&p->p_vmspace->vm_map, &va, round_page(sz),
|
|
|
|
uobj, 0, 0,
|
|
|
|
UVM_MAPFLAG(UVM_PROT_RX, UVM_PROT_RX, UVM_INH_SHARE,
|
|
|
|
UVM_ADV_RANDOM, 0));
|
|
|
|
if (error) {
|
|
|
|
(*uobj->pgops->pgo_detach)(uobj);
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
p->p_sigctx.ps_sigcode = (void *)va;
|
|
|
|
return (0);
|
|
|
|
}
|