2005-10-31 07:39:41 +03:00
|
|
|
/* $NetBSD: kern_exec.c,v 1.211 2005/10/31 04:39:41 christos 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>
|
2005-10-31 07:39:41 +03:00
|
|
|
__KERNEL_RCSID(0, "$NetBSD: kern_exec.c,v 1.211 2005/10/31 04:39:41 christos 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"
|
2005-07-17 02:47:18 +04:00
|
|
|
#include "opt_verified_exec.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>
|
|
|
|
#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>
|
1994-06-29 10:29:24 +04:00
|
|
|
|
2003-01-18 13:06:22 +03:00
|
|
|
#include <sys/sa.h>
|
|
|
|
#include <sys/savar.h>
|
1994-10-20 07:22:35 +03:00
|
|
|
#include <sys/syscallargs.h>
|
2005-04-20 17:44:45 +04:00
|
|
|
#ifdef VERIFIED_EXEC
|
|
|
|
#include <sys/verified_exec.h>
|
|
|
|
#endif
|
1994-10-20 07:22:35 +03:00
|
|
|
|
2005-06-26 23:58:29 +04:00
|
|
|
#ifdef SYSTRACE
|
|
|
|
#include <sys/systrace.h>
|
|
|
|
#endif /* SYSTRACE */
|
|
|
|
|
1998-02-05 10:59:28 +03:00
|
|
|
#include <uvm/uvm_extern.h>
|
|
|
|
|
1994-06-29 10:29:24 +04:00
|
|
|
#include <machine/cpu.h>
|
|
|
|
#include <machine/reg.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 */
|
|
|
|
|
2003-02-01 09:23:35 +03:00
|
|
|
MALLOC_DEFINE(M_EXEC, "exec", "argument lists & other mem used by 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,
|
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.
|
|
|
|
*/
|
|
|
|
struct lock 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 */
|
|
|
|
|
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-10-31 07:39:41 +03:00
|
|
|
* proc pointer of exec'ing proc
|
2005-06-26 23:58:29 +04:00
|
|
|
* if verified exec enabled then flag indicating a direct exec or
|
2002-10-29 15:31:20 +03:00
|
|
|
* an indirect exec (i.e. for a shell script interpreter)
|
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*/
|
2005-10-31 07:39:41 +03:00
|
|
|
check_exec(struct proc *p, struct exec_package *epp, int flag)
|
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;
|
|
|
|
ndp->ni_cnd.cn_flags = FOLLOW | LOCKLEAF | SAVENAME;
|
|
|
|
/* 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;
|
|
|
|
}
|
2005-10-31 07:39:41 +03:00
|
|
|
if ((error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p)) != 0)
|
1997-05-08 20:19:43 +04:00
|
|
|
goto bad1;
|
1994-06-29 10:29:24 +04:00
|
|
|
|
|
|
|
/* get attributes */
|
2005-10-31 07:39:41 +03:00
|
|
|
if ((error = VOP_GETATTR(vp, epp->ep_vap, p->p_ucred, p)) != 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 */
|
2005-10-31 07:39:41 +03:00
|
|
|
if ((error = VOP_OPEN(vp, FREAD, p->p_ucred, p)) != 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
|
|
|
|
2004-03-05 14:30:50 +03:00
|
|
|
|
2002-10-29 15:31:20 +03:00
|
|
|
#ifdef VERIFIED_EXEC
|
2005-10-31 07:39:41 +03:00
|
|
|
if ((error = veriexec_verify(p, vp, epp->ep_vap, epp->ep_ndp->ni_dirp,
|
2005-06-26 23:58:29 +04:00
|
|
|
flag, NULL)) != 0)
|
2002-10-29 15:31:20 +03:00
|
|
|
goto bad2;
|
|
|
|
#endif
|
|
|
|
|
1994-06-29 10:29:24 +04:00
|
|
|
/* now we have the file, get the exec header */
|
2000-11-27 11:39:39 +03:00
|
|
|
uvn_attach(vp, VM_PROT_READ);
|
1996-02-04 05:15:01 +03:00
|
|
|
error = vn_rdwr(UIO_READ, vp, epp->ep_hdr, epp->ep_hdrlen, 0,
|
2004-09-17 18:11:20 +04:00
|
|
|
UIO_SYSSPACE, 0, p->p_ucred, &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
|
|
|
*
|
2003-04-11 00:57:01 +04:00
|
|
|
* XXX probably should be all done in the exec pakages.
|
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;
|
|
|
|
for (i = 0; i < nexecs && error != 0; 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-10-31 07:39:41 +03:00
|
|
|
newerror = (*execsw[i]->es_makecmds)(p, epp);
|
1995-05-02 02:36:45 +04:00
|
|
|
/* make sure the first "interesting" error code is saved. */
|
|
|
|
if (!newerror || error == ENOEXEC)
|
|
|
|
error = newerror;
|
2000-11-21 03:37:49 +03:00
|
|
|
|
2004-02-06 11:02:58 +03:00
|
|
|
/* if es_makecmds call was successful, update epp->ep_es */
|
2000-11-21 03:37:49 +03:00
|
|
|
if (!newerror && (epp->ep_flags & EXEC_HASES) == 0)
|
2000-12-08 22:42:11 +03:00
|
|
|
epp->ep_es = execsw[i];
|
2000-11-21 03:37:49 +03:00
|
|
|
|
1994-06-29 10:29:24 +04:00
|
|
|
if (epp->ep_flags & EXEC_DESTR && error != 0)
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
if (!error) {
|
|
|
|
/* check that entry point is sane */
|
|
|
|
if (epp->ep_entry > VM_MAXUSER_ADDRESS)
|
|
|
|
error = ENOEXEC;
|
|
|
|
|
|
|
|
/* check limits */
|
|
|
|
if ((epp->ep_tsize > MAXTSIZ) ||
|
2002-08-26 01:18:15 +04:00
|
|
|
(epp->ep_dsize >
|
|
|
|
(u_quad_t)p->p_rlimit[RLIMIT_DATA].rlim_cur))
|
1994-06-29 10:29:24 +04:00
|
|
|
error = ENOMEM;
|
|
|
|
|
|
|
|
if (!error)
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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);
|
2005-10-31 07:39:41 +03:00
|
|
|
VOP_CLOSE(vp, FREAD, p->p_ucred, p);
|
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
|
2003-01-18 13:06:22 +03:00
|
|
|
sys_execve(struct lwp *l, void *v, register_t *retval)
|
1995-09-20 01:40:36 +04:00
|
|
|
{
|
2000-03-30 13:27:11 +04:00
|
|
|
struct sys_execve_args /* {
|
2001-02-26 23:43:25 +03:00
|
|
|
syscallarg(const char *) path;
|
|
|
|
syscallarg(char * const *) argp;
|
|
|
|
syscallarg(char * const *) envp;
|
1995-09-20 01:40:36 +04:00
|
|
|
} */ *uap = v;
|
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;
|
|
|
|
u_int i;
|
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
|
|
|
struct ucred *cred;
|
|
|
|
char *argp;
|
|
|
|
char *dp, *sp;
|
|
|
|
long argc, envc;
|
|
|
|
size_t len;
|
|
|
|
char *stack;
|
|
|
|
struct ps_strings arginfo;
|
|
|
|
struct vmspace *vm;
|
|
|
|
char **tmpfap;
|
|
|
|
int szsigcode;
|
|
|
|
struct exec_vmcmd *base_vcp;
|
2003-01-18 13:06:22 +03:00
|
|
|
int oldlwpflags;
|
2005-06-26 23:58:29 +04:00
|
|
|
#ifdef SYSTRACE
|
|
|
|
int wassugid = ISSET(p->p_flag, P_SUGID);
|
|
|
|
char pathbuf[MAXPATHLEN];
|
|
|
|
size_t pathbuflen;
|
|
|
|
#endif /* SYSTRACE */
|
2001-02-26 23:43:25 +03:00
|
|
|
|
2003-01-18 13:06:22 +03:00
|
|
|
/* Disable scheduler activation upcalls. */
|
|
|
|
oldlwpflags = l->l_flag & (L_SA | L_SA_UPCALL);
|
|
|
|
if (l->l_flag & L_SA)
|
|
|
|
l->l_flag &= ~(L_SA | L_SA_UPCALL);
|
|
|
|
|
|
|
|
p = l->l_proc;
|
2002-01-12 00:16:27 +03:00
|
|
|
/*
|
|
|
|
* Lock the process and set the P_INEXEC flag to indicate that
|
|
|
|
* it 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.
|
|
|
|
*/
|
|
|
|
p->p_flag |= P_INEXEC;
|
|
|
|
|
2001-02-26 23:43:25 +03:00
|
|
|
cred = p->p_ucred;
|
|
|
|
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().
|
|
|
|
*/
|
2005-06-26 23:58:29 +04:00
|
|
|
#ifdef SYSTRACE
|
2005-06-27 21:11:20 +04:00
|
|
|
if (ISSET(p->p_flag, P_SYSTRACE))
|
|
|
|
systrace_execve0(p);
|
|
|
|
|
2005-07-12 00:15:26 +04:00
|
|
|
error = copyinstr(path, pathbuf, sizeof(pathbuf),
|
2005-06-26 23:58:29 +04:00
|
|
|
&pathbuflen);
|
|
|
|
if (error)
|
|
|
|
goto clrflg;
|
|
|
|
|
2005-10-31 07:39:41 +03:00
|
|
|
NDINIT(&nid, LOOKUP, NOFOLLOW, UIO_SYSSPACE, pathbuf, p);
|
2005-06-26 23:58:29 +04:00
|
|
|
#else
|
2005-10-31 07:39:41 +03:00
|
|
|
NDINIT(&nid, LOOKUP, NOFOLLOW, UIO_USERSPACE, path, p);
|
2005-06-26 23:58:29 +04:00
|
|
|
#endif /* SYSTRACE */
|
1994-06-29 10:29:24 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* initialize the fields of the exec package.
|
|
|
|
*/
|
2005-06-26 23:58:29 +04:00
|
|
|
#ifdef SYSTRACE
|
|
|
|
pack.ep_name = pathbuf;
|
|
|
|
#else
|
2005-07-12 00:15:26 +04:00
|
|
|
pack.ep_name = path;
|
2005-06-26 23:58:29 +04:00
|
|
|
#endif /* SYSTRACE */
|
2000-08-03 00:36:33 +04:00
|
|
|
pack.ep_hdr = malloc(exec_maxhdrsz, M_EXEC, M_WAITOK);
|
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;
|
|
|
|
|
2001-11-24 01:02:39 +03:00
|
|
|
#ifdef LKM
|
2000-12-08 22:42:11 +03:00
|
|
|
lockmgr(&exec_lock, LK_SHARED, NULL);
|
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. */
|
2002-10-29 15:31:20 +03:00
|
|
|
#ifdef VERIFIED_EXEC
|
2005-10-31 07:39:41 +03:00
|
|
|
if ((error = check_exec(p, &pack, VERIEXEC_DIRECT)) != 0)
|
2004-03-05 14:30:50 +03:00
|
|
|
#else
|
2005-10-31 07:39:41 +03:00
|
|
|
if ((error = check_exec(p, &pack, 0)) != 0)
|
2002-10-29 15:31:20 +03:00
|
|
|
#endif
|
1994-06-29 10:29:24 +04:00
|
|
|
goto freehdr;
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
while (*tmpfap != NULL) {
|
|
|
|
char *cp;
|
|
|
|
|
|
|
|
cp = *tmpfap;
|
|
|
|
while (*cp)
|
|
|
|
*dp++ = *cp++;
|
1996-02-04 05:15:01 +03:00
|
|
|
dp++;
|
1994-06-29 10:29:24 +04:00
|
|
|
|
|
|
|
FREE(*tmpfap, M_EXEC);
|
|
|
|
tmpfap++; argc++;
|
|
|
|
}
|
|
|
|
FREE(pack.ep_fa, M_EXEC);
|
|
|
|
pack.ep_flags &= ~EXEC_HASARGL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now get argv & environment */
|
2005-07-12 00:15:26 +04:00
|
|
|
if (args == NULL) {
|
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;
|
2005-07-12 00:15:26 +04:00
|
|
|
if ((error = (*fetch_element)(args, i, &sp)) != 0)
|
1994-06-29 10:29:24 +04:00
|
|
|
goto bad;
|
|
|
|
if (!sp)
|
|
|
|
break;
|
1996-02-04 05:15:01 +03:00
|
|
|
if ((error = copyinstr(sp, dp, len, &len)) != 0) {
|
1994-06-29 10:29:24 +04:00
|
|
|
if (error == ENAMETOOLONG)
|
|
|
|
error = E2BIG;
|
|
|
|
goto bad;
|
|
|
|
}
|
2003-07-17 02:42:47 +04:00
|
|
|
#ifdef KTRACE
|
|
|
|
if (KTRPOINT(p, KTR_EXEC_ARG))
|
2005-10-31 07:39:41 +03:00
|
|
|
ktrkmem(p, KTR_EXEC_ARG, dp, len - 1);
|
2003-07-17 02:42:47 +04:00
|
|
|
#endif
|
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;
|
2005-07-12 00:15:26 +04:00
|
|
|
if ((error = (*fetch_element)(envs, i, &sp)) != 0)
|
1994-06-29 10:29:24 +04:00
|
|
|
goto bad;
|
|
|
|
if (!sp)
|
|
|
|
break;
|
1996-02-04 05:15:01 +03:00
|
|
|
if ((error = copyinstr(sp, dp, len, &len)) != 0) {
|
1994-06-29 10:29:24 +04:00
|
|
|
if (error == ENAMETOOLONG)
|
|
|
|
error = E2BIG;
|
|
|
|
goto bad;
|
|
|
|
}
|
2003-07-17 02:42:47 +04:00
|
|
|
#ifdef KTRACE
|
|
|
|
if (KTRPOINT(p, KTR_EXEC_ENV))
|
2005-10-31 07:39:41 +03:00
|
|
|
ktrkmem(p, KTR_EXEC_ENV, dp, len - 1);
|
2003-07-17 02:42:47 +04:00
|
|
|
#endif
|
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);
|
|
|
|
|
2000-11-28 15:24:34 +03:00
|
|
|
szsigcode = pack.ep_es->es_emul->e_esigcode -
|
|
|
|
pack.ep_es->es_emul->e_sigcode;
|
1995-04-08 02:33:23 +04:00
|
|
|
|
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)
|
2000-11-28 15:24:34 +03:00
|
|
|
len = ((argc + envc + 2 + pack.ep_es->es_arglen) *
|
|
|
|
sizeof(int) + sizeof(int) + dp + STACKGAPLEN +
|
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
|
2000-11-28 15:24:34 +03:00
|
|
|
len = ((argc + envc + 2 + pack.ep_es->es_arglen) *
|
|
|
|
sizeof(char *) + sizeof(int) + dp + STACKGAPLEN +
|
2004-07-19 01:29:26 +04:00
|
|
|
szsigcode + sizeof(struct ps_strings) + STACK_PTHREADSPACE)
|
|
|
|
- argp;
|
1995-04-22 23:42:47 +04:00
|
|
|
|
1994-06-29 10:29:24 +04:00
|
|
|
len = ALIGN(len); /* make the stack "safely" aligned */
|
|
|
|
|
|
|
|
if (len > pack.ep_ssize) { /* in effect, compare to initial limit */
|
|
|
|
error = ENOMEM;
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
|
2003-01-18 13:06:22 +03:00
|
|
|
/* Get rid of other LWPs/ */
|
|
|
|
p->p_flag |= P_WEXIT; /* XXX hack. lwp-exit stuff wants to see it. */
|
|
|
|
exit_lwps(l);
|
|
|
|
p->p_flag &= ~P_WEXIT;
|
|
|
|
KDASSERT(p->p_nlwps == 1);
|
|
|
|
|
|
|
|
/* This is now LWP 1 */
|
|
|
|
l->l_lid = 1;
|
|
|
|
p->p_nlwpid = 1;
|
|
|
|
|
|
|
|
/* Release any SA state. */
|
2003-11-18 01:52:09 +03:00
|
|
|
if (p->p_sa)
|
|
|
|
sa_release(p);
|
2003-01-18 13:06:22 +03:00
|
|
|
|
|
|
|
/* 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;
|
2002-10-08 19:50:11 +04:00
|
|
|
vm->vm_taddr = (caddr_t) pack.ep_taddr;
|
1994-06-29 10:29:24 +04:00
|
|
|
vm->vm_tsize = btoc(pack.ep_tsize);
|
2002-10-08 19:50:11 +04:00
|
|
|
vm->vm_daddr = (caddr_t) 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);
|
2002-10-08 19:50:11 +04:00
|
|
|
vm->vm_maxsaddr = (caddr_t) pack.ep_maxsaddr;
|
|
|
|
vm->vm_minsaddr = (caddr_t) pack.ep_minsaddr;
|
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-10-31 07:39:41 +03:00
|
|
|
error = (*vcp->ev_proc)(p, vcp);
|
2001-07-16 00:49:40 +04:00
|
|
|
#ifdef DEBUG_EXEC
|
2000-06-21 09:43:33 +04:00
|
|
|
if (error) {
|
2001-07-16 00:49:40 +04:00
|
|
|
int j;
|
|
|
|
struct exec_vmcmd *vp = &pack.ep_vmcmds.evs_cmds[0];
|
|
|
|
for (j = 0; j <= i; j++)
|
|
|
|
uprintf(
|
|
|
|
"vmcmd[%d] = %#lx/%#lx fd@%#lx prot=0%o flags=%d\n",
|
|
|
|
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);
|
2005-10-31 07:39:41 +03:00
|
|
|
VOP_CLOSE(pack.ep_vp, FREAD, cred, p);
|
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) {
|
2001-07-16 00:49:40 +04:00
|
|
|
DPRINTF(("execve: vmcmd %i 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;
|
|
|
|
|
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));
|
|
|
|
#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
|
|
|
|
* stack, right at the first user stack pointer, and puts
|
2002-11-18 01:53:46 +03:00
|
|
|
* STACKGAPLEN very deep in the stack. When the stack
|
|
|
|
* grows up, the situation is reversed.
|
|
|
|
*
|
|
|
|
* 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
|
|
|
|
* out and steal 32 bytes before we call copyargs. This
|
2002-11-18 01:53:46 +03:00
|
|
|
* space is effectively stolen from STACKGAPLEN.
|
|
|
|
*/
|
|
|
|
stack += 32;
|
|
|
|
#endif /* __MACHINE_STACK_GROWS_UP */
|
|
|
|
|
1995-04-22 23:42:47 +04:00
|
|
|
/* Now copy argc, args & environ to new stack */
|
2005-10-31 07:39:41 +03:00
|
|
|
error = (*pack.ep_es->es_copyargs)(p, &pack, &arginfo, &stack, argp);
|
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 */
|
2001-07-30 01:22:42 +04:00
|
|
|
if ((error = copyout(&arginfo, (char *)p->p_psstr,
|
|
|
|
sizeof(arginfo))) != 0) {
|
2001-07-16 00:49:40 +04:00
|
|
|
DPRINTF(("execve: ps_strings copyout %p->%p size %ld failed\n",
|
|
|
|
&arginfo, (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
|
|
|
|
1999-08-09 06:42:20 +04:00
|
|
|
stopprofclock(p); /* stop profiling */
|
2005-10-31 07:39:41 +03:00
|
|
|
fdcloseexec(p); /* 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
|
|
|
|
|
|
|
/* set command name & other accounting info */
|
|
|
|
len = min(nid.ni_cnd.cn_namelen, MAXCOMLEN);
|
Abolition of bcopy, ovbcopy, bcmp, and bzero, phase one.
bcopy(x, y, z) -> memcpy(y, x, z)
ovbcopy(x, y, z) -> memmove(y, x, z)
bcmp(x, y, z) -> memcmp(x, y, z)
bzero(x, y) -> memset(x, 0, y)
1998-08-04 08:03:10 +04:00
|
|
|
memcpy(p->p_comm, nid.ni_cnd.cn_nameptr, len);
|
1994-06-29 10:29:24 +04:00
|
|
|
p->p_comm[len] = 0;
|
|
|
|
p->p_acflag &= ~AFORK;
|
|
|
|
|
|
|
|
p->p_flag |= P_EXEC;
|
|
|
|
if (p->p_flag & P_PPWAIT) {
|
|
|
|
p->p_flag &= ~P_PPWAIT;
|
|
|
|
wakeup((caddr_t) p->p_pptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* deal with set[ug]id.
|
2001-06-15 21:24:19 +04:00
|
|
|
* MNT_NOSUID has already been used to disable s[ug]id.
|
1994-06-29 10:29:24 +04:00
|
|
|
*/
|
2001-06-15 21:24:19 +04:00
|
|
|
if ((p->p_flag & P_TRACED) == 0 &&
|
|
|
|
|
|
|
|
(((attr.va_mode & S_ISUID) != 0 &&
|
|
|
|
p->p_ucred->cr_uid != attr.va_uid) ||
|
|
|
|
|
|
|
|
((attr.va_mode & S_ISGID) != 0 &&
|
|
|
|
p->p_ucred->cr_gid != attr.va_gid))) {
|
|
|
|
/*
|
|
|
|
* Mark the process as SUGID before we do
|
|
|
|
* anything that might block.
|
|
|
|
*/
|
|
|
|
p_sugid(p);
|
|
|
|
|
2002-04-23 19:11:25 +04:00
|
|
|
/* Make sure file descriptors 0..2 are in use. */
|
2005-10-31 07:39:41 +03:00
|
|
|
if ((error = fdcheckstd(p)) != 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
|
|
|
|
1994-06-29 10:29:24 +04:00
|
|
|
p->p_ucred = crcopy(cred);
|
|
|
|
#ifdef KTRACE
|
|
|
|
/*
|
|
|
|
* If process is being ktraced, turn off - unless
|
|
|
|
* root set it.
|
|
|
|
*/
|
1998-05-02 22:33:19 +04:00
|
|
|
if (p->p_tracep && !(p->p_traceflag & KTRFAC_ROOT))
|
|
|
|
ktrderef(p);
|
1994-06-29 10:29:24 +04:00
|
|
|
#endif
|
1997-05-08 14:19:10 +04:00
|
|
|
if (attr.va_mode & S_ISUID)
|
1994-06-29 10:29:24 +04:00
|
|
|
p->p_ucred->cr_uid = attr.va_uid;
|
1997-05-08 14:19:10 +04:00
|
|
|
if (attr.va_mode & S_ISGID)
|
1994-06-29 10:29:24 +04:00
|
|
|
p->p_ucred->cr_gid = attr.va_gid;
|
2005-10-31 07:31:58 +03:00
|
|
|
} else {
|
|
|
|
if (p->p_ucred->cr_uid == p->p_cred->p_ruid &&
|
|
|
|
p->p_ucred->cr_gid == p->p_cred->p_rgid)
|
|
|
|
p->p_flag &= ~P_SUGID;
|
|
|
|
}
|
1994-06-29 10:29:24 +04:00
|
|
|
p->p_cred->p_svuid = p->p_ucred->cr_uid;
|
|
|
|
p->p_cred->p_svgid = p->p_ucred->cr_gid;
|
|
|
|
|
2002-08-28 11:16:33 +04:00
|
|
|
#if defined(__HAVE_RAS)
|
|
|
|
/*
|
|
|
|
* Remove all RASs from the address space.
|
|
|
|
*/
|
|
|
|
ras_purgeall(p);
|
|
|
|
#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. */
|
2003-01-18 13:06:22 +03:00
|
|
|
(*pack.ep_es->es_emul->e_setregs)(l, &pack, (u_long) stack);
|
2001-09-18 23:36:32 +04:00
|
|
|
if (pack.ep_es->es_setregs)
|
2003-01-18 13:06:22 +03:00
|
|
|
(*pack.ep_es->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 */
|
2005-08-19 06:04:02 +04:00
|
|
|
if (exec_sigcode_map(p, pack.ep_es->es_emul)) {
|
|
|
|
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
|
|
|
|
1994-06-29 10:29:24 +04:00
|
|
|
if (p->p_flag & P_TRACED)
|
|
|
|
psignal(p, SIGTRAP);
|
|
|
|
|
2000-08-03 00:36:33 +04:00
|
|
|
free(pack.ep_hdr, M_EXEC);
|
1995-07-19 19:19:08 +04:00
|
|
|
|
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
|
|
|
|
&& p->p_emul != pack.ep_es->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.
|
|
|
|
*/
|
2000-11-21 03:37:49 +03:00
|
|
|
if (pack.ep_es->es_emul->e_proc_exec)
|
|
|
|
(*pack.ep_es->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 */
|
2000-11-21 03:37:49 +03:00
|
|
|
p->p_emul = pack.ep_es->es_emul;
|
2001-12-08 03:35:25 +03:00
|
|
|
|
|
|
|
/* ...and the same for p_execsw */
|
|
|
|
p->p_execsw = pack.ep_es;
|
|
|
|
|
2000-12-11 08:28:59 +03:00
|
|
|
#ifdef __HAVE_SYSCALL_INTERN
|
|
|
|
(*p->p_emul->e_syscall_intern)(p);
|
|
|
|
#endif
|
1995-07-19 19:19:08 +04:00
|
|
|
#ifdef KTRACE
|
|
|
|
if (KTRPOINT(p, KTR_EMUL))
|
2005-10-31 07:39:41 +03:00
|
|
|
ktremul(p);
|
1995-07-19 19:19:08 +04:00
|
|
|
#endif
|
1997-09-12 03:01:44 +04:00
|
|
|
|
2001-11-24 01:02:39 +03:00
|
|
|
#ifdef LKM
|
2000-12-08 22:42:11 +03:00
|
|
|
lockmgr(&exec_lock, LK_RELEASE, NULL);
|
2001-11-24 01:02:39 +03:00
|
|
|
#endif
|
2002-01-12 00:16:27 +03:00
|
|
|
p->p_flag &= ~P_INEXEC;
|
2002-11-07 03:22:28 +03:00
|
|
|
|
|
|
|
if (p->p_flag & P_STOPEXEC) {
|
|
|
|
int s;
|
|
|
|
|
|
|
|
sigminusset(&contsigmask, &p->p_sigctx.ps_siglist);
|
|
|
|
SCHED_LOCK(s);
|
2003-11-13 00:07:37 +03:00
|
|
|
p->p_pptr->p_nstopchild++;
|
2002-11-07 03:22:28 +03:00
|
|
|
p->p_stat = SSTOP;
|
2003-01-18 13:06:22 +03:00
|
|
|
l->l_stat = LSSTOP;
|
|
|
|
p->p_nrlwps--;
|
|
|
|
mi_switch(l, NULL);
|
2002-11-07 03:22:28 +03:00
|
|
|
SCHED_ASSERT_UNLOCKED();
|
|
|
|
splx(s);
|
|
|
|
}
|
|
|
|
|
2005-06-26 23:58:29 +04:00
|
|
|
#ifdef SYSTRACE
|
|
|
|
if (ISSET(p->p_flag, P_SYSTRACE) &&
|
|
|
|
wassugid && !ISSET(p->p_flag, P_SUGID))
|
2005-06-27 21:11:20 +04:00
|
|
|
systrace_execve1(pathbuf, p);
|
2005-06-26 23:58:29 +04:00
|
|
|
#endif /* SYSTRACE */
|
|
|
|
|
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:
|
2002-01-12 00:16:27 +03:00
|
|
|
p->p_flag &= ~P_INEXEC;
|
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;
|
2005-10-31 07:39:41 +03:00
|
|
|
(void) fdrelease(p, 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);
|
2005-10-31 07:39:41 +03:00
|
|
|
VOP_CLOSE(pack.ep_vp, FREAD, cred, p);
|
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:
|
2005-06-26 23:58:29 +04:00
|
|
|
free(pack.ep_hdr, M_EXEC);
|
|
|
|
|
|
|
|
#ifdef SYSTRACE
|
|
|
|
clrflg:
|
|
|
|
#endif /* SYSTRACE */
|
2003-01-18 13:06:22 +03:00
|
|
|
l->l_flag |= oldlwpflags;
|
2002-01-12 17:20:30 +03:00
|
|
|
p->p_flag &= ~P_INEXEC;
|
2001-11-24 01:02:39 +03:00
|
|
|
#ifdef LKM
|
2000-12-08 22:42:11 +03:00
|
|
|
lockmgr(&exec_lock, LK_RELEASE, NULL);
|
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:
|
2002-01-12 17:20:30 +03:00
|
|
|
p->p_flag &= ~P_INEXEC;
|
2001-11-24 01:02:39 +03:00
|
|
|
#ifdef LKM
|
2000-12-08 22:42:11 +03:00
|
|
|
lockmgr(&exec_lock, LK_RELEASE, NULL);
|
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);
|
2000-08-03 00:36:33 +04:00
|
|
|
free(pack.ep_hdr, M_EXEC);
|
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
|
2005-10-31 07:39:41 +03:00
|
|
|
copyargs(struct proc *p, struct exec_package *pack, struct ps_strings *arginfo,
|
2001-07-30 01:22:42 +04:00
|
|
|
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
|
|
|
|
2000-11-21 03:37:49 +03:00
|
|
|
dp = (char *) (cpp + argc + envc + 2 + pack->ep_es->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;
|
2000-12-08 22:42:11 +03:00
|
|
|
lockmgr(&exec_lock, LK_SHARED, NULL);
|
|
|
|
|
|
|
|
if (emul_search(emul->e_name)) {
|
|
|
|
error = EEXIST;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
MALLOC(ee, struct emul_entry *, sizeof(struct emul_entry),
|
|
|
|
M_EXEC, M_WAITOK);
|
|
|
|
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:
|
2000-12-08 22:42:11 +03:00
|
|
|
lockmgr(&exec_lock, LK_RELEASE, NULL);
|
|
|
|
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;
|
2000-12-08 22:42:11 +03:00
|
|
|
lockmgr(&exec_lock, LK_SHARED, NULL);
|
|
|
|
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
proclist_lock_read();
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
proclist_unlock_read();
|
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);
|
|
|
|
FREE(it, M_EXEC);
|
|
|
|
|
2001-02-26 23:43:25 +03:00
|
|
|
out:
|
2000-12-08 22:42:11 +03:00
|
|
|
lockmgr(&exec_lock, LK_RELEASE, NULL);
|
|
|
|
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;
|
2000-12-08 22:42:11 +03:00
|
|
|
lockmgr(&exec_lock, LK_EXCLUSIVE, NULL);
|
|
|
|
|
|
|
|
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 */
|
|
|
|
MALLOC(it, struct exec_entry *, sizeof(struct exec_entry),
|
|
|
|
M_EXEC, M_WAITOK);
|
|
|
|
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:
|
2000-12-08 22:42:11 +03:00
|
|
|
lockmgr(&exec_lock, LK_RELEASE, NULL);
|
|
|
|
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;
|
2000-12-08 22:42:11 +03:00
|
|
|
lockmgr(&exec_lock, LK_EXCLUSIVE, NULL);
|
|
|
|
|
|
|
|
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);
|
|
|
|
FREE(it, M_EXEC);
|
|
|
|
|
|
|
|
/* update execsw[] */
|
|
|
|
exec_init(0);
|
|
|
|
|
2001-02-26 23:43:25 +03:00
|
|
|
out:
|
2000-12-08 22:42:11 +03:00
|
|
|
lockmgr(&exec_lock, LK_RELEASE, NULL);
|
|
|
|
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;
|
|
|
|
|
|
|
|
MALLOC(et, struct execsw_entry *, sizeof(struct execsw_entry),
|
|
|
|
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);
|
|
|
|
#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 */
|
|
|
|
lockinit(&exec_lock, PWAIT, "execlck", 0, 0);
|
|
|
|
|
|
|
|
/* 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.
|
|
|
|
*/
|
|
|
|
new_es = malloc(es_sz * sizeof(struct execsw *), M_EXEC, M_WAITOK);
|
|
|
|
for(i=0; list; i++) {
|
|
|
|
new_es[i] = list->es;
|
|
|
|
e1 = list->next;
|
|
|
|
FREE(list, M_TEMP);
|
|
|
|
list = e1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* New execsw[] array built, now replace old execsw[] and free
|
|
|
|
* used memory.
|
|
|
|
*/
|
|
|
|
old_es = execsw;
|
|
|
|
execsw = new_es;
|
|
|
|
nexecs = es_sz;
|
|
|
|
if (old_es)
|
2005-05-30 02:24:14 +04:00
|
|
|
/*XXXUNCONST*/
|
|
|
|
free(__UNCONST(old_es), M_EXEC);
|
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;
|
|
|
|
execsw = malloc(nexecs*sizeof(struct execsw *), M_EXEC, M_WAITOK);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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) {
|
|
|
|
uobj = uao_create(sz, 0);
|
2004-02-06 01:26:52 +03:00
|
|
|
(*uobj->pgops->pgo_reference)(uobj);
|
2003-08-24 21:52:28 +04:00
|
|
|
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);
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
memcpy((void *)va, e->e_sigcode, sz);
|
|
|
|
#ifdef PMAP_NEED_PROCWR
|
|
|
|
pmap_procwr(&proc0, va, sz);
|
|
|
|
#endif
|
|
|
|
uvm_unmap(kernel_map, va, va + round_page(sz));
|
|
|
|
*e->e_sigobject = uobj;
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
}
|