* Copyright (c) 1982, 1986, 1991 The Regents of the University of California.
* %sccs.include.proprietary.c%
* @(#)kern_exec.c 7.52 (Berkeley) %G%
#include "user.h" /* for pcb */
#include "hp300/hpux/hpux_exec.h"
extern char sigcode
[], esigcode
[];
#define szsigcode (esigcode - sigcode)
register struct ucred
*cred
= p
->p_ucred
;
register struct filedesc
*fdp
= p
->p_fd
;
int na
, ne
, ucp
, ap
, cc
, ssize
;
int resid
, error
, paged
= 0;
vm_offset_t execargs
= 0;
char ex_shell
[MAXINTERP
]; /* #! and interpreter name */
struct hpux_exec ex_hexec
;
extern long argdbsize
; /* XXX */
NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
| SAVENAME
, UIO_USERSPACE
,
if (error
= VOP_GETATTR(vp
, &vattr
, cred
, p
))
if (vp
->v_mount
->mnt_flag
& MNT_NOEXEC
) {
if ((vp
->v_mount
->mnt_flag
& MNT_NOSUID
) == 0) {
if (vattr
.va_mode
& VSUID
)
if (vattr
.va_mode
& VSGID
)
if (error
= VOP_ACCESS(vp
, VEXEC
, cred
, p
))
if ((p
->p_flag
& STRC
) && (error
= VOP_ACCESS(vp
, VREAD
, cred
, p
)))
if (vp
->v_type
!= VREG
||
(vattr
.va_mode
& (VEXEC
|(VEXEC
>>3)|(VEXEC
>>6))) == 0) {
* Read in first few bytes of file for segment sizes, magic number:
* OMAGIC = plain executable
* ZMAGIC = demand paged RO text
* Also an ASCII line beginning with #! is
* the file name of a ``shell'' and arguments may be prepended
* to the argument list if given here.
* SHELL NAMES ARE LIMITED IN LENGTH.
* ONLY ONE ARGUMENT MAY BE PASSED TO THE SHELL FROM
exdata
.ex_shell
[0] = '\0'; /* for zero length files */
error
= vn_rdwr(UIO_READ
, vp
, (caddr_t
)&exdata
, sizeof (exdata
),
(off_t
)0, UIO_SYSSPACE
, (IO_UNIT
|IO_NODELOCKED
), cred
, &resid
,
if (resid
> sizeof(exdata
) - sizeof(exdata
.ex_exec
) &&
exdata
.ex_shell
[0] != '#') {
switch ((int)exdata
.ex_exec
.a_mid
) {
* An ancient hp200 or hp300 binary, shouldn't happen anymore.
exdata
.ex_exec
.a_magic
= 0;
* HP200 series has a smaller page size so we cannot
* demand-load or even write protect text, so we just
exdata
.ex_exec
.a_magic
= OMAGIC
;
* Save a.out header. This is eventually saved in the pcb,
* but we cannot do that yet in case the exec fails before
* the image is overlayed.
bcopy((caddr_t
)&exdata
.ex_hexec
,
(caddr_t
)&hhead
, sizeof hhead
);
* If version number is 0x2bad this is a native BSD
* binary created via the HPUX SGS. Should not be
* treated as an HPUX binary.
if (exdata
.ex_hexec
.ha_version
!= BSDVNUM
)
paged
|= SHPUX
; /* XXX */
* Shuffle important fields to their BSD locations.
* Note that the order in which this is done is important.
exdata
.ex_exec
.a_text
= exdata
.ex_hexec
.ha_text
;
exdata
.ex_exec
.a_data
= exdata
.ex_hexec
.ha_data
;
exdata
.ex_exec
.a_bss
= exdata
.ex_hexec
.ha_bss
;
exdata
.ex_exec
.a_entry
= exdata
.ex_hexec
.ha_entry
;
* For ZMAGIC files, make sizes consistant with those
if (exdata
.ex_exec
.a_magic
== ZMAGIC
) {
ctob(btoc(exdata
.ex_exec
.a_text
));
nc
= exdata
.ex_exec
.a_data
+ exdata
.ex_exec
.a_bss
;
ctob(btoc(exdata
.ex_exec
.a_data
));
nc
-= (int)exdata
.ex_exec
.a_data
;
exdata
.ex_exec
.a_bss
= (nc
< 0) ? 0 : nc
;
switch ((int)exdata
.ex_exec
.a_magic
) {
if (exdata
.ex_exec
.ex_fhdr
.magic
!= COFF_MAGIC
) {
if (exdata
.ex_exec
.a_mid
!= MID_SUN_SPARC
) {
exdata
.ex_exec
.a_data
+= exdata
.ex_exec
.a_text
;
exdata
.ex_exec
.a_text
= 0;
if (exdata
.ex_exec
.ex_fhdr
.magic
!= COFF_MAGIC
) {
if (exdata
.ex_exec
.a_mid
!= MID_SUN_SPARC
) {
if (exdata
.ex_exec
.a_text
== 0) {
if (exdata
.ex_shell
[0] != '#' ||
exdata
.ex_shell
[1] != '!' ||
for (cp
= &exdata
.ex_shell
[2];; ++cp
) {
if (cp
>= &exdata
.ex_shell
[MAXINTERP
]) {
cp
= &exdata
.ex_shell
[2];
while (*cp
&& *cp
!= ' ')
bcopy((caddr_t
)cp
, (caddr_t
)cfarg
, MAXINTERP
);
nd
.ni_segflg
= UIO_SYSSPACE
;
if (error
= VOP_GETATTR(vp
, &vattr
, cred
, p
))
uid
= cred
->cr_uid
; /* shell scripts can't be setuid */
* Collect arguments on "file" in swap space.
execargs
= kmem_alloc_wait(exec_map
, NCARGS
);
if (execargs
== (vm_offset_t
)0)
panic("execve: kmem_alloc_wait");
* Copy arguments into file in argdev area.
if (uap
->argp
) for (;;) {
sharg
= nd
.ni_cnd
.cn_nameptr
;
uap
->argp
++; /* ignore argv[0] */
} else if (indir
&& (na
== 1 && cfarg
[0])) {
} else if (indir
&& (na
== 1 || na
== 2 && cfarg
[0]))
ap
= fuword((caddr_t
)uap
->argp
);
if (ap
== NULL
&& uap
->envp
) {
if ((ap
= fuword((caddr_t
)uap
->envp
)) != NULL
)
error
= copystr(sharg
, cp
, (unsigned)cc
, &len
);
error
= copyinstr((caddr_t
)ap
, cp
, (unsigned)cc
,
} while (error
== ENAMETOOLONG
);
* XXX the following is excessively bogus
* Compute initial process stack size and location of argc
* and character strings. `nc' is currently just the number
* of characters of arg and env strings.
* nc = size of signal code + 4 bytes of NULL pointer + nc,
* rounded to nearest integer;
* ucp = USRSTACK - nc; [user characters pointer]
* apsize = padding (if any) +
* 4 bytes of NULL pointer +
* ne 4-byte pointers to env strings +
* 4 bytes of NULL pointer +
* (na-ne) 4-byte pointers to arg strings +
* (this is the same as nc + (na+3)*4)
* ap = ucp - apsize; [user address of argc]
* ssize = ssize + nc + machine-dependent space;
nc
= (szsigcode
+ 4 + nc
+ NBPW
-1) & ~(NBPW
- 1);
ssize
= (nc
+ (na
+ 3) * NBPW
+ 7) & ~7;
ssize
+= sizeof(struct rwindow
);
error
= getxfile(p
, vp
, &exdata
.ex_exec
, paged
, ssize
, uid
, gid
);
* We are now committed to the exec so we can save the exec
* header in the pcb where we can dump it if necessary in core()
if (p
->p_addr
->u_pcb
.pcb_flags
& PCB_HPUXBIN
)
(caddr_t
)p
->p_addr
->u_pcb
.pcb_exec
, sizeof hhead
);
(void) suword((caddr_t
)ap
, na
-ne
);
(void) suword((caddr_t
)ap
, 0);
(void) suword((caddr_t
)ap
, ucp
);
error
= copyoutstr(cp
, (caddr_t
)ucp
, (unsigned)cc
,
} while (error
== ENAMETOOLONG
);
(void) suword((caddr_t
)ap
, 0);
for (nc
= fdp
->fd_lastfile
; nc
>= 0; --nc
) {
if (fdp
->fd_ofileflags
[nc
] & UF_EXCLOSE
) {
(void) closef(fdp
->fd_ofiles
[nc
], p
);
fdp
->fd_ofiles
[nc
] = NULL
;
fdp
->fd_ofileflags
[nc
] = 0;
if (nc
< fdp
->fd_freefile
)
fdp
->fd_ofileflags
[nc
] &= ~UF_MAPPED
;
* Adjust fd_lastfile to account for descriptors closed above.
* Don't decrement fd_lastfile past 0, as it's unsigned.
while (fdp
->fd_lastfile
> 0 && fdp
->fd_ofiles
[fdp
->fd_lastfile
] == NULL
)
setregs(p
, exdata
.ex_exec
.a_entry
, retval
);
* Install sigcode at top of user stack.
copyout((caddr_t
)sigcode
, (caddr_t
)(USRSTACK
- szsigcode
), szsigcode
);
* Remember file name for accounting.
if (nd
.ni_cnd
.cn_namelen
> MAXCOMLEN
)
nd
.ni_cnd
.cn_namelen
= MAXCOMLEN
;
bcopy((caddr_t
)nd
.ni_cnd
.cn_nameptr
, (caddr_t
)p
->p_comm
,
(unsigned)nd
.ni_cnd
.cn_namelen
);
p
->p_comm
[nd
.ni_cnd
.cn_namelen
] = '\0';
FREE(nd
.ni_cnd
.cn_pnbuf
, M_NAMEI
);
kmem_free_wakeup(exec_map
, execargs
, NCARGS
);
* Read in and set up memory for executed file.
getxfile(p
, vp
, ep
, paged
, ssize
, uid
, gid
)
register struct vnode
*vp
;
register struct exec
*ep
;
int paged
, ssize
, uid
, gid
;
register struct ucred
*cred
= p
->p_ucred
;
register struct vmspace
*vm
= p
->p_vmspace
;
int hpux
= (paged
& SHPUX
);
if (ep
->a_mid
== MID_HPUX
) {
toff
= sizeof (struct hpux_exec
);
if (ep
->a_mid
== MID_SUN_SPARC
)
toff
= paged
? 0 : sizeof(struct exec
);
toff
= sizeof (struct exec
);
if (ep
->a_text
!= 0 && (vp
->v_flag
& VTEXT
) == 0 &&
* Compute text and data sizes and make sure not too large.
* Text size is rounded to an ``ld page''; data+bss is left
* in machine pages. Check data and bss separately as they
* may overflow when summed together. (XXX not done yet)
xts
= roundup(ep
->a_text
, __LDPGSZ
);
ds
= clrnd(btoc(ep
->a_data
+ ep
->a_bss
));
* If we're sharing the address space, allocate a new space
* and release our reference to the old one. Otherwise,
* empty out the existing vmspace.
kill_user_windows(p
); /* before addrs go away */
p
->p_vmspace
= vmspace_alloc(VM_MIN_ADDRESS
,
(void) vm_map_remove(&vm
->vm_map
, VM_MIN_ADDRESS
,
* If parent is waiting for us to exec or exit,
* SPPWAIT will be set; clear it and wakeup parent.
if (p
->p_flag
& SPPWAIT
) {
wakeup((caddr_t
) p
->p_pptr
);
p
->p_addr
->u_pcb
.pcb_flags
&= ~(PCB_HPUXMMAP
|PCB_HPUXBIN
);
/* remember that we were loaded from an HPUX format file */
if (ep
->a_mid
== MID_HPUX
)
p
->p_addr
->u_pcb
.pcb_flags
|= PCB_HPUXBIN
;
* Always start out as an ULTRIX process.
* A system call in crt0.o will change us to BSD system calls later.
p
->p_md
.md_flags
|= MDP_ULTRIX
;
if (vm_allocate(&vm
->vm_map
, &addr
, xts
+ ctob(ds
), FALSE
)) {
uprintf("Cannot allocate text+data space\n");
error
= ENOMEM
; /* XXX */
vm
->vm_taddr
= (caddr_t
)VM_MIN_ADDRESS
;
vm
->vm_daddr
= (caddr_t
)(VM_MIN_ADDRESS
+ xts
);
addr
= (vm_offset_t
)ep
->ex_aout
.codeStart
;
vm
->vm_taddr
= (caddr_t
)addr
;
if (vm_allocate(&vm
->vm_map
, &addr
, xts
, FALSE
)) {
uprintf("Cannot allocate text space\n");
error
= ENOMEM
; /* XXX */
addr
= (vm_offset_t
)ep
->ex_aout
.heapStart
;
vm
->vm_daddr
= (caddr_t
)addr
;
if (vm_allocate(&vm
->vm_map
, &addr
, round_page(ctob(ds
)), FALSE
)) {
uprintf("Cannot allocate data space\n");
error
= ENOMEM
; /* XXX */
size
= round_page(MAXSSIZ
); /* XXX */
addr
= trunc_page(USRSTACK
- size
) - NBPG
; /* XXX */
addr
= trunc_page(USRSTACK
- size
);
if (vm_allocate(&vm
->vm_map
, &addr
, size
, FALSE
)) {
uprintf("Cannot allocate stack space\n");
error
= ENOMEM
; /* XXX */
size
-= round_page(p
->p_rlimit
[RLIMIT_STACK
].rlim_cur
);
if (vm_map_protect(&vm
->vm_map
, addr
, addr
+size
, VM_PROT_NONE
, FALSE
)) {
uprintf("Cannot protect stack space\n");
vm
->vm_maxsaddr
= (caddr_t
)addr
;
(void) vn_rdwr(UIO_READ
, vp
, vm
->vm_daddr
, (int) ep
->a_data
,
(off_t
)(toff
+ ep
->a_text
), UIO_USERSPACE
,
(IO_UNIT
|IO_NODELOCKED
), cred
, (int *)0, p
);
* Read in text segment if necessary (0410),
error
= vn_rdwr(UIO_READ
, vp
, vm
->vm_taddr
,
(int)ep
->a_text
, toff
, UIO_USERSPACE
,
(IO_UNIT
|IO_NODELOCKED
), cred
, (int *)0, p
);
(void) vm_map_protect(&vm
->vm_map
, vm
->vm_taddr
,
vm
->vm_taddr
+ trunc_page(ep
->a_text
),
VM_PROT_READ
|VM_PROT_EXECUTE
, FALSE
);
* Allocate a region backed by the exec'ed vnode.
size
= round_page(xts
+ ep
->a_data
);
error
= vm_mmap(&vm
->vm_map
, &addr
, size
, VM_PROT_ALL
,
MAP_FILE
|MAP_COPY
|MAP_FIXED
,
(caddr_t
)vp
, (vm_offset_t
)toff
);
(void) vm_map_protect(&vm
->vm_map
, addr
, addr
+ xts
,
VM_PROT_READ
|VM_PROT_EXECUTE
, FALSE
);
addr
= (vm_offset_t
)vm
->vm_taddr
;
error
= vm_mmap(&vm
->vm_map
, &addr
, size
,
VM_PROT_READ
|VM_PROT_EXECUTE
,
MAP_FILE
|MAP_COPY
|MAP_FIXED
,
(caddr_t
)vp
, (vm_offset_t
)toff
);
addr
= (vm_offset_t
)vm
->vm_daddr
;
size
= round_page(ep
->a_data
);
error
= vm_mmap(&vm
->vm_map
, &addr
, size
, VM_PROT_ALL
,
MAP_FILE
|MAP_COPY
|MAP_FIXED
,
(caddr_t
)vp
, (vm_offset_t
)toff
);
printf("pid %d: VM allocation failure\n", p
->p_pid
);
uprintf("sorry, pid %d was killed in exec: VM allocation\n",
* set SUID/SGID protections, if no tracing
if ((p
->p_flag
&STRC
)==0) {
if (uid
!= cred
->cr_uid
|| gid
!= cred
->cr_gid
) {
p
->p_ucred
= cred
= crcopy(cred
);
* If process is being ktraced, turn off - unless
if (p
->p_tracep
&& !(p
->p_traceflag
& KTRFAC_ROOT
)) {
p
->p_cred
->p_svuid
= cred
->cr_uid
;
p
->p_cred
->p_svgid
= cred
->cr_gid
;
vm
->vm_tsize
= btoc(xts
);
p
->p_stats
->p_prof
.pr_scale
= 0;
/* move this when tahoe cpu_exec is created */
p
->p_addr
->u_pcb
.pcb_savacc
.faddr
= (float *)NULL
;