2011-08-08 10:30:43 +04:00
|
|
|
/* $NetBSD: exec_subr.c,v 1.70 2011/08/08 06:30:43 enami Exp $ */
|
1994-06-29 10:29:24 +04:00
|
|
|
|
1994-01-08 10:14:24 +03:00
|
|
|
/*
|
1996-10-01 03:18:43 +04:00
|
|
|
* Copyright (c) 1993, 1994, 1996 Christopher G. Demetriou
|
1994-01-08 10:14:24 +03:00
|
|
|
* 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 Christopher G. Demetriou.
|
|
|
|
* 4. The name of the author may not be used to endorse or promote products
|
1994-01-29 02:43:26 +03:00
|
|
|
* derived from this software without specific prior written permission
|
1994-01-08 10:14:24 +03:00
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
|
|
* IN NO EVENT SHALL THE AUTHOR 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>
|
2011-08-08 10:30:43 +04:00
|
|
|
__KERNEL_RCSID(0, "$NetBSD: exec_subr.c,v 1.70 2011/08/08 06:30:43 enami Exp $");
|
2006-05-20 19:45:37 +04:00
|
|
|
|
|
|
|
#include "opt_pax.h"
|
2001-11-12 18:25:01 +03:00
|
|
|
|
1994-01-08 10:14:24 +03:00
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/systm.h>
|
|
|
|
#include <sys/proc.h>
|
2008-01-03 17:29:31 +03:00
|
|
|
#include <sys/kmem.h>
|
1994-01-08 10:14:24 +03:00
|
|
|
#include <sys/vnode.h>
|
1994-01-16 06:07:33 +03:00
|
|
|
#include <sys/filedesc.h>
|
1994-01-08 10:14:24 +03:00
|
|
|
#include <sys/exec.h>
|
|
|
|
#include <sys/mman.h>
|
2003-08-08 22:53:13 +04:00
|
|
|
#include <sys/resourcevar.h>
|
2005-07-07 03:08:57 +04:00
|
|
|
#include <sys/device.h>
|
1994-01-08 10:14:24 +03:00
|
|
|
|
2011-06-24 03:42:43 +04:00
|
|
|
#if defined(PAX_ASLR) || defined(PAX_MPROTECT)
|
2006-05-20 19:45:37 +04:00
|
|
|
#include <sys/pax.h>
|
2011-06-24 03:42:43 +04:00
|
|
|
#endif /* PAX_ASLR || PAX_MPROTECT */
|
2006-05-20 19:45:37 +04:00
|
|
|
|
2011-01-17 10:13:31 +03:00
|
|
|
#include <uvm/uvm_extern.h>
|
1998-02-05 10:59:28 +03:00
|
|
|
|
2005-07-07 03:08:57 +04:00
|
|
|
#define VMCMD_EVCNT_DECL(name) \
|
|
|
|
static struct evcnt vmcmd_ev_##name = \
|
|
|
|
EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL, "vmcmd", #name); \
|
|
|
|
EVCNT_ATTACH_STATIC(vmcmd_ev_##name)
|
|
|
|
|
|
|
|
#define VMCMD_EVCNT_INCR(name) \
|
|
|
|
vmcmd_ev_##name.ev_count++
|
|
|
|
|
|
|
|
VMCMD_EVCNT_DECL(calls);
|
|
|
|
VMCMD_EVCNT_DECL(extends);
|
|
|
|
VMCMD_EVCNT_DECL(kills);
|
1996-10-01 03:18:43 +04:00
|
|
|
|
2011-03-04 07:25:58 +03:00
|
|
|
#ifdef DEBUG_STACK
|
|
|
|
#define DPRINTF(a) uprintf a
|
|
|
|
#else
|
|
|
|
#define DPRINTF(a)
|
|
|
|
#endif
|
|
|
|
|
1994-01-08 10:14:24 +03:00
|
|
|
/*
|
|
|
|
* new_vmcmd():
|
|
|
|
* create a new vmcmd structure and fill in its fields based
|
|
|
|
* on function call arguments. make sure objects ref'd by
|
|
|
|
* the vmcmd are 'held'.
|
|
|
|
*/
|
|
|
|
|
|
|
|
void
|
2000-08-01 08:57:28 +04:00
|
|
|
new_vmcmd(struct exec_vmcmd_set *evsp,
|
2005-12-11 15:16:03 +03:00
|
|
|
int (*proc)(struct lwp * l, struct exec_vmcmd *),
|
2009-12-10 17:13:48 +03:00
|
|
|
vsize_t len, vaddr_t addr, struct vnode *vp, u_long offset,
|
2000-08-01 08:57:28 +04:00
|
|
|
u_int prot, int flags)
|
1994-01-08 10:14:24 +03:00
|
|
|
{
|
|
|
|
struct exec_vmcmd *vcp;
|
|
|
|
|
2005-07-07 03:08:57 +04:00
|
|
|
VMCMD_EVCNT_INCR(calls);
|
2010-12-18 01:35:07 +03:00
|
|
|
KASSERT(proc != vmcmd_map_pagedvn || (vp->v_iflag & VI_TEXT));
|
|
|
|
KASSERT(vp == NULL || vp->v_usecount > 0);
|
2005-07-07 03:08:57 +04:00
|
|
|
|
1994-01-08 10:14:24 +03:00
|
|
|
if (evsp->evs_used >= evsp->evs_cnt)
|
|
|
|
vmcmdset_extend(evsp);
|
|
|
|
vcp = &evsp->evs_cmds[evsp->evs_used++];
|
|
|
|
vcp->ev_proc = proc;
|
|
|
|
vcp->ev_len = len;
|
|
|
|
vcp->ev_addr = addr;
|
|
|
|
if ((vcp->ev_vp = vp) != NULL)
|
|
|
|
vref(vp);
|
|
|
|
vcp->ev_offset = offset;
|
|
|
|
vcp->ev_prot = prot;
|
2000-11-06 01:41:35 +03:00
|
|
|
vcp->ev_flags = flags;
|
1994-01-08 10:14:24 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2000-08-01 08:57:28 +04:00
|
|
|
vmcmdset_extend(struct exec_vmcmd_set *evsp)
|
1994-01-08 10:14:24 +03:00
|
|
|
{
|
|
|
|
struct exec_vmcmd *nvcp;
|
|
|
|
u_int ocnt;
|
|
|
|
|
|
|
|
#ifdef DIAGNOSTIC
|
|
|
|
if (evsp->evs_used < evsp->evs_cnt)
|
|
|
|
panic("vmcmdset_extend: not necessary");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* figure out number of entries in new set */
|
2005-07-07 03:08:57 +04:00
|
|
|
if ((ocnt = evsp->evs_cnt) != 0) {
|
|
|
|
evsp->evs_cnt += ocnt;
|
|
|
|
VMCMD_EVCNT_INCR(extends);
|
|
|
|
} else
|
|
|
|
evsp->evs_cnt = EXEC_DEFAULT_VMCMD_SETSIZE;
|
1994-01-08 10:14:24 +03:00
|
|
|
|
|
|
|
/* allocate it */
|
2008-01-03 17:29:31 +03:00
|
|
|
nvcp = kmem_alloc(evsp->evs_cnt * sizeof(struct exec_vmcmd), KM_SLEEP);
|
1994-01-08 10:14:24 +03:00
|
|
|
|
|
|
|
/* free the old struct, if there was one, and record the new one */
|
|
|
|
if (ocnt) {
|
2000-08-03 00:42:03 +04:00
|
|
|
memcpy(nvcp, evsp->evs_cmds,
|
|
|
|
(ocnt * sizeof(struct exec_vmcmd)));
|
2008-01-03 17:29:31 +03:00
|
|
|
kmem_free(evsp->evs_cmds, ocnt * sizeof(struct exec_vmcmd));
|
1994-01-08 10:14:24 +03:00
|
|
|
}
|
|
|
|
evsp->evs_cmds = nvcp;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2000-08-01 08:57:28 +04:00
|
|
|
kill_vmcmds(struct exec_vmcmd_set *evsp)
|
1994-01-08 10:14:24 +03:00
|
|
|
{
|
|
|
|
struct exec_vmcmd *vcp;
|
2002-08-25 23:13:08 +04:00
|
|
|
u_int i;
|
1994-01-08 10:14:24 +03:00
|
|
|
|
2005-07-07 03:08:57 +04:00
|
|
|
VMCMD_EVCNT_INCR(kills);
|
|
|
|
|
1994-01-08 10:14:24 +03:00
|
|
|
if (evsp->evs_cnt == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (i = 0; i < evsp->evs_used; i++) {
|
|
|
|
vcp = &evsp->evs_cmds[i];
|
2003-08-24 21:52:28 +04:00
|
|
|
if (vcp->ev_vp != NULL)
|
1994-01-08 10:14:24 +03:00
|
|
|
vrele(vcp->ev_vp);
|
|
|
|
}
|
2008-01-03 17:29:31 +03:00
|
|
|
kmem_free(evsp->evs_cmds, evsp->evs_cnt * sizeof(struct exec_vmcmd));
|
1994-01-08 10:14:24 +03:00
|
|
|
evsp->evs_used = evsp->evs_cnt = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* vmcmd_map_pagedvn():
|
|
|
|
* handle vmcmd which specifies that a vnode should be mmap'd.
|
|
|
|
* appropriate for handling demand-paged text and data segments.
|
|
|
|
*/
|
|
|
|
|
|
|
|
int
|
2005-12-11 15:16:03 +03:00
|
|
|
vmcmd_map_pagedvn(struct lwp *l, struct exec_vmcmd *cmd)
|
1994-01-08 10:14:24 +03:00
|
|
|
{
|
2001-03-15 09:10:32 +03:00
|
|
|
struct uvm_object *uobj;
|
2006-10-05 18:48:32 +04:00
|
|
|
struct vnode *vp = cmd->ev_vp;
|
2005-12-11 15:16:03 +03:00
|
|
|
struct proc *p = l->l_proc;
|
2001-03-15 09:10:32 +03:00
|
|
|
int error;
|
2006-05-20 19:45:37 +04:00
|
|
|
vm_prot_t prot, maxprot;
|
2001-03-15 09:10:32 +03:00
|
|
|
|
2007-10-11 00:42:20 +04:00
|
|
|
KASSERT(vp->v_iflag & VI_TEXT);
|
1998-02-05 10:59:28 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* map the vnode in using uvm_map.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (cmd->ev_len == 0)
|
|
|
|
return(0);
|
|
|
|
if (cmd->ev_offset & PAGE_MASK)
|
|
|
|
return(EINVAL);
|
|
|
|
if (cmd->ev_addr & PAGE_MASK)
|
|
|
|
return(EINVAL);
|
2000-06-13 08:25:31 +04:00
|
|
|
if (cmd->ev_len & PAGE_MASK)
|
|
|
|
return(EINVAL);
|
1998-02-05 10:59:28 +03:00
|
|
|
|
2007-07-27 12:26:38 +04:00
|
|
|
prot = cmd->ev_prot;
|
|
|
|
maxprot = UVM_PROT_ALL;
|
|
|
|
#ifdef PAX_MPROTECT
|
|
|
|
pax_mprotect(l, &prot, &maxprot);
|
|
|
|
#endif /* PAX_MPROTECT */
|
|
|
|
|
1998-02-05 10:59:28 +03:00
|
|
|
/*
|
2007-07-22 23:16:04 +04:00
|
|
|
* check the file system's opinion about mmapping the file
|
1998-02-05 10:59:28 +03:00
|
|
|
*/
|
|
|
|
|
2008-01-28 23:09:06 +03:00
|
|
|
error = VOP_MMAP(vp, prot, l->l_cred);
|
2007-07-22 23:16:04 +04:00
|
|
|
if (error)
|
|
|
|
return error;
|
2006-10-05 18:48:32 +04:00
|
|
|
|
2007-10-11 00:42:20 +04:00
|
|
|
if ((vp->v_vflag & VV_MAPPED) == 0) {
|
2006-10-05 18:48:32 +04:00
|
|
|
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
|
2007-10-11 00:42:20 +04:00
|
|
|
vp->v_vflag |= VV_MAPPED;
|
2010-06-24 16:58:48 +04:00
|
|
|
VOP_UNLOCK(vp);
|
2006-10-05 18:48:32 +04:00
|
|
|
}
|
1998-02-05 10:59:28 +03:00
|
|
|
|
|
|
|
/*
|
2007-07-22 23:16:04 +04:00
|
|
|
* do the map, reference the object for this map entry
|
1998-02-05 10:59:28 +03:00
|
|
|
*/
|
2007-07-22 23:16:04 +04:00
|
|
|
uobj = &vp->v_uobj;
|
|
|
|
vref(vp);
|
1998-02-05 10:59:28 +03:00
|
|
|
|
2005-02-27 00:34:55 +03:00
|
|
|
error = uvm_map(&p->p_vmspace->vm_map, &cmd->ev_addr, cmd->ev_len,
|
2000-09-13 19:00:15 +04:00
|
|
|
uobj, cmd->ev_offset, 0,
|
2006-05-20 19:45:37 +04:00
|
|
|
UVM_MAPFLAG(prot, maxprot, UVM_INH_COPY,
|
2003-02-21 01:16:05 +03:00
|
|
|
UVM_ADV_NORMAL, UVM_FLAG_COPYONW|UVM_FLAG_FIXED));
|
2001-03-15 09:10:32 +03:00
|
|
|
if (error) {
|
|
|
|
uobj->pgops->pgo_detach(uobj);
|
|
|
|
}
|
|
|
|
return error;
|
1994-01-08 10:14:24 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* vmcmd_map_readvn():
|
|
|
|
* handle vmcmd which specifies that a vnode should be read from.
|
|
|
|
* appropriate for non-demand-paged text/data segments, i.e. impure
|
|
|
|
* objects (a la OMAGIC and NMAGIC).
|
|
|
|
*/
|
|
|
|
int
|
2005-12-11 15:16:03 +03:00
|
|
|
vmcmd_map_readvn(struct lwp *l, struct exec_vmcmd *cmd)
|
1994-01-08 10:14:24 +03:00
|
|
|
{
|
2005-12-11 15:16:03 +03:00
|
|
|
struct proc *p = l->l_proc;
|
1994-01-08 10:14:24 +03:00
|
|
|
int error;
|
1999-07-08 00:23:45 +04:00
|
|
|
long diff;
|
1994-01-08 10:14:24 +03:00
|
|
|
|
1998-02-05 10:59:28 +03:00
|
|
|
if (cmd->ev_len == 0)
|
2001-03-15 09:10:32 +03:00
|
|
|
return 0;
|
|
|
|
|
1999-07-08 00:23:45 +04:00
|
|
|
diff = cmd->ev_addr - trunc_page(cmd->ev_addr);
|
|
|
|
cmd->ev_addr -= diff; /* required by uvm_map */
|
|
|
|
cmd->ev_offset -= diff;
|
|
|
|
cmd->ev_len += diff;
|
|
|
|
|
2005-02-27 00:34:55 +03:00
|
|
|
error = uvm_map(&p->p_vmspace->vm_map, &cmd->ev_addr,
|
2000-09-13 19:00:15 +04:00
|
|
|
round_page(cmd->ev_len), NULL, UVM_UNKNOWN_OFFSET, 0,
|
1998-02-23 21:53:22 +03:00
|
|
|
UVM_MAPFLAG(UVM_PROT_ALL, UVM_PROT_ALL, UVM_INH_COPY,
|
1998-02-05 10:59:28 +03:00
|
|
|
UVM_ADV_NORMAL,
|
2003-02-21 01:16:05 +03:00
|
|
|
UVM_FLAG_FIXED|UVM_FLAG_OVERLAY|UVM_FLAG_COPYONW));
|
1998-02-05 10:59:28 +03:00
|
|
|
|
1994-01-08 10:14:24 +03:00
|
|
|
if (error)
|
|
|
|
return error;
|
|
|
|
|
2005-12-11 15:16:03 +03:00
|
|
|
return vmcmd_readvn(l, cmd);
|
2000-06-21 09:41:07 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2005-12-11 15:16:03 +03:00
|
|
|
vmcmd_readvn(struct lwp *l, struct exec_vmcmd *cmd)
|
2000-06-21 09:41:07 +04:00
|
|
|
{
|
2005-12-11 15:16:03 +03:00
|
|
|
struct proc *p = l->l_proc;
|
2000-06-21 09:41:07 +04:00
|
|
|
int error;
|
2006-05-20 19:45:37 +04:00
|
|
|
vm_prot_t prot, maxprot;
|
2000-06-21 09:41:07 +04:00
|
|
|
|
2007-03-04 08:59:00 +03:00
|
|
|
error = vn_rdwr(UIO_READ, cmd->ev_vp, (void *)cmd->ev_addr,
|
1996-10-01 03:18:43 +04:00
|
|
|
cmd->ev_len, cmd->ev_offset, UIO_USERSPACE, IO_UNIT,
|
2006-07-24 02:06:03 +04:00
|
|
|
l->l_cred, NULL, l);
|
1994-01-08 10:14:24 +03:00
|
|
|
if (error)
|
|
|
|
return error;
|
|
|
|
|
2006-05-20 19:45:37 +04:00
|
|
|
prot = cmd->ev_prot;
|
|
|
|
maxprot = VM_PROT_ALL;
|
|
|
|
#ifdef PAX_MPROTECT
|
|
|
|
pax_mprotect(l, &prot, &maxprot);
|
|
|
|
#endif /* PAX_MPROTECT */
|
|
|
|
|
2003-01-12 08:24:17 +03:00
|
|
|
#ifdef PMAP_NEED_PROCWR
|
|
|
|
/*
|
|
|
|
* we had to write the process, make sure the pages are synched
|
|
|
|
* with the instruction cache.
|
|
|
|
*/
|
2006-05-20 19:45:37 +04:00
|
|
|
if (prot & VM_PROT_EXECUTE)
|
2003-01-12 08:24:17 +03:00
|
|
|
pmap_procwr(p, cmd->ev_addr, cmd->ev_len);
|
|
|
|
#endif
|
|
|
|
|
2006-05-20 19:45:37 +04:00
|
|
|
/*
|
|
|
|
* we had to map in the area at PROT_ALL so that vn_rdwr()
|
|
|
|
* could write to it. however, the caller seems to want
|
|
|
|
* it mapped read-only, so now we are going to have to call
|
|
|
|
* uvm_map_protect() to fix up the protection. ICK.
|
|
|
|
*/
|
|
|
|
if (maxprot != VM_PROT_ALL) {
|
|
|
|
error = uvm_map_protect(&p->p_vmspace->vm_map,
|
|
|
|
trunc_page(cmd->ev_addr),
|
|
|
|
round_page(cmd->ev_addr + cmd->ev_len),
|
2007-02-22 09:34:42 +03:00
|
|
|
maxprot, true);
|
2006-05-20 19:45:37 +04:00
|
|
|
if (error)
|
|
|
|
return (error);
|
|
|
|
}
|
2001-03-15 09:10:32 +03:00
|
|
|
|
2006-05-20 19:45:37 +04:00
|
|
|
if (prot != maxprot) {
|
|
|
|
error = uvm_map_protect(&p->p_vmspace->vm_map,
|
1998-02-23 21:53:22 +03:00
|
|
|
trunc_page(cmd->ev_addr),
|
|
|
|
round_page(cmd->ev_addr + cmd->ev_len),
|
2007-02-22 09:34:42 +03:00
|
|
|
prot, false);
|
2006-05-20 19:45:37 +04:00
|
|
|
if (error)
|
|
|
|
return (error);
|
1998-02-23 21:53:22 +03:00
|
|
|
}
|
2006-05-20 19:45:37 +04:00
|
|
|
|
2001-03-15 09:10:32 +03:00
|
|
|
return 0;
|
1994-01-08 10:14:24 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* vmcmd_map_zero():
|
|
|
|
* handle vmcmd which specifies a zero-filled address space region. The
|
|
|
|
* address range must be first allocated, then protected appropriately.
|
|
|
|
*/
|
|
|
|
|
|
|
|
int
|
2005-12-11 15:16:03 +03:00
|
|
|
vmcmd_map_zero(struct lwp *l, struct exec_vmcmd *cmd)
|
1994-01-08 10:14:24 +03:00
|
|
|
{
|
2005-12-11 15:16:03 +03:00
|
|
|
struct proc *p = l->l_proc;
|
1994-01-08 10:14:24 +03:00
|
|
|
int error;
|
1999-07-08 00:23:45 +04:00
|
|
|
long diff;
|
2006-05-20 19:45:37 +04:00
|
|
|
vm_prot_t prot, maxprot;
|
1994-01-08 10:14:24 +03:00
|
|
|
|
1999-07-08 00:23:45 +04:00
|
|
|
diff = cmd->ev_addr - trunc_page(cmd->ev_addr);
|
|
|
|
cmd->ev_addr -= diff; /* required by uvm_map */
|
|
|
|
cmd->ev_len += diff;
|
|
|
|
|
2006-05-20 19:45:37 +04:00
|
|
|
prot = cmd->ev_prot;
|
|
|
|
maxprot = UVM_PROT_ALL;
|
|
|
|
#ifdef PAX_MPROTECT
|
|
|
|
pax_mprotect(l, &prot, &maxprot);
|
|
|
|
#endif /* PAX_MPROTECT */
|
|
|
|
|
2005-02-27 00:34:55 +03:00
|
|
|
error = uvm_map(&p->p_vmspace->vm_map, &cmd->ev_addr,
|
2000-09-13 19:00:15 +04:00
|
|
|
round_page(cmd->ev_len), NULL, UVM_UNKNOWN_OFFSET, 0,
|
2006-05-20 19:45:37 +04:00
|
|
|
UVM_MAPFLAG(prot, maxprot, UVM_INH_COPY,
|
1998-02-05 10:59:28 +03:00
|
|
|
UVM_ADV_NORMAL,
|
2003-02-21 01:16:05 +03:00
|
|
|
UVM_FLAG_FIXED|UVM_FLAG_COPYONW));
|
- add new RLIMIT_AS (aka RLIMIT_VMEM) resource that limits the total
address space available to processes. this limit exists in most other
modern unix variants, and like most of them, our defaults are unlimited.
remove the old mmap / rlimit.datasize hack.
- adds the VMCMD_STACK flag to all the stack-creation vmcmd callers.
it is currently unused, but was added a few years ago.
- add a pair of new process size values to kinfo_proc2{}. one is the
total size of the process memory map, and the other is the total size
adjusted for unused stack space (since most processes have a lot of
this...)
- patch sh, and csh to notice RLIMIT_AS. (in some cases, the alias
RLIMIT_VMEM was already present and used if availble.)
- patch ps, top and systat to notice the new k_vm_vsize member of
kinfo_proc2{}.
- update irix, svr4, svr4_32, linux and osf1 emulations to support
this information. (freebsd could be done, but that it's best left
as part of the full-update of compat/freebsd.)
this addresses PR 7897. it also gives correct memory usage values,
which have never been entirely correct (since mmap), and have been
very incorrect since jemalloc() was enabled.
tested on i386 and sparc64, build tested on several other platforms.
thanks to many folks for feedback and testing but most espcially
chuq and yamt for critical suggestions that lead to this patch not
having a special ugliness i wasn't happy with anyway :-)
2009-03-29 05:02:48 +04:00
|
|
|
if (cmd->ev_flags & VMCMD_STACK)
|
|
|
|
curproc->p_vmspace->vm_issize += atop(round_page(cmd->ev_len));
|
2001-03-15 09:10:32 +03:00
|
|
|
return error;
|
1994-01-08 10:14:24 +03:00
|
|
|
}
|
2001-07-14 06:08:29 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* exec_read_from():
|
|
|
|
*
|
|
|
|
* Read from vnode into buffer at offset.
|
|
|
|
*/
|
|
|
|
int
|
2005-12-11 15:16:03 +03:00
|
|
|
exec_read_from(struct lwp *l, struct vnode *vp, u_long off, void *bf,
|
2001-07-14 06:08:29 +04:00
|
|
|
size_t size)
|
|
|
|
{
|
|
|
|
int error;
|
|
|
|
size_t resid;
|
|
|
|
|
2005-05-30 02:24:14 +04:00
|
|
|
if ((error = vn_rdwr(UIO_READ, vp, bf, size, off, UIO_SYSSPACE,
|
2006-07-24 02:06:03 +04:00
|
|
|
0, l->l_cred, &resid, NULL)) != 0)
|
2001-07-14 06:08:29 +04:00
|
|
|
return error;
|
|
|
|
/*
|
|
|
|
* See if we got all of it
|
|
|
|
*/
|
|
|
|
if (resid != 0)
|
|
|
|
return ENOEXEC;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2003-08-08 22:53:13 +04:00
|
|
|
/*
|
|
|
|
* exec_setup_stack(): Set up the stack segment for an elf
|
|
|
|
* executable.
|
|
|
|
*
|
|
|
|
* Note that the ep_ssize parameter must be set to be the current stack
|
|
|
|
* limit; this is adjusted in the body of execve() to yield the
|
|
|
|
* appropriate stack segment usage once the argument length is
|
|
|
|
* calculated.
|
|
|
|
*
|
|
|
|
* This function returns an int for uniformity with other (future) formats'
|
|
|
|
* stack setup functions. They might have errors to return.
|
|
|
|
*/
|
|
|
|
|
|
|
|
int
|
2005-12-11 15:16:03 +03:00
|
|
|
exec_setup_stack(struct lwp *l, struct exec_package *epp)
|
2003-08-08 22:53:13 +04:00
|
|
|
{
|
2009-12-10 17:13:48 +03:00
|
|
|
vsize_t max_stack_size;
|
|
|
|
vaddr_t access_linear_min;
|
|
|
|
vsize_t access_size;
|
|
|
|
vaddr_t noaccess_linear_min;
|
|
|
|
vsize_t noaccess_size;
|
2003-08-08 22:53:13 +04:00
|
|
|
|
|
|
|
#ifndef USRSTACK32
|
|
|
|
#define USRSTACK32 (0x00000000ffffffffL&~PGOFSET)
|
2011-03-04 07:25:58 +03:00
|
|
|
#endif
|
|
|
|
#ifndef MAXSSIZ32
|
|
|
|
#define MAXSSIZ32 (MAXSSIZ >> 2)
|
2003-08-08 22:53:13 +04:00
|
|
|
#endif
|
|
|
|
|
|
|
|
if (epp->ep_flags & EXEC_32) {
|
|
|
|
epp->ep_minsaddr = USRSTACK32;
|
2011-03-04 07:25:58 +03:00
|
|
|
max_stack_size = MAXSSIZ32;
|
2003-08-08 22:53:13 +04:00
|
|
|
} else {
|
|
|
|
epp->ep_minsaddr = USRSTACK;
|
|
|
|
max_stack_size = MAXSSIZ;
|
|
|
|
}
|
2011-03-04 07:25:58 +03:00
|
|
|
|
|
|
|
DPRINTF(("ep_minsaddr=%llx max_stack_size=%llx\n",
|
|
|
|
(unsigned long long)epp->ep_minsaddr,
|
|
|
|
(unsigned long long)max_stack_size));
|
|
|
|
|
2011-08-08 10:30:43 +04:00
|
|
|
epp->ep_ssize = MIN(l->l_proc->p_rlimit[RLIMIT_STACK].rlim_cur,
|
|
|
|
max_stack_size);
|
2007-12-27 01:11:47 +03:00
|
|
|
|
|
|
|
#ifdef PAX_ASLR
|
|
|
|
pax_aslr_stack(l, epp, &max_stack_size);
|
|
|
|
#endif /* PAX_ASLR */
|
|
|
|
|
|
|
|
l->l_proc->p_stackbase = epp->ep_minsaddr;
|
|
|
|
|
2009-12-10 17:13:48 +03:00
|
|
|
epp->ep_maxsaddr = (vaddr_t)STACK_GROW(epp->ep_minsaddr,
|
2003-08-08 22:53:13 +04:00
|
|
|
max_stack_size);
|
|
|
|
|
2011-03-04 07:25:58 +03:00
|
|
|
DPRINTF(("ep_ssize=%llx ep_maxsaddr=%llx\n",
|
|
|
|
(unsigned long long)epp->ep_ssize,
|
|
|
|
(unsigned long long)epp->ep_maxsaddr));
|
|
|
|
|
2003-08-08 22:53:13 +04:00
|
|
|
/*
|
|
|
|
* set up commands for stack. note that this takes *two*, one to
|
|
|
|
* map the part of the stack which we can access, and one to map
|
|
|
|
* the part which we can't.
|
|
|
|
*
|
|
|
|
* arguably, it could be made into one, but that would require the
|
|
|
|
* addition of another mapping proc, which is unnecessary
|
|
|
|
*/
|
|
|
|
access_size = epp->ep_ssize;
|
2009-12-10 17:13:48 +03:00
|
|
|
access_linear_min = (vaddr_t)STACK_ALLOC(epp->ep_minsaddr, access_size);
|
2003-08-08 22:53:13 +04:00
|
|
|
noaccess_size = max_stack_size - access_size;
|
2009-12-10 17:13:48 +03:00
|
|
|
noaccess_linear_min = (vaddr_t)STACK_ALLOC(STACK_GROW(epp->ep_minsaddr,
|
2003-08-08 22:53:13 +04:00
|
|
|
access_size), noaccess_size);
|
2011-03-04 07:25:58 +03:00
|
|
|
|
|
|
|
DPRINTF(("access_size=%llx, access_linear_min=%llx, "
|
|
|
|
"noaccess_size=%llx, noaccess_linear_min=%llx\n",
|
|
|
|
(unsigned long long)access_size,
|
|
|
|
(unsigned long long)access_linear_min,
|
|
|
|
(unsigned long long)noaccess_size,
|
|
|
|
(unsigned long long)noaccess_linear_min));
|
|
|
|
|
2010-08-24 00:53:08 +04:00
|
|
|
if (noaccess_size > 0 && noaccess_size <= MAXSSIZ) {
|
- add new RLIMIT_AS (aka RLIMIT_VMEM) resource that limits the total
address space available to processes. this limit exists in most other
modern unix variants, and like most of them, our defaults are unlimited.
remove the old mmap / rlimit.datasize hack.
- adds the VMCMD_STACK flag to all the stack-creation vmcmd callers.
it is currently unused, but was added a few years ago.
- add a pair of new process size values to kinfo_proc2{}. one is the
total size of the process memory map, and the other is the total size
adjusted for unused stack space (since most processes have a lot of
this...)
- patch sh, and csh to notice RLIMIT_AS. (in some cases, the alias
RLIMIT_VMEM was already present and used if availble.)
- patch ps, top and systat to notice the new k_vm_vsize member of
kinfo_proc2{}.
- update irix, svr4, svr4_32, linux and osf1 emulations to support
this information. (freebsd could be done, but that it's best left
as part of the full-update of compat/freebsd.)
this addresses PR 7897. it also gives correct memory usage values,
which have never been entirely correct (since mmap), and have been
very incorrect since jemalloc() was enabled.
tested on i386 and sparc64, build tested on several other platforms.
thanks to many folks for feedback and testing but most espcially
chuq and yamt for critical suggestions that lead to this patch not
having a special ugliness i wasn't happy with anyway :-)
2009-03-29 05:02:48 +04:00
|
|
|
NEW_VMCMD2(&epp->ep_vmcmds, vmcmd_map_zero, noaccess_size,
|
|
|
|
noaccess_linear_min, NULL, 0, VM_PROT_NONE, VMCMD_STACK);
|
2003-08-21 19:17:03 +04:00
|
|
|
}
|
2010-08-24 00:53:08 +04:00
|
|
|
KASSERT(access_size > 0 && access_size <= MAXSSIZ);
|
- add new RLIMIT_AS (aka RLIMIT_VMEM) resource that limits the total
address space available to processes. this limit exists in most other
modern unix variants, and like most of them, our defaults are unlimited.
remove the old mmap / rlimit.datasize hack.
- adds the VMCMD_STACK flag to all the stack-creation vmcmd callers.
it is currently unused, but was added a few years ago.
- add a pair of new process size values to kinfo_proc2{}. one is the
total size of the process memory map, and the other is the total size
adjusted for unused stack space (since most processes have a lot of
this...)
- patch sh, and csh to notice RLIMIT_AS. (in some cases, the alias
RLIMIT_VMEM was already present and used if availble.)
- patch ps, top and systat to notice the new k_vm_vsize member of
kinfo_proc2{}.
- update irix, svr4, svr4_32, linux and osf1 emulations to support
this information. (freebsd could be done, but that it's best left
as part of the full-update of compat/freebsd.)
this addresses PR 7897. it also gives correct memory usage values,
which have never been entirely correct (since mmap), and have been
very incorrect since jemalloc() was enabled.
tested on i386 and sparc64, build tested on several other platforms.
thanks to many folks for feedback and testing but most espcially
chuq and yamt for critical suggestions that lead to this patch not
having a special ugliness i wasn't happy with anyway :-)
2009-03-29 05:02:48 +04:00
|
|
|
NEW_VMCMD2(&epp->ep_vmcmds, vmcmd_map_zero, access_size,
|
|
|
|
access_linear_min, NULL, 0, VM_PROT_READ | VM_PROT_WRITE,
|
|
|
|
VMCMD_STACK);
|
2003-08-08 22:53:13 +04:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|