exec() cleanup, generalization, improvement

. make exec() callers (i.e. vfs and rs) determine the
	  memory layout by explicitly reserving regions using
	  mmap() calls on behalf of the exec()ing process,
	  i.e. handling all of the exec logic, thereby eliminating
	  all special exec() knowledge from VM.
	. the new procedure is: clear the exec()ing process
	  first, then call third-party mmap()s to reserve memory, then
	  copy the executable file section contents in, all using callbacks
	  tailored to the caller's way of starting an executable
	. i.e. no more explicit EXEC_NEWMEM-style calls in PM or VM
	  as with rigid 2-section arguments
	. this naturally allows generalizing exec() by simply loading
	  all ELF sections
	. drop/merge of lots of duplicate exec() code into libexec
	. not copying the code sections to vfs and into the executable
	  again is a measurable performance improvement (about 3.3% faster
	  for 'make' in src/servers/)
This commit is contained in:
Ben Gras 2012-05-30 19:34:07 +02:00
parent 41b869d4d6
commit 040362e379
29 changed files with 409 additions and 946 deletions

View File

@ -49,4 +49,9 @@
#define PAGE_SIZE (1 << PAGE_SHIFT) #define PAGE_SIZE (1 << PAGE_SHIFT)
#define PAGE_MASK (PAGE_SIZE - 1) #define PAGE_MASK (PAGE_SIZE - 1)
/* As visible from the user space process, where is the top of the
* stack (first non-stack byte), when in paged mode?
*/
#define VM_STACKTOP 0x80000000
#endif /* _I386_VMPARAM_H_ */ #endif /* _I386_VMPARAM_H_ */

View File

@ -97,9 +97,7 @@
#define CPROF 99 /* to PM */ #define CPROF 99 /* to PM */
/* Calls provided by PM and FS that are not part of the API */ /* Calls provided by PM and FS that are not part of the API */
#define EXEC_NEWMEM 100 /* from VFS or RS to PM: new memory map for #define PM_NEWEXEC 100 /* from VFS or RS to PM: new exec */
* exec
*/
#define SRV_FORK 101 /* to PM: special fork call for RS */ #define SRV_FORK 101 /* to PM: special fork call for RS */
#define EXEC_RESTART 102 /* to PM: final part of exec for RS */ #define EXEC_RESTART 102 /* to PM: final part of exec for RS */
#define GETPROCNR 104 /* to PM */ #define GETPROCNR 104 /* to PM */

View File

@ -54,4 +54,7 @@ error "_MINIX_MACHINE has incorrect value (0)"
#define _KMESS_BUF_SIZE 10000 #define _KMESS_BUF_SIZE 10000
/* Default stack size (limit) */
#define DEFAULT_STACK_LIMIT (64 * 1024 * 1024)
#endif /* _MINIX_SYS_CONFIG_H */ #endif /* _MINIX_SYS_CONFIG_H */

View File

@ -166,26 +166,6 @@ struct mem_range
phys_bytes mr_limit; /* Highest memory address in range */ phys_bytes mr_limit; /* Highest memory address in range */
}; };
/* For EXEC_NEWMEM */
struct exec_newmem
{
vir_bytes text_addr; /* Starting address of text section */
vir_bytes text_bytes; /* Length of text section (in bytes) */
vir_bytes data_addr; /* Starting address of data section */
vir_bytes data_bytes; /* Length of data section (in bytes) */
vir_bytes tot_bytes; /* Minimum stack region size (in bytes) */
vir_bytes args_bytes; /* Arguments/environ size on stack (in bytes) */
int sep_id; /* Separate I&D? */
int is_elf; /* Is ELF exe? */
dev_t st_dev; /* Device holding executable file */
ino_t st_ino; /* Inode of executable file */
time_t enst_ctime; /* Last changed time of executable file */
uid_t new_uid; /* Process UID after exec */
gid_t new_gid; /* Process GID after exec */
int setugid; /* Process is setuid or setgid */
char progname[16]; /* Should be at least PROC_NAME_LEN */
};
/* Memory chunks. */ /* Memory chunks. */
struct memory { struct memory {
phys_bytes base; phys_bytes base;

View File

@ -9,8 +9,6 @@
int vm_exit(endpoint_t ep); int vm_exit(endpoint_t ep);
int vm_fork(endpoint_t ep, int slotno, endpoint_t *child_ep); int vm_fork(endpoint_t ep, int slotno, endpoint_t *child_ep);
int vm_brk(endpoint_t ep, char *newaddr); int vm_brk(endpoint_t ep, char *newaddr);
int vm_exec_newmem(endpoint_t ep, struct exec_newmem *args, int
args_bytes, char **ret_stack_top, int *ret_flags);
int vm_push_sig(endpoint_t ep, vir_bytes *old_sp); int vm_push_sig(endpoint_t ep, vir_bytes *old_sp);
int vm_willexit(endpoint_t ep); int vm_willexit(endpoint_t ep);
int vm_adddma(endpoint_t proc_e, phys_bytes start, phys_bytes size); int vm_adddma(endpoint_t proc_e, phys_bytes start, phys_bytes size);

View File

@ -368,7 +368,7 @@ static void mb_extract_image(multiboot_info_t mbi)
off_t text_offset, data_offset; off_t text_offset, data_offset;
/* Save memory map for kernel tasks */ /* Save memory map for kernel tasks */
r = read_header_elf((const char *)MULTIBOOT_KERNEL_ADDR, r = read_header_elf((char *) MULTIBOOT_KERNEL_ADDR,
4096, /* everything is there */ 4096, /* everything is there */
&text_vaddr, &text_paddr, &text_vaddr, &text_paddr,
&text_filebytes, &text_membytes, &text_filebytes, &text_membytes,
@ -401,7 +401,7 @@ static void mb_extract_image(multiboot_info_t mbi)
/* Load boot image services into memory and save memory map */ /* Load boot image services into memory and save memory map */
for (i = 0; module < &mb_module_info[mods_count]; ++module, ++i) { for (i = 0; module < &mb_module_info[mods_count]; ++module, ++i) {
r = read_header_elf((const char *)module->mod_start, r = read_header_elf((char *) module->mod_start,
module->mod_end - module->mod_start + 1, module->mod_end - module->mod_start + 1,
&text_vaddr, &text_paddr, &text_vaddr, &text_paddr,
&text_filebytes, &text_membytes, &text_filebytes, &text_membytes,

View File

@ -2,7 +2,7 @@
LIB= exec LIB= exec
INCS= libexec.h INCS= libexec.h
SRCS= exec_aout.c exec_elf.c SRCS= exec_aout.c exec_elf.c exec_general.c
.if (${NBSD_LIBC} != "no") .if (${NBSD_LIBC} != "no")
INCSDIR= /usr/include INCSDIR= /usr/include

View File

@ -2,13 +2,18 @@
#include <minix/type.h> #include <minix/type.h>
#include <minix/const.h> #include <minix/const.h>
#include <minix/com.h>
#include <minix/syslib.h>
#include <sys/param.h> #include <sys/param.h>
#include <sys/mman.h>
#include <assert.h> #include <assert.h>
#include <unistd.h> #include <unistd.h>
#include <errno.h> #include <errno.h>
#include <libexec.h> #include <libexec.h>
#include <string.h> #include <string.h>
#include <machine/elf.h> #include <machine/elf.h>
#include <machine/vmparam.h>
#include <machine/memory.h>
/* For verbose logging */ /* For verbose logging */
#define ELF_DEBUG 0 #define ELF_DEBUG 0
@ -18,9 +23,9 @@
#define SECTOR_SIZE 512 #define SECTOR_SIZE 512
static int check_header(const Elf_Ehdr *hdr); static int check_header(Elf_Ehdr *hdr);
static int elf_sane(const Elf_Ehdr *hdr) static int elf_sane(Elf_Ehdr *hdr)
{ {
if (check_header(hdr) != OK) { if (check_header(hdr) != OK) {
return 0; return 0;
@ -41,7 +46,7 @@ static int elf_sane(const Elf_Ehdr *hdr)
return 1; return 1;
} }
static int elf_ph_sane(const Elf_Phdr *phdr) static int elf_ph_sane(Elf_Phdr *phdr)
{ {
if (rounddown((uintptr_t)phdr, sizeof(Elf_Addr)) != (uintptr_t)phdr) { if (rounddown((uintptr_t)phdr, sizeof(Elf_Addr)) != (uintptr_t)phdr) {
return 0; return 0;
@ -49,17 +54,17 @@ static int elf_ph_sane(const Elf_Phdr *phdr)
return 1; return 1;
} }
static int elf_unpack(const char *exec_hdr, static int elf_unpack(char *exec_hdr,
int hdr_len, const Elf_Ehdr **hdr, const Elf_Phdr **phdr) int hdr_len, Elf_Ehdr **hdr, Elf_Phdr **phdr)
{ {
*hdr = (const Elf_Ehdr *)exec_hdr; *hdr = (Elf_Ehdr *) exec_hdr;
if(!elf_sane(*hdr)) { if(!elf_sane(*hdr)) {
#if ELF_DEBUG #if ELF_DEBUG
printf("elf_sane failed\n"); printf("elf_sane failed\n");
#endif #endif
return ENOEXEC; return ENOEXEC;
} }
*phdr = (const Elf_Phdr *)(exec_hdr + (*hdr)->e_phoff); *phdr = (Elf_Phdr *)(exec_hdr + (*hdr)->e_phoff);
if(!elf_ph_sane(*phdr)) { if(!elf_ph_sane(*phdr)) {
#if ELF_DEBUG #if ELF_DEBUG
printf("elf_ph_sane failed\n"); printf("elf_ph_sane failed\n");
@ -73,23 +78,23 @@ static int elf_unpack(const char *exec_hdr,
} }
int read_header_elf( int read_header_elf(
const char *exec_hdr, /* executable header */ char *exec_hdr, /* executable header */
int hdr_len, /* significant bytes in exec_hdr */ int hdr_len, /* significant bytes in exec_hdr */
vir_bytes *text_vaddr, /* text virtual address */ vir_bytes *text_vaddr, /* text virtual address */
phys_bytes *text_paddr, /* text physical address */ phys_bytes *text_paddr, /* text physical address */
vir_bytes *text_filebytes, /* text segment size (in the file) */ vir_bytes *text_filebytes, /* text segment size (in the file) */
vir_bytes *text_membytes, /* text segment size (in memory) */ vir_bytes *text_membytes, /* text segment size (in memory) */
vir_bytes *data_vaddr, /* data virtual address */ vir_bytes *data_vaddr, /* data virtual address */
phys_bytes *data_paddr, /* data physical address */ phys_bytes *data_paddr, /* data physical address */
vir_bytes *data_filebytes, /* data segment size (in the file) */ vir_bytes *data_filebytes, /* data segment size (in the file) */
vir_bytes *data_membytes, /* data segment size (in memory) */ vir_bytes *data_membytes, /* data segment size (in memory) */
vir_bytes *pc, /* program entry point (initial PC) */ vir_bytes *pc, /* program entry point (initial PC) */
off_t *text_offset, /* file offset to text segment */ off_t *text_offset, /* file offset to text segment */
off_t *data_offset /* file offset to data segment */ off_t *data_offset /* file offset to data segment */
) )
{ {
const Elf_Ehdr *hdr = NULL; Elf_Ehdr *hdr = NULL;
const Elf_Phdr *phdr = NULL; Elf_Phdr *phdr = NULL;
unsigned long seg_filebytes, seg_membytes; unsigned long seg_filebytes, seg_membytes;
int e, i = 0; int e, i = 0;
@ -101,9 +106,9 @@ int read_header_elf(
if((e=elf_unpack(exec_hdr, hdr_len, &hdr, &phdr)) != OK) { if((e=elf_unpack(exec_hdr, hdr_len, &hdr, &phdr)) != OK) {
#if ELF_DEBUG #if ELF_DEBUG
printf("elf_unpack failed\n"); printf("elf_unpack failed\n");
#endif #endif
return e; return e;
} }
#if ELF_DEBUG #if ELF_DEBUG
@ -120,30 +125,30 @@ int read_header_elf(
for (i = 0; i < hdr->e_phnum; i++) { for (i = 0; i < hdr->e_phnum; i++) {
switch (phdr[i].p_type) { switch (phdr[i].p_type) {
case PT_LOAD: case PT_LOAD:
if (phdr[i].p_memsz == 0) if (phdr[i].p_memsz == 0)
break; break;
seg_filebytes = phdr[i].p_filesz; seg_filebytes = phdr[i].p_filesz;
seg_membytes = round_page(phdr[i].p_memsz + phdr[i].p_vaddr - seg_membytes = round_page(phdr[i].p_memsz + phdr[i].p_vaddr -
trunc_page(phdr[i].p_vaddr)); trunc_page(phdr[i].p_vaddr));
if (hdr->e_entry >= phdr[i].p_vaddr && if (hdr->e_entry >= phdr[i].p_vaddr &&
hdr->e_entry < (phdr[i].p_vaddr + phdr[i].p_memsz)) { hdr->e_entry < (phdr[i].p_vaddr + phdr[i].p_memsz)) {
*text_vaddr = phdr[i].p_vaddr; *text_vaddr = phdr[i].p_vaddr;
*text_paddr = phdr[i].p_paddr; *text_paddr = phdr[i].p_paddr;
*text_filebytes = seg_filebytes; *text_filebytes = seg_filebytes;
*text_membytes = seg_membytes; *text_membytes = seg_membytes;
*pc = (vir_bytes)hdr->e_entry; *pc = (vir_bytes)hdr->e_entry;
*text_offset = phdr[i].p_offset; *text_offset = phdr[i].p_offset;
} else { } else {
*data_vaddr = phdr[i].p_vaddr; *data_vaddr = phdr[i].p_vaddr;
*data_paddr = phdr[i].p_paddr; *data_paddr = phdr[i].p_paddr;
*data_filebytes = seg_filebytes; *data_filebytes = seg_filebytes;
*data_membytes = seg_membytes; *data_membytes = seg_membytes;
*data_offset = phdr[i].p_offset; *data_offset = phdr[i].p_offset;
} }
break; break;
default: default:
break; break;
} }
} }
@ -169,7 +174,7 @@ int read_header_elf(
(ehdr).e_ident[EI_MAG2] == ELFMAG2 && \ (ehdr).e_ident[EI_MAG2] == ELFMAG2 && \
(ehdr).e_ident[EI_MAG3] == ELFMAG3) (ehdr).e_ident[EI_MAG3] == ELFMAG3)
static int check_header(const Elf_Ehdr *hdr) static int check_header(Elf_Ehdr *hdr)
{ {
if (!IS_ELF(*hdr) || if (!IS_ELF(*hdr) ||
hdr->e_ident[EI_DATA] != ELF_TARG_DATA || hdr->e_ident[EI_DATA] != ELF_TARG_DATA ||
@ -181,46 +186,16 @@ static int check_header(const Elf_Ehdr *hdr)
return OK; return OK;
} }
int elf_phdr(const char *exec_hdr, int hdr_len, vir_bytes *ret_phdr)
{
const Elf_Ehdr *hdr = NULL;
const Elf_Phdr *phdr = NULL;
int e, i, have_computed_phdr = 1;
if((e=elf_unpack(exec_hdr, hdr_len, &hdr, &phdr)) != OK) return e;
for (i = 0; i < hdr->e_phnum; i++) {
switch (phdr[i].p_type) {
case PT_LOAD:
/* compute phdr based on this heuristic, to be used
* if there is no PT_PHDR
*/
if(phdr[i].p_offset == 0) {
*ret_phdr = phdr[i].p_vaddr + hdr->e_phoff;
have_computed_phdr = 1;
}
break;
case PT_PHDR:
*ret_phdr = phdr[i].p_vaddr;
return OK;
default:
break;;
}
}
if(have_computed_phdr) return OK;
return ENOENT;
}
/* Return >0 if there is an ELF interpreter (i.e. it is a dynamically linked /* Return >0 if there is an ELF interpreter (i.e. it is a dynamically linked
* executable) and we could extract it successfully. * executable) and we could extract it successfully.
* Return 0 if there isn't one. * Return 0 if there isn't one.
* Return <0 on error. * Return <0 on error.
*/ */
int elf_has_interpreter(const char *exec_hdr, /* executable header */ int elf_has_interpreter(char *exec_hdr, /* executable header */
int hdr_len, char *interp, int maxsz) int hdr_len, char *interp, int maxsz)
{ {
const Elf_Ehdr *hdr = NULL; Elf_Ehdr *hdr = NULL;
const Elf_Phdr *phdr = NULL; Elf_Phdr *phdr = NULL;
int e, i; int e, i;
if((e=elf_unpack(exec_hdr, hdr_len, &hdr, &phdr)) != OK) return e; if((e=elf_unpack(exec_hdr, hdr_len, &hdr, &phdr)) != OK) return e;
@ -243,3 +218,95 @@ int elf_has_interpreter(const char *exec_hdr, /* executable header */
return 0; return 0;
} }
int libexec_load_elf(struct exec_info *execi)
{
int r;
Elf_Ehdr *hdr = NULL;
Elf_Phdr *phdr = NULL;
int e, i = 0;
int first = 1;
vir_bytes startv, stacklow;
assert(execi != NULL);
assert(execi->hdr != NULL);
if((e=elf_unpack(execi->hdr, execi->hdr_len, &hdr, &phdr)) != OK) {
printf("libexec_load_elf: elf_unpack failed\n");
return e;
}
/* this function can load the dynamic linker, but that
* shouldn't require an interpreter itself.
*/
i = elf_has_interpreter(execi->hdr, execi->hdr_len, NULL, 0);
if(i > 0) {
printf("libexec: cannot load dynamically linked executable\n");
return ENOEXEC;
}
/* Make VM forget about all existing memory in process. */
vm_procctl(execi->proc_e, VMPPARAM_CLEAR);
execi->stack_size = roundup(execi->stack_size, PAGE_SIZE);
execi->stack_high = VM_STACKTOP;
assert(!(VM_STACKTOP % PAGE_SIZE));
stacklow = execi->stack_high - execi->stack_size;
for (i = 0; i < hdr->e_phnum; i++) {
vir_bytes seg_membytes, page_offset, vaddr;
Elf_Phdr *ph = &phdr[i];
if (ph->p_type != PT_LOAD || ph->p_memsz == 0) continue;
#if 0
printf("index %d memsz 0x%lx vaddr 0x%lx\n", i, ph->p_memsz, ph->p_vaddr);
#endif
vaddr = ph->p_vaddr;
seg_membytes = ph->p_memsz;
page_offset = vaddr % PAGE_SIZE;
vaddr -= page_offset;
seg_membytes += page_offset;
seg_membytes = roundup(seg_membytes, PAGE_SIZE);
if(first || startv > vaddr) startv = vaddr;
first = 0;
#if 0
printf("libexec_load_elf: mmap 0x%lx bytes at 0x%lx\n",
seg_membytes, vaddr);
#endif
/* Tell VM to make us some memory */
if(minix_mmap_for(execi->proc_e, (void *) vaddr, seg_membytes,
PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_ANON|MAP_PREALLOC|MAP_FIXED, -1, 0) == MAP_FAILED) {
printf("libexec_load_elf: mmap of 0x%lx bytes failed\n", seg_membytes);
vm_procctl(execi->proc_e, VMPPARAM_CLEAR);
return ENOMEM;
}
/* Copy executable section into it */
if(execi->load(execi, ph->p_offset, ph->p_vaddr, ph->p_filesz) != OK) {
printf("libexec_load_elf: load callback failed\n");
vm_procctl(execi->proc_e, VMPPARAM_CLEAR);
return ENOMEM;
}
}
/* Make it a stack */
if(minix_mmap_for(execi->proc_e, (void *) stacklow, execi->stack_size,
PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_ANON|MAP_FIXED, -1, 0) == MAP_FAILED) {
printf("libexec_load_elf: mmap for stack failed\n");
vm_procctl(execi->proc_e, VMPPARAM_CLEAR);
return ENOMEM;
}
/* record entry point and lowest load vaddr for caller */
execi->pc = hdr->e_entry;
execi->load_base = startv;
if((r = libexec_pm_newexec(execi->proc_e, execi)) != OK) {
printf("libexec_load_elf: pm_newexec failed: %d\n", r);
}
return(r);
}

View File

@ -0,0 +1,57 @@
#define _SYSTEM 1
#include <minix/type.h>
#include <minix/const.h>
#include <sys/param.h>
#include <assert.h>
#include <unistd.h>
#include <errno.h>
#include <libexec.h>
#include <string.h>
#include <assert.h>
#include <minix/ipc.h>
#include <minix/com.h>
#include <minix/callnr.h>
#include <machine/elf.h>
void libexec_patch_ptr(char stack[ARG_MAX], vir_bytes base)
{
/* When doing an exec(name, argv, envp) call, the user builds up a stack
* image with arg and env pointers relative to the start of the stack. Now
* these pointers must be relocated, since the stack is not positioned at
* address 0 in the user's address space.
*/
char **ap, flag;
vir_bytes v;
flag = 0; /* counts number of 0-pointers seen */
ap = (char **) stack; /* points initially to 'nargs' */
ap++; /* now points to argv[0] */
while (flag < 2) {
if (ap >= (char **) &stack[ARG_MAX]) return; /* too bad */
if (*ap != NULL) {
v = (vir_bytes) *ap; /* v is relative pointer */
v += base; /* relocate it */
*ap = (char *) v; /* put it back */
} else {
flag++;
}
ap++;
}
}
int libexec_pm_newexec(endpoint_t proc_e, struct exec_info *e)
{
int r;
message m;
m.m_type = PM_NEWEXEC;
m.EXC_NM_PROC = proc_e;
m.EXC_NM_PTR = (char *)e;
if ((r = sendrec(PM_PROC_NR, &m)) != OK) return(r);
e->allow_setuid = !!(m.m1_i2 & EXC_NM_RF_ALLOW_SETUID);
return(m.m_type);
}

View File

@ -3,15 +3,49 @@
#include <sys/exec_elf.h> #include <sys/exec_elf.h>
/* ELF routines */ struct exec_info;
int read_header_elf(const char *exec_hdr, int hdr_len,
typedef int (*libexec_loadfunc_t)(struct exec_info *execi,
off_t offset, off_t vaddr, size_t len);
typedef int (*libexec_clearfunc_t)(struct exec_info *execi,
off_t vaddr, size_t len);
struct exec_info {
/* Filled in by libexec caller */
endpoint_t proc_e; /* Process endpoint */
char *hdr; /* Header or full image */
size_t hdr_len; /* Size of hdr */
vir_bytes frame_len; /* Stack size */
char progname[PROC_NAME_LEN]; /* Program name */
uid_t new_uid; /* Process UID after exec */
gid_t new_gid; /* Process GID after exec */
int allow_setuid; /* Allow set{u,g}id execution? */
libexec_loadfunc_t load; /* Load callback */
libexec_clearfunc_t clear; /* Clear callback */
void *opaque; /* Callback data */
vir_bytes stack_size; /* Desired stack size */
/* Filled in by libexec load function */
vir_bytes load_base; /* Where executable is loaded */
vir_bytes pc; /* Entry point of exec file */
vir_bytes stack_high; /* High stack addr */
};
int elf_has_interpreter(char *exec_hdr, int hdr_len, char *interp, int maxsz);
int elf_phdr(char *exec_hdr, int hdr_len, vir_bytes *phdr);
int read_header_elf(char *exec_hdr, int hdr_len,
vir_bytes *text_vaddr, phys_bytes *text_paddr, vir_bytes *text_vaddr, phys_bytes *text_paddr,
vir_bytes *text_filebytes, vir_bytes *text_membytes, vir_bytes *text_filebytes, vir_bytes *text_membytes,
vir_bytes *data_vaddr, phys_bytes *data_paddr, vir_bytes *data_vaddr, phys_bytes *data_paddr,
vir_bytes *data_filebytes, vir_bytes *data_membytes, vir_bytes *data_filebytes, vir_bytes *data_membytes,
vir_bytes *pc, off_t *text_offset, off_t *data_offset); vir_bytes *pc, off_t *text_offset, off_t *data_offset);
int elf_has_interpreter(const char *exec_hdr, int hdr_len, char *interp, int maxsz); void libexec_patch_ptr(char stack[ARG_MAX], vir_bytes base);
int elf_phdr(const char *exec_hdr, int hdr_len, vir_bytes *phdr); int libexec_pm_newexec(endpoint_t proc_e, struct exec_info *execi);
typedef int (*libexec_exec_loadfunc_t)(struct exec_info *execi);
int libexec_load_elf(struct exec_info *execi);
#endif /* !_LIBEXEC_H_ */ #endif /* !_LIBEXEC_H_ */

View File

@ -130,7 +130,7 @@ CPPFLAGS.${i}+= -I${LIBCSRCDIR}/include -I${LIBCSRCDIR}/locale
link.c _mcontext.c mknod.c mmap.c nanosleep.c open.c \ link.c _mcontext.c mknod.c mmap.c nanosleep.c open.c \
read.c sbrk.c select.c setuid.c sigprocmask.c stat.c \ read.c sbrk.c select.c setuid.c sigprocmask.c stat.c \
stime.c syscall.c _ucontext.c umask.c unlink.c waitpid.c \ stime.c syscall.c _ucontext.c umask.c unlink.c waitpid.c \
brksize.S _ipc.S _senda.S ucontext.S brksize.S _ipc.S _senda.S ucontext.S mmap.c
.PATH.c: ${LIBCSRCDIR}/sys-minix .PATH.c: ${LIBCSRCDIR}/sys-minix
.PATH.S: ${LIBCSRCDIR}/arch/${MACHINE}/sys-minix .PATH.S: ${LIBCSRCDIR}/arch/${MACHINE}/sys-minix
SRCS+= ${i} SRCS+= ${i}

View File

@ -118,7 +118,6 @@ SRCS= \
vbox.c \ vbox.c \
vm_brk.c \ vm_brk.c \
vm_dmacalls.c \ vm_dmacalls.c \
vm_exec_newmem.c \
vm_exit.c \ vm_exit.c \
vm_fork.c \ vm_fork.c \
vm_info.c \ vm_info.c \

View File

@ -1,26 +0,0 @@
#include "syslib.h"
#include <minix/vm.h>
/*===========================================================================*
* vm_exec_newmem *
*===========================================================================*/
int vm_exec_newmem(endpoint_t ep, struct exec_newmem *args,
int argssize, char **ret_stack_top, int *ret_flags)
{
message m;
int result;
m.VMEN_ENDPOINT = ep;
m.VMEN_ARGSPTR = (void *) args;
m.VMEN_ARGSSIZE = argssize;
result = _taskcall(VM_PROC_NR, VM_EXEC_NEWMEM, &m);
*ret_stack_top = m.VMEN_STACK_TOP;
*ret_flags = m.VMEN_FLAGS;
return result;
}

View File

@ -20,3 +20,4 @@ int vm_procctl(endpoint_t ep, int param)
result = _taskcall(VM_PROC_NR, VM_PROCCTL, &m); result = _taskcall(VM_PROC_NR, VM_PROCCTL, &m);
return(result); return(result);
} }

View File

@ -26,6 +26,7 @@
#include <a.out.h> #include <a.out.h>
#include <signal.h> #include <signal.h>
#include <string.h> #include <string.h>
#include <libexec.h>
#include <sys/ptrace.h> #include <sys/ptrace.h>
#include "mproc.h" #include "mproc.h"
#include "param.h" #include "param.h"
@ -46,7 +47,7 @@ int do_exec()
m.PM_PATH = m_in.exec_name; m.PM_PATH = m_in.exec_name;
m.PM_PATH_LEN = m_in.exec_len; m.PM_PATH_LEN = m_in.exec_len;
m.PM_FRAME = m_in.frame_ptr; m.PM_FRAME = m_in.frame_ptr;
m.PM_FRAME_LEN = m_in.frame_len; m.PM_FRAME_LEN = m_in.msg_frame_len;
m.PM_EXECFLAGS = m_in.PMEXEC_FLAGS; m.PM_EXECFLAGS = m_in.PMEXEC_FLAGS;
tell_vfs(mp, &m); tell_vfs(mp, &m);
@ -57,16 +58,15 @@ int do_exec()
/*===========================================================================* /*===========================================================================*
* do_exec_newmem * * do_newexec *
*===========================================================================*/ *===========================================================================*/
int do_exec_newmem() int do_newexec()
{ {
int proc_e, proc_n, allow_setuid; int proc_e, proc_n, allow_setuid;
char *ptr; char *ptr;
struct mproc *rmp; struct mproc *rmp;
struct exec_newmem args; struct exec_info args;
int r, flags; int r, flags;
char *stack_top;
if (who_e != VFS_PROC_NR && who_e != RS_PROC_NR) if (who_e != VFS_PROC_NR && who_e != RS_PROC_NR)
return EPERM; return EPERM;
@ -82,50 +82,46 @@ int do_exec_newmem()
if (r != OK) if (r != OK)
panic("do_exec_newmem: sys_datacopy failed: %d", r); panic("do_exec_newmem: sys_datacopy failed: %d", r);
if ((r = vm_exec_newmem(proc_e, &args, sizeof(args), &stack_top, allow_setuid = 0; /* Do not allow setuid execution */
&flags)) == OK) { rmp->mp_flags &= ~TAINTED; /* By default not tainted */
allow_setuid = 0; /* Do not allow setuid execution */
rmp->mp_flags &= ~TAINTED; /* By default not tainted */
if (rmp->mp_tracer == NO_TRACER) { if (rmp->mp_tracer == NO_TRACER) {
/* Okay, setuid execution is allowed */ /* Okay, setuid execution is allowed */
allow_setuid = 1; allow_setuid = 1;
}
if (allow_setuid && args.setugid) {
rmp->mp_effuid = args.new_uid;
rmp->mp_effgid = args.new_gid;
}
/* A process is considered 'tainted' when it's executing with
* setuid or setgid bit set, or when the real{u,g}id doesn't
* match the eff{u,g}id, respectively. */
if (allow_setuid && args.setugid) {
/* Program has setuid and/or setgid bits set */
rmp->mp_flags |= TAINTED;
} else if (rmp->mp_effuid != rmp->mp_realuid ||
rmp->mp_effgid != rmp->mp_realgid) {
rmp->mp_flags |= TAINTED;
}
/* System will save command line for debugging, ps(1) output, etc. */
strncpy(rmp->mp_name, args.progname, PROC_NAME_LEN-1);
rmp->mp_name[PROC_NAME_LEN-1] = '\0';
/* Save offset to initial argc (for procfs) */
rmp->mp_frame_addr = (vir_bytes) stack_top - args.args_bytes;
rmp->mp_frame_len = args.args_bytes;
/* Kill process if something goes wrong after this point. */
rmp->mp_flags |= PARTIAL_EXEC;
mp->mp_reply.reply_res2= (vir_bytes) stack_top;
mp->mp_reply.reply_res3= flags;
if (allow_setuid && args.setugid)
mp->mp_reply.reply_res3 |= EXC_NM_RF_ALLOW_SETUID;
} else {
printf("PM: newmem failed for %s\n", args.progname);
} }
if (allow_setuid && args.allow_setuid) {
rmp->mp_effuid = args.new_uid;
rmp->mp_effgid = args.new_gid;
}
/* A process is considered 'tainted' when it's executing with
* setuid or setgid bit set, or when the real{u,g}id doesn't
* match the eff{u,g}id, respectively. */
if (allow_setuid && args.allow_setuid) {
/* Program has setuid and/or setgid bits set */
rmp->mp_flags |= TAINTED;
} else if (rmp->mp_effuid != rmp->mp_realuid ||
rmp->mp_effgid != rmp->mp_realgid) {
rmp->mp_flags |= TAINTED;
}
/* System will save command line for debugging, ps(1) output, etc. */
strncpy(rmp->mp_name, args.progname, PROC_NAME_LEN-1);
rmp->mp_name[PROC_NAME_LEN-1] = '\0';
/* Save offset to initial argc (for procfs) */
rmp->mp_frame_addr = (vir_bytes) args.stack_high - args.frame_len;
rmp->mp_frame_len = args.frame_len;
/* Kill process if something goes wrong after this point. */
rmp->mp_flags |= PARTIAL_EXEC;
mp->mp_reply.reply_res2= (vir_bytes) rmp->mp_frame_addr;
mp->mp_reply.reply_res3= flags;
if (allow_setuid && args.allow_setuid)
mp->mp_reply.reply_res3 |= EXC_NM_RF_ALLOW_SETUID;
return r; return r;
} }

View File

@ -12,7 +12,7 @@
#define new_val m1_p1 #define new_val m1_p1
#define old_val m1_p2 #define old_val m1_p2
#define sig m6_i1 #define sig m6_i1
#define frame_len m1_i2 #define msg_frame_len m1_i2
#define frame_ptr m1_p2 #define frame_ptr m1_p2
#define status m1_i1 #define status m1_i1
#define usr_id m1_i1 #define usr_id m1_i1

View File

@ -18,7 +18,7 @@ int do_brk(void);
/* exec.c */ /* exec.c */
int do_exec(void); int do_exec(void);
int do_exec_newmem(void); int do_newexec(void);
int do_execrestart(void); int do_execrestart(void);
void exec_restart(struct mproc *rmp, int result, vir_bytes pc, vir_bytes sp); void exec_restart(struct mproc *rmp, int result, vir_bytes pc, vir_bytes sp);

View File

@ -111,7 +111,7 @@ int (*call_vec[])(void) = {
no_sys, /* 97 = unused */ no_sys, /* 97 = unused */
do_sprofile, /* 98 = sprofile */ do_sprofile, /* 98 = sprofile */
do_cprofile, /* 99 = cprofile */ do_cprofile, /* 99 = cprofile */
do_exec_newmem, /* 100 = exec_newmem */ do_newexec, /* 100 = newexec */
do_srv_fork, /* 101 = srv_fork */ do_srv_fork, /* 101 = srv_fork */
do_execrestart, /* 102 = exec_restart */ do_execrestart, /* 102 = exec_restart */
no_sys, /* 103 = unused */ no_sys, /* 103 = unused */

View File

@ -2,30 +2,19 @@
#include <a.out.h> #include <a.out.h>
#include <assert.h> #include <assert.h>
#include <libexec.h> #include <libexec.h>
#include "exec.h" #include <machine/vmparam.h>
#define BLOCK_SIZE 1024
static int do_exec(int proc_e, char *exec, size_t exec_len, char *progname, static int do_exec(int proc_e, char *exec, size_t exec_len, char *progname,
char *frame, int frame_len); char *frame, int frame_len);
static int exec_newmem(int proc_e, vir_bytes text_addr,
vir_bytes text_bytes, vir_bytes data_addr,
vir_bytes data_bytes, vir_bytes tot_bytes,
vir_bytes frame_len, int sep_id, int is_elf,
dev_t st_dev, ino_t st_ino, time_t ctime, char *progname,
int new_uid, int new_gid, vir_bytes *stack_topp,
int *load_textp, int *allow_setuidp);
static void patch_ptr(char stack[ARG_MAX], vir_bytes base);
static int exec_restart(int proc_e, int result, vir_bytes pc); static int exec_restart(int proc_e, int result, vir_bytes pc);
static int read_seg(struct exec_info *execi, off_t off, static int read_seg(struct exec_info *execi, off_t off,
int proc_e, int seg, vir_bytes seg_addr, phys_bytes seg_bytes); off_t seg_addr, size_t seg_bytes);
static int load_elf(struct exec_info *execi);
/* Array of loaders for different object formats */ /* Array of loaders for different object formats */
static struct exec_loaders { static struct exec_loaders {
int (*load_object)(struct exec_info *); libexec_exec_loadfunc_t load_object;
} const exec_loaders[] = { } const exec_loaders[] = {
{ load_elf }, { libexec_load_elf },
{ NULL } { NULL }
}; };
@ -128,12 +117,16 @@ static int do_exec(int proc_e, char *exec, size_t exec_len, char *progname,
struct exec_info execi; struct exec_info execi;
int i; int i;
memset(&execi, 0, sizeof(execi));
execi.stack_size = DEFAULT_STACK_LIMIT;
execi.proc_e = proc_e; execi.proc_e = proc_e;
execi.image = exec; execi.hdr = exec;
execi.image_len = exec_len; execi.hdr_len = exec_len;
strncpy(execi.progname, progname, PROC_NAME_LEN-1); strncpy(execi.progname, progname, PROC_NAME_LEN-1);
execi.progname[PROC_NAME_LEN-1] = '\0'; execi.progname[PROC_NAME_LEN-1] = '\0';
execi.frame_len = frame_len; execi.frame_len = frame_len;
execi.load = read_seg;
for(i = 0; exec_loaders[i].load_object != NULL; i++) { for(i = 0; exec_loaders[i].load_object != NULL; i++) {
r = (*exec_loaders[i].load_object)(&execi); r = (*exec_loaders[i].load_object)(&execi);
@ -148,14 +141,12 @@ static int do_exec(int proc_e, char *exec, size_t exec_len, char *progname,
} }
/* Patch up stack and copy it from RS to new core image. */ /* Patch up stack and copy it from RS to new core image. */
vsp = execi.stack_top; vsp = execi.stack_high;
vsp -= frame_len; vsp -= frame_len;
patch_ptr(frame, vsp); libexec_patch_ptr(frame, vsp);
r = sys_datacopy(SELF, (vir_bytes) frame, r = sys_datacopy(SELF, (vir_bytes) frame,
proc_e, (vir_bytes) vsp, (phys_bytes)frame_len); proc_e, (vir_bytes) vsp, (phys_bytes)frame_len);
if (r != OK) { if (r != OK) {
printf("RS: stack_top is 0x%lx; tried to copy to 0x%lx in %d\n",
execi.stack_top, vsp, proc_e);
printf("do_exec: copying out new stack failed: %d\n", r); printf("do_exec: copying out new stack failed: %d\n", r);
exec_restart(proc_e, r, execi.pc); exec_restart(proc_e, r, execi.pc);
return r; return r;
@ -164,149 +155,6 @@ static int do_exec(int proc_e, char *exec, size_t exec_len, char *progname,
return exec_restart(proc_e, OK, execi.pc); return exec_restart(proc_e, OK, execi.pc);
} }
static int load_elf(struct exec_info *execi)
{
int r;
int proc_e;
phys_bytes tot_bytes; /* total space for program, including gap */
vir_bytes text_vaddr, text_paddr, text_filebytes, text_membytes;
vir_bytes data_vaddr, data_paddr, data_filebytes, data_membytes;
off_t text_offset, data_offset;
int sep_id, is_elf, load_text, allow_setuid;
uid_t new_uid;
gid_t new_gid;
assert(execi != NULL);
assert(execi->image != NULL);
proc_e = execi->proc_e;
/* Read the file header and extract the segment sizes. */
r = read_header_elf(execi->image, execi->image_len, &text_vaddr, &text_paddr,
&text_filebytes, &text_membytes,
&data_vaddr, &data_paddr,
&data_filebytes, &data_membytes,
&execi->pc, &text_offset, &data_offset);
if (r != OK) {
return(r);
}
if(elf_has_interpreter(execi->image, execi->image_len, NULL, 0)) {
printf("RS: can't execute dynamically linked executables\n");
return ENOEXEC;
}
new_uid= getuid();
new_gid= getgid();
allow_setuid = 0;
sep_id = 0;
is_elf = 1;
tot_bytes = 0; /* Use default stack size */
r = exec_newmem(proc_e,
trunc_page(text_vaddr), text_membytes,
trunc_page(data_vaddr), data_membytes,
tot_bytes, execi->frame_len, sep_id, is_elf,
0 /*dev*/, proc_e /*inum*/, 0 /*ctime*/,
execi->progname, new_uid, new_gid,
&execi->stack_top, &load_text, &allow_setuid);
if (r != OK)
{
printf("RS: load_elf: exec_newmem failed: %d\n", r);
exec_restart(proc_e, r, execi->pc);
return r;
}
/* Read in text and data segments. */
if (load_text) {
r = read_seg(execi, text_offset, proc_e, T, text_vaddr, text_filebytes);
if (r != OK)
{
printf("RS: load_elf: read_seg failed: %d\n", r);
exec_restart(proc_e, r, execi->pc);
return r;
}
}
else
printf("RS: load_elf: not loading text segment\n");
r = read_seg(execi, data_offset, proc_e, D, data_vaddr, data_filebytes);
if (r != OK)
{
printf("RS: load_elf: read_seg failed: %d\n", r);
exec_restart(proc_e, r, execi->pc);
return r;
}
return(OK);
}
/*===========================================================================*
* exec_newmem *
*===========================================================================*/
static int exec_newmem(
int proc_e,
vir_bytes text_addr,
vir_bytes text_bytes,
vir_bytes data_addr,
vir_bytes data_bytes,
vir_bytes tot_bytes,
vir_bytes frame_len,
int sep_id,
int is_elf,
dev_t st_dev,
ino_t st_ino,
time_t ctime,
char *progname,
int new_uid,
int new_gid,
vir_bytes *stack_topp,
int *load_textp,
int *allow_setuidp
)
{
int r;
struct exec_newmem e;
message m;
e.text_addr = text_addr;
e.text_bytes= text_bytes;
e.data_addr = data_addr;
e.data_bytes= data_bytes;
e.tot_bytes= tot_bytes;
e.args_bytes= frame_len;
e.sep_id= sep_id;
e.is_elf= is_elf;
e.st_dev= st_dev;
e.st_ino= st_ino;
e.enst_ctime= ctime;
e.new_uid= new_uid;
e.new_gid= new_gid;
e.setugid= *allow_setuidp;
strncpy(e.progname, progname, sizeof(e.progname)-1);
e.progname[sizeof(e.progname)-1]= '\0';
m.m_type= EXEC_NEWMEM;
m.EXC_NM_PROC= proc_e;
m.EXC_NM_PTR= (char *)&e;
r= sendrec(PM_PROC_NR, &m);
if (r != OK)
return r;
#if 0
printf("exec_newmem: r = %d, m_type = %d\n", r, m.m_type);
#endif
*stack_topp= m.m1_i1;
*load_textp= !!(m.m1_i2 & EXC_NM_RF_LOAD_TEXT);
*allow_setuidp= !!(m.m1_i2 & EXC_NM_RF_ALLOW_SETUID);
#if 0
printf("RS: exec_newmem: stack_top = 0x%x\n", *stack_topp);
printf("RS: exec_newmem: load_text = %d\n", *load_textp);
#endif
return m.m_type;
}
/*===========================================================================* /*===========================================================================*
* exec_restart * * exec_restart *
*===========================================================================*/ *===========================================================================*/
@ -326,48 +174,13 @@ static int exec_restart(int proc_e, int result, vir_bytes pc)
} }
/*===========================================================================* /*===========================================================================*
* patch_ptr * * read_seg *
*===========================================================================*/
static void patch_ptr(
char stack[ARG_MAX], /* pointer to stack image within PM */
vir_bytes base /* virtual address of stack base inside user */
)
{
/* When doing an exec(name, argv, envp) call, the user builds up a stack
* image with arg and env pointers relative to the start of the stack. Now
* these pointers must be relocated, since the stack is not positioned at
* address 0 in the user's address space.
*/
char **ap, flag;
vir_bytes v;
flag = 0; /* counts number of 0-pointers seen */
ap = (char **) stack; /* points initially to 'nargs' */
ap++; /* now points to argv[0] */
while (flag < 2) {
if (ap >= (char **) &stack[ARG_MAX]) return; /* too bad */
if (*ap != NULL) {
v = (vir_bytes) *ap; /* v is relative pointer */
v += base; /* relocate it */
*ap = (char *) v; /* put it back */
} else {
flag++;
}
ap++;
}
}
/*===========================================================================*
* read_seg *
*===========================================================================*/ *===========================================================================*/
static int read_seg( static int read_seg(
struct exec_info *execi, /* various data needed for exec */ struct exec_info *execi, /* various data needed for exec */
off_t off, /* offset in file */ off_t off, /* offset in file */
int proc_e, /* process number (endpoint) */ off_t seg_addr, /* address to load segment */
int seg, /* T, D, or S */ size_t seg_bytes /* how much is to be transferred? */
vir_bytes seg_addr, /* address to load segment */
phys_bytes seg_bytes /* how much is to be transferred? */
) )
{ {
/* /*
@ -378,9 +191,11 @@ phys_bytes seg_bytes /* how much is to be transferred? */
int r; int r;
assert((seg == T)||(seg == D)); if (off+seg_bytes > execi->hdr_len) return ENOEXEC;
if((r= sys_vircopy(SELF, D, ((vir_bytes)execi->hdr)+off,
if (off+seg_bytes > execi->image_len) return ENOEXEC; execi->proc_e, D, seg_addr, seg_bytes)) != OK) {
r= sys_vircopy(SELF, D, ((vir_bytes)execi->image)+off, proc_e, seg, seg_addr, seg_bytes); printf("RS: exec read_seg: copy 0x%lx bytes into %d at 0x%lx failed: %d\n",
seg_bytes, execi->proc_e, seg_addr, r);
}
return r; return r;
} }

View File

@ -1,14 +0,0 @@
#ifndef _RS_EXEC_H_
#define _RS_EXEC_H_ 1
struct exec_info {
int proc_e; /* Process endpoint */
char *image; /* Executable image */
size_t image_len; /* Size of executable image */
vir_bytes pc; /* Entry point of exec file */
vir_bytes stack_top; /* Top of the stack */
vir_bytes frame_len; /* Stack size */
char progname[PROC_NAME_LEN]; /* Program name */
};
#endif /* !_RS_EXEC_H_ */

View File

@ -34,45 +34,48 @@
#include <machine/vmparam.h> #include <machine/vmparam.h>
#include <assert.h> #include <assert.h>
#include <fcntl.h> #include <fcntl.h>
#include "exec.h"
#define _KERNEL /* for ELF_AUX_ENTRIES */ #define _KERNEL /* for ELF_AUX_ENTRIES */
#include <libexec.h> #include <libexec.h>
/* fields only used by elf and in VFS */
struct vfs_exec_info {
struct exec_info args; /* libexec exec args */
struct vnode *vp; /* Exec file's vnode */
struct vmnt *vmp; /* Exec file's vmnt */
struct stat sb; /* Exec file's stat structure */
int userflags; /* exec() flags from userland */
int is_dyn; /* Dynamically linked executable */
int elf_main_fd; /* Dyn: FD of main program execuatble */
char execname[PATH_MAX]; /* Full executable invocation */
};
static void lock_exec(void); static void lock_exec(void);
static void unlock_exec(void); static void unlock_exec(void);
static int exec_newmem(int proc_e, vir_bytes text_addr, vir_bytes text_bytes,
vir_bytes data_addr, vir_bytes data_bytes, vir_bytes tot_bytes,
vir_bytes frame_len, int sep_id, int is_elf, dev_t st_dev,
ino_t st_ino, time_t ctime, char *progname, int new_uid, int new_gid,
vir_bytes *stack_topp, int *load_textp, int *setugidp);
static int patch_stack(struct vnode *vp, char stack[ARG_MAX], static int patch_stack(struct vnode *vp, char stack[ARG_MAX],
size_t *stk_bytes, char path[PATH_MAX]); size_t *stk_bytes, char path[PATH_MAX]);
static int is_script(struct exec_info *execi); static int is_script(struct vfs_exec_info *execi);
static int insert_arg(char stack[ARG_MAX], size_t *stk_bytes, char *arg, static int insert_arg(char stack[ARG_MAX], size_t *stk_bytes, char *arg,
int replace); int replace);
static void patch_ptr(char stack[ARG_MAX], vir_bytes base);
static void clo_exec(struct fproc *rfp); static void clo_exec(struct fproc *rfp);
static int read_seg(struct vnode *vp, off_t off, int proc_e, int seg, static int stack_prepare_elf(struct vfs_exec_info *execi,
vir_bytes seg_addr, phys_bytes seg_bytes);
static int load_elf(struct exec_info *execi);
static int stack_prepare_elf(struct exec_info *execi,
char *curstack, size_t *frame_len, vir_bytes *vsp, int *extrabase); char *curstack, size_t *frame_len, vir_bytes *vsp, int *extrabase);
static int map_header(struct exec_info *execi); static int map_header(struct vfs_exec_info *execi);
static int read_seg(struct exec_info *execi, off_t off, off_t seg_addr, size_t seg_bytes);
#define PTRSIZE sizeof(char *) /* Size of pointers in argv[] and envp[]. */ #define PTRSIZE sizeof(char *) /* Size of pointers in argv[] and envp[]. */
/* Array of loaders for different object file formats */ /* Array of loaders for different object file formats */
typedef int (*exechook_t)(struct exec_info *execpackage); typedef int (*exechook_t)(struct vfs_exec_info *execpackage);
typedef int (*stackhook_t)(struct exec_info *execi, char *curstack, typedef int (*stackhook_t)(struct vfs_exec_info *execi, char *curstack,
size_t *frame_len, vir_bytes *, int *extrabase); size_t *frame_len, vir_bytes *, int *extrabase);
struct exec_loaders { struct exec_loaders {
exechook_t load_object; /* load executable into memory */ libexec_exec_loadfunc_t load_object; /* load executable into memory */
stackhook_t setup_stack; /* prepare stack before argc and argv push */ stackhook_t setup_stack; /* prepare stack before argc and argv push */
}; };
static const struct exec_loaders exec_loaders[] = { static const struct exec_loaders exec_loaders[] = {
{ load_elf, stack_prepare_elf }, { libexec_load_elf, stack_prepare_elf },
{ NULL, NULL } { NULL, NULL }
}; };
@ -110,8 +113,8 @@ static void unlock_exec(void)
/*===========================================================================* /*===========================================================================*
* get_read_vp * * get_read_vp *
*===========================================================================*/ *===========================================================================*/
static int get_read_vp(struct exec_info *execi, char *fullpath, static int get_read_vp(struct vfs_exec_info *execi,
int copyprogname, int sugid, struct lookup *resolve, struct fproc *fp) char *fullpath, int copyprogname, int sugid, struct lookup *resolve, struct fproc *fp)
{ {
/* Make the executable that we want to exec() into the binary pointed /* Make the executable that we want to exec() into the binary pointed
* to by 'fullpath.' This function fills in necessary details in the execi * to by 'fullpath.' This function fills in necessary details in the execi
@ -137,8 +140,8 @@ static int get_read_vp(struct exec_info *execi, char *fullpath,
char *cp = strrchr(fullpath, '/'); char *cp = strrchr(fullpath, '/');
if(cp) cp++; if(cp) cp++;
else cp = fullpath; else cp = fullpath;
strncpy(execi->progname, cp, sizeof(execi->progname)-1); strncpy(execi->args.progname, cp, sizeof(execi->args.progname)-1);
execi->progname[sizeof(execi->progname)-1] = '\0'; execi->args.progname[sizeof(execi->args.progname)-1] = '\0';
} }
/* Open executable */ /* Open executable */
@ -161,12 +164,12 @@ static int get_read_vp(struct exec_info *execi, char *fullpath,
if (sugid) { if (sugid) {
/* Deal with setuid/setgid executables */ /* Deal with setuid/setgid executables */
if (execi->vp->v_mode & I_SET_UID_BIT) { if (execi->vp->v_mode & I_SET_UID_BIT) {
execi->new_uid = execi->vp->v_uid; execi->args.new_uid = execi->vp->v_uid;
execi->setugid = 1; execi->args.allow_setuid = 1;
} }
if (execi->vp->v_mode & I_SET_GID_BIT) { if (execi->vp->v_mode & I_SET_GID_BIT) {
execi->new_gid = execi->vp->v_gid; execi->args.new_gid = execi->vp->v_gid;
execi->setugid = 1; execi->args.allow_setuid = 1;
} }
} }
@ -198,7 +201,7 @@ int pm_exec(endpoint_t proc_e, vir_bytes path, size_t path_len,
struct fproc *rfp; struct fproc *rfp;
int extrabase = 0; int extrabase = 0;
static char mbuf[ARG_MAX]; /* buffer for stack and zeroes */ static char mbuf[ARG_MAX]; /* buffer for stack and zeroes */
struct exec_info execi; struct vfs_exec_info execi;
int i; int i;
static char fullpath[PATH_MAX], static char fullpath[PATH_MAX],
elf_interpreter[PATH_MAX], elf_interpreter[PATH_MAX],
@ -213,6 +216,7 @@ int pm_exec(endpoint_t proc_e, vir_bytes path, size_t path_len,
/* passed from exec() libc code */ /* passed from exec() libc code */
execi.userflags = user_exec_flags; execi.userflags = user_exec_flags;
execi.args.stack_size = DEFAULT_STACK_LIMIT;
okendpt(proc_e, &slot); okendpt(proc_e, &slot);
rfp = fp = &fproc[slot]; rfp = fp = &fproc[slot];
@ -233,8 +237,8 @@ int pm_exec(endpoint_t proc_e, vir_bytes path, size_t path_len,
} }
/* The default is to keep the original user and group IDs */ /* The default is to keep the original user and group IDs */
execi.new_uid = rfp->fp_effuid; execi.args.new_uid = rfp->fp_effuid;
execi.new_gid = rfp->fp_effgid; execi.args.new_gid = rfp->fp_effgid;
/* Get the exec file name. */ /* Get the exec file name. */
FAILCHECK(fetch_name(path, path_len, fullpath)); FAILCHECK(fetch_name(path, path_len, fullpath));
@ -267,7 +271,7 @@ int pm_exec(endpoint_t proc_e, vir_bytes path, size_t path_len,
* executable instead. But open the current executable in an * executable instead. But open the current executable in an
* fd for the current process. * fd for the current process.
*/ */
if(elf_has_interpreter(execi.hdr, execi.hdr_len, if(elf_has_interpreter(execi.args.hdr, execi.args.hdr_len,
elf_interpreter, sizeof(elf_interpreter))) { elf_interpreter, sizeof(elf_interpreter))) {
/* Switch the executable vnode to the interpreter */ /* Switch the executable vnode to the interpreter */
execi.is_dyn = 1; execi.is_dyn = 1;
@ -292,11 +296,14 @@ int pm_exec(endpoint_t proc_e, vir_bytes path, size_t path_len,
Get_read_vp(execi, fullpath, 0, 0, &resolve, fp); Get_read_vp(execi, fullpath, 0, 0, &resolve, fp);
} }
execi.proc_e = proc_e; execi.args.opaque = &execi;
execi.frame_len = frame_len; execi.args.load = &read_seg;
execi.args.clear = NULL;
execi.args.proc_e = proc_e;
execi.args.frame_len = frame_len;
for (i = 0; exec_loaders[i].load_object != NULL; i++) { for (i = 0; exec_loaders[i].load_object != NULL; i++) {
r = (*exec_loaders[i].load_object)(&execi); r = (*exec_loaders[i].load_object)(&execi.args);
/* Loaded successfully, so no need to try other loaders */ /* Loaded successfully, so no need to try other loaders */
if (r == OK) { makestack = exec_loaders[i].setup_stack; break; } if (r == OK) { makestack = exec_loaders[i].setup_stack; break; }
} }
@ -304,14 +311,14 @@ int pm_exec(endpoint_t proc_e, vir_bytes path, size_t path_len,
FAILCHECK(r); FAILCHECK(r);
/* Save off PC */ /* Save off PC */
*pc = execi.pc; *pc = execi.args.pc;
/* call a stack-setup function if this executable type wants it */ /* call a stack-setup function if this executable type wants it */
vsp = execi.stack_top - frame_len; vsp = execi.args.stack_high - frame_len;
if(makestack) FAILCHECK(makestack(&execi, mbuf, &frame_len, &vsp, &extrabase)); if(makestack) FAILCHECK(makestack(&execi, mbuf, &frame_len, &vsp, &extrabase));
/* Patch up stack and copy it from VFS to new core image. */ /* Patch up stack and copy it from VFS to new core image. */
patch_ptr(mbuf, vsp + extrabase); libexec_patch_ptr(mbuf, vsp + extrabase);
FAILCHECK(sys_datacopy(SELF, (vir_bytes) mbuf, proc_e, (vir_bytes) vsp, FAILCHECK(sys_datacopy(SELF, (vir_bytes) mbuf, proc_e, (vir_bytes) vsp,
(phys_bytes)frame_len)); (phys_bytes)frame_len));
@ -320,15 +327,15 @@ int pm_exec(endpoint_t proc_e, vir_bytes path, size_t path_len,
clo_exec(rfp); clo_exec(rfp);
if (execi.setugid) { if (execi.args.allow_setuid) {
/* If after loading the image we're still allowed to run with /* If after loading the image we're still allowed to run with
* setuid or setgid, change credentials now */ * setuid or setgid, change credentials now */
rfp->fp_effuid = execi.new_uid; rfp->fp_effuid = execi.args.new_uid;
rfp->fp_effgid = execi.new_gid; rfp->fp_effgid = execi.args.new_gid;
} }
/* Remember the new name of the process */ /* Remember the new name of the process */
strcpy(rfp->fp_name, execi.progname); strcpy(rfp->fp_name, execi.args.progname);
pm_execfinal: pm_execfinal:
if (execi.vp != NULL) { if (execi.vp != NULL) {
@ -339,7 +346,7 @@ pm_execfinal:
return(r); return(r);
} }
static int stack_prepare_elf(struct exec_info *execi, char *frame, size_t *framelen, static int stack_prepare_elf(struct vfs_exec_info *execi, char *frame, size_t *framelen,
vir_bytes *newsp, int *extrabase) vir_bytes *newsp, int *extrabase)
{ {
AuxInfo *a, *term; AuxInfo *a, *term;
@ -351,8 +358,8 @@ static int stack_prepare_elf(struct exec_info *execi, char *frame, size_t *frame
if(!execi->is_dyn) if(!execi->is_dyn)
return OK; return OK;
assert(execi->hdr_len >= sizeof(*elf_header)); assert(execi->args.hdr_len >= sizeof(*elf_header));
elf_header = (Elf_Ehdr *) execi->hdr; elf_header = (Elf_Ehdr *) execi->args.hdr;
/* exec() promises stack space. Now find it. */ /* exec() promises stack space. Now find it. */
mysp++; /* skip argc */ mysp++; /* skip argc */
@ -399,12 +406,11 @@ static int stack_prepare_elf(struct exec_info *execi, char *frame, size_t *frame
#define AUXINFO(type, value) \ #define AUXINFO(type, value) \
{ assert((char *) a < (char *) mysp_end); a->a_type = type; a->a_v = value; a++; } { assert((char *) a < (char *) mysp_end); a->a_type = type; a->a_v = value; a++; }
#if 0 #if 0
AUXINFO(AT_PHDR, execi->elf_phdr);
AUXINFO(AT_PHENT, elf_header->e_phentsize); AUXINFO(AT_PHENT, elf_header->e_phentsize);
AUXINFO(AT_PHNUM, elf_header->e_phnum); AUXINFO(AT_PHNUM, elf_header->e_phnum);
#endif #endif
AUXINFO(AT_BASE, execi->elf_base); AUXINFO(AT_BASE, execi->args.load_base);
AUXINFO(AT_ENTRY, execi->pc); AUXINFO(AT_ENTRY, execi->args.pc);
AUXINFO(AT_PAGESZ, PAGE_SIZE); AUXINFO(AT_PAGESZ, PAGE_SIZE);
AUXINFO(AT_EXECFD, execi->elf_main_fd); AUXINFO(AT_EXECFD, execi->elf_main_fd);
@ -439,150 +445,16 @@ static int stack_prepare_elf(struct exec_info *execi, char *frame, size_t *frame
return OK; return OK;
} }
/*===========================================================================*
* load_elf *
*===========================================================================*/
static int load_elf(struct exec_info *execi)
{
int r;
struct vnode *vp;
int proc_e;
phys_bytes tot_bytes; /* total space for program, including gap */
vir_bytes text_vaddr, text_paddr, text_filebytes, text_membytes;
vir_bytes data_vaddr, data_paddr, data_filebytes, data_membytes;
off_t text_offset, data_offset;
int sep_id, is_elf, i;
vir_bytes text_base, data_base;
assert(execi != NULL);
assert(execi->hdr != NULL);
assert(execi->vp != NULL);
proc_e = execi->proc_e;
vp = execi->vp;
/* this function can load the dynamic linker, but that
* shouldn't require an interpreter itself.
*/
i = elf_has_interpreter(execi->hdr, execi->hdr_len, NULL, 0);
if(i > 0) {
printf("VFS: cannot load dynamically linked executable\n");
return ENOEXEC;
}
/* Read the file header and extract the segment sizes. */
r = read_header_elf(execi->hdr, execi->hdr_len, &text_vaddr, &text_paddr,
&text_filebytes, &text_membytes,
&data_vaddr, &data_paddr,
&data_filebytes, &data_membytes,
&execi->pc, &text_offset, &data_offset);
if (r != OK) {
return(r);
}
if(elf_phdr(execi->hdr, execi->hdr_len, &execi->elf_phdr) == OK)
if(execi->elf_phdr == 0) /* 0 should indicate: not known */
printf("VFS: warning: unexpected zero elf_phdr\n");
sep_id = 0;
is_elf = 1;
tot_bytes = 0; /* Use default stack size */
text_base = trunc_page(text_vaddr);
data_base = trunc_page(data_vaddr);
execi->elf_base = MIN(text_base, data_base);
r = exec_newmem(proc_e,
text_base, text_membytes,
data_base, data_membytes,
tot_bytes, execi->frame_len, sep_id, is_elf,
vp->v_dev, vp->v_inode_nr, execi->sb.st_ctime,
execi->progname, execi->new_uid, execi->new_gid,
&execi->stack_top, &execi->load_text, &execi->setugid);
if (r != OK) {
printf("VFS: load_elf: exec_newmem failed: %d\n", r);
return(r);
}
/* Read in text and data segments. */
if (execi->load_text)
r = read_seg(vp, text_offset, proc_e, T, text_vaddr, text_filebytes);
if (r == OK)
r = read_seg(vp, data_offset, proc_e, D, data_vaddr, data_filebytes);
return(r);
}
/*===========================================================================*
* exec_newmem *
*===========================================================================*/
static int exec_newmem(
int proc_e,
vir_bytes text_addr,
vir_bytes text_bytes,
vir_bytes data_addr,
vir_bytes data_bytes,
vir_bytes tot_bytes,
vir_bytes frame_len,
int sep_id,
int is_elf,
dev_t st_dev,
ino_t st_ino,
time_t ctime,
char *progname,
int new_uid,
int new_gid,
vir_bytes *stack_topp,
int *load_textp,
int *setugidp
)
{
/* Allocate a new memory map for a process that tries to exec */
int r;
struct exec_newmem e;
message m;
assert(setugidp != NULL);
e.text_addr = text_addr;
e.text_bytes = text_bytes;
e.data_addr = data_addr;
e.data_bytes = data_bytes;
e.tot_bytes = tot_bytes;
e.args_bytes = frame_len;
e.sep_id = sep_id;
e.is_elf = is_elf;
e.st_dev = st_dev;
e.st_ino = st_ino;
e.enst_ctime = ctime;
e.new_uid = new_uid;
e.new_gid = new_gid;
e.setugid = *setugidp;
strncpy(e.progname, progname, sizeof(e.progname)-1);
e.progname[sizeof(e.progname)-1] = '\0';
m.m_type = EXEC_NEWMEM;
m.EXC_NM_PROC = proc_e;
m.EXC_NM_PTR = (char *)&e;
if ((r = sendrec(PM_PROC_NR, &m)) != OK) return(r);
*stack_topp = m.m1_i1;
*load_textp = !!(m.m1_i2 & EXC_NM_RF_LOAD_TEXT);
*setugidp = !!(m.m1_i2 & EXC_NM_RF_ALLOW_SETUID);
return(m.m_type);
}
/*===========================================================================* /*===========================================================================*
* is_script * * is_script *
*===========================================================================*/ *===========================================================================*/
static int is_script(struct exec_info *execi) static int is_script(struct vfs_exec_info *execi)
{ {
/* Is Interpreted script? */ /* Is Interpreted script? */
assert(execi->hdr != NULL); assert(execi->args.hdr != NULL);
return(execi->hdr[0] == '#' && execi->hdr[1] == '!' && execi->hdr_len >= 2); return(execi->args.hdr[0] == '#' && execi->args.hdr[1] == '!'
&& execi->args.hdr_len >= 2);
} }
/*===========================================================================* /*===========================================================================*
@ -713,56 +585,15 @@ int replace
((char **) stack)[0]++; /* nargs++; */ ((char **) stack)[0]++; /* nargs++; */
} }
/* Now patch up argv[] and envp[] by offset. */ /* Now patch up argv[] and envp[] by offset. */
patch_ptr(stack, (vir_bytes) offset); libexec_patch_ptr(stack, (vir_bytes) offset);
((char **) stack)[1] = (char *) a0; /* set argv[0] correctly */ ((char **) stack)[1] = (char *) a0; /* set argv[0] correctly */
return(TRUE); return(TRUE);
} }
/*===========================================================================*
* patch_ptr *
*===========================================================================*/
static void patch_ptr(
char stack[ARG_MAX], /* pointer to stack image within PM */
vir_bytes base /* virtual address of stack base inside user */
)
{
/* When doing an exec(name, argv, envp) call, the user builds up a stack
* image with arg and env pointers relative to the start of the stack. Now
* these pointers must be relocated, since the stack is not positioned at
* address 0 in the user's address space.
*/
char **ap, flag;
vir_bytes v;
flag = 0; /* counts number of 0-pointers seen */
ap = (char **) stack; /* points initially to 'nargs' */
ap++; /* now points to argv[0] */
while (flag < 2) {
if (ap >= (char **) &stack[ARG_MAX]) return; /* too bad */
if (*ap != NULL) {
v = (vir_bytes) *ap; /* v is relative pointer */
v += base; /* relocate it */
*ap = (char *) v; /* put it back */
} else {
flag++;
}
ap++;
}
}
/*===========================================================================* /*===========================================================================*
* read_seg * * read_seg *
*===========================================================================*/ *===========================================================================*/
static int read_seg( static int read_seg(struct exec_info *execi, off_t off, off_t seg_addr, size_t seg_bytes)
struct vnode *vp, /* inode descriptor to read from */
off_t off, /* offset in file */
int proc_e, /* process number (endpoint) */
int seg, /* T, D, or S */
vir_bytes seg_addr, /* address to load segment */
phys_bytes seg_bytes /* how much is to be transferred? */
)
{ {
/* /*
* The byte count on read is usually smaller than the segment count, because * The byte count on read is usually smaller than the segment count, because
@ -770,51 +601,16 @@ phys_bytes seg_bytes /* how much is to be transferred? */
* partially initialized. * partially initialized.
*/ */
int r; int r;
unsigned n, o;
u64_t new_pos; u64_t new_pos;
unsigned int cum_io; unsigned int cum_io;
static char buf[128 * 1024]; struct vnode *vp = ((struct vfs_exec_info *) execi->opaque)->vp;
assert((seg == T)||(seg == D));
/* Make sure that the file is big enough */ /* Make sure that the file is big enough */
if (off + seg_bytes > LONG_MAX) return(EIO); if (off + seg_bytes > LONG_MAX) return(EIO);
if ((unsigned long) vp->v_size < off+seg_bytes) return(EIO); if ((unsigned long) vp->v_size < off+seg_bytes) return(EIO);
if (seg == T) {
/* We have to use a copy loop until safecopies support segments */
o = 0;
while (o < seg_bytes) {
n = seg_bytes - o;
if (n > sizeof(buf))
n = sizeof(buf);
if ((r = req_readwrite(vp->v_fs_e,vp->v_inode_nr,cvul64(off+o),
READING, VFS_PROC_NR, buf,
n, &new_pos, &cum_io)) != OK) {
printf("VFS: read_seg: req_readwrite failed (text)\n");
return(r);
}
if (cum_io != n) {
printf(
"VFSread_seg segment has not been read properly by exec() \n");
return(EIO);
}
if ((r = sys_vircopy(VFS_PROC_NR, D, (vir_bytes)buf, proc_e,
seg, seg_addr + o, n)) != OK) {
printf("VFS: read_seg: copy failed (text)\n");
return(r);
}
o += n;
}
return(OK);
} else if (seg == D) {
if ((r = req_readwrite(vp->v_fs_e, vp->v_inode_nr, cvul64(off), READING, if ((r = req_readwrite(vp->v_fs_e, vp->v_inode_nr, cvul64(off), READING,
proc_e, (char*)seg_addr, seg_bytes, execi->proc_e, (char*)seg_addr, seg_bytes,
&new_pos, &cum_io)) != OK) { &new_pos, &cum_io)) != OK) {
printf("VFS: read_seg: req_readwrite failed (data)\n"); printf("VFS: read_seg: req_readwrite failed (data)\n");
return(r); return(r);
@ -824,9 +620,6 @@ phys_bytes seg_bytes /* how much is to be transferred? */
printf("VFS: read_seg segment has not been read properly\n"); printf("VFS: read_seg segment has not been read properly\n");
return(r); return(r);
}
return(OK);
} }
@ -848,7 +641,7 @@ static void clo_exec(struct fproc *rfp)
/*===========================================================================* /*===========================================================================*
* map_header * * map_header *
*===========================================================================*/ *===========================================================================*/
static int map_header(struct exec_info *execi) static int map_header(struct vfs_exec_info *execi)
{ {
int r; int r;
u64_t new_pos; u64_t new_pos;
@ -859,12 +652,12 @@ static int map_header(struct exec_info *execi)
pos = 0; /* Read from the start of the file */ pos = 0; /* Read from the start of the file */
/* How much is sensible to read */ /* How much is sensible to read */
execi->hdr_len = MIN(execi->vp->v_size, sizeof(hdr)); execi->args.hdr_len = MIN(execi->vp->v_size, sizeof(hdr));
execi->hdr = hdr; execi->args.hdr = hdr;
r = req_readwrite(execi->vp->v_fs_e, execi->vp->v_inode_nr, r = req_readwrite(execi->vp->v_fs_e, execi->vp->v_inode_nr,
cvul64(pos), READING, VFS_PROC_NR, hdr, cvul64(pos), READING, VFS_PROC_NR, hdr,
execi->hdr_len, &new_pos, &cum_io); execi->args.hdr_len, &new_pos, &cum_io);
if (r != OK) { if (r != OK) {
printf("VFS: exec: map_header: req_readwrite failed\n"); printf("VFS: exec: map_header: req_readwrite failed\n");
return(r); return(r);

View File

@ -1,29 +0,0 @@
#ifndef _VFS_EXEC_H_
#define _VFS_EXEC_H_ 1
struct exec_info {
int proc_e; /* Process endpoint */
char *hdr; /* Exec file's header */
int hdr_len; /* How many bytes are in hdr */
vir_bytes pc; /* Entry point of exec file */
vir_bytes stack_top; /* Top of the stack */
vir_bytes frame_len; /* Stack size */
uid_t new_uid; /* Process UID after exec */
gid_t new_gid; /* Process GID after exec */
int load_text; /* Load text section? */
int setugid; /* Allow set{u,g}id execution? */
struct vnode *vp; /* Exec file's vnode */
struct vmnt *vmp; /* Exec file's vmnt */
struct stat sb; /* Exec file's stat structure */
char progname[PROC_NAME_LEN]; /* Program name */
int userflags; /* exec() flags from userland */
/* fields only used by elf and in VFS */
int is_dyn; /* Dynamically linked executable */
vir_bytes elf_phdr; /* Program header location */
vir_bytes elf_base; /* Userland addr load address */
int elf_main_fd; /* Dyn: FD of main program execuatble */
char execname[PATH_MAX]; /* Full executable invocation */
};
#endif /* !_VFS_EXEC_H_ */

View File

@ -1,10 +1,5 @@
#include <machine/vm.h> #include <machine/vm.h>
/* As visible from the user space process, where is the top of the
* stack (first non-stack byte), when in paged mode?
*/
#define VM_STACKTOP 0x80000000
/* And what is the highest addressable piece of memory, when in paged /* And what is the highest addressable piece of memory, when in paged
* mode? Some data for kernel and stack are subtracted from this, the * mode? Some data for kernel and stack are subtracted from this, the
* final results stored in bytes in arch.vm_data_top. * final results stored in bytes in arch.vm_data_top.

View File

@ -18,6 +18,7 @@
#include <errno.h> #include <errno.h>
#include <assert.h> #include <assert.h>
#include <string.h>
#include <env.h> #include <env.h>
#include <pagetable.h> #include <pagetable.h>
#include <sys/param.h> #include <sys/param.h>
@ -31,228 +32,6 @@
#include "memory.h" #include "memory.h"
static int new_mem(struct vmproc *vmp, vir_bytes text_addr, vir_bytes
text_bytes, vir_bytes data_addr, vir_bytes data_bytes, vir_bytes
stk_bytes, phys_bytes tot_bytes, vir_bytes *stack_top, int is_elf);
/*===========================================================================*
* exec_newmem *
*===========================================================================*/
int do_exec_newmem(message *msg)
{
int r, proc_e, proc_n;
vir_bytes stack_top;
vir_clicks tc, dc, sc, totc, dvir, s_vir;
struct vmproc *vmp;
char *ptr;
struct exec_newmem args;
SANITYCHECK(SCL_FUNCTIONS);
proc_e= msg->VMEN_ENDPOINT;
if (vm_isokendpt(proc_e, &proc_n) != OK)
{
printf("VM: exec_newmem: bad endpoint %d from %d\n",
proc_e, msg->m_source);
return ESRCH;
}
vmp= &vmproc[proc_n];
ptr= msg->VMEN_ARGSPTR;
if(msg->VMEN_ARGSSIZE != sizeof(args)) {
printf("VM: exec_newmem: args size %d != %u\n",
msg->VMEN_ARGSSIZE, sizeof(args));
return EINVAL;
}
SANITYCHECK(SCL_DETAIL);
r= sys_datacopy(msg->m_source, (vir_bytes)ptr,
SELF, (vir_bytes)&args, sizeof(args));
if (r != OK)
panic("exec_newmem: sys_datacopy failed: %d", r);
/* Minimum stack region (not preallocated)
* Stopgap for better rlimit-based stack size system
*/
if(args.tot_bytes < MINSTACKREGION) {
args.tot_bytes = MINSTACKREGION;
}
/* Check to see if segment sizes are feasible. */
tc = (vir_clicks) (CLICK_CEIL(args.text_bytes) >> CLICK_SHIFT);
dc = (vir_clicks) (CLICK_CEIL(args.data_bytes) >> CLICK_SHIFT);
totc = (vir_clicks) (CLICK_CEIL(args.tot_bytes) >> CLICK_SHIFT);
sc = (vir_clicks) (CLICK_CEIL(args.args_bytes) >> CLICK_SHIFT);
if (dc >= totc) {
printf("VM: newmem: no stack?\n");
return(ENOEXEC); /* stack must be at least 1 click */
}
dvir = (args.sep_id ? 0 : tc);
s_vir = dvir + (totc - sc);
r = (dvir + dc > s_vir) ? ENOMEM : OK;
if (r != OK) {
printf("VM: newmem: no virtual space?\n");
return r;
}
/* Allocate new memory and release old memory. Fix map and tell
* kernel.
*/
r = new_mem(vmp, args.text_addr, args.text_bytes,
args.data_addr, args.data_bytes,
args.args_bytes, args.tot_bytes, &stack_top,
args.is_elf);
if (r != OK) {
printf("VM: newmem: new_mem failed\n");
return(r);
}
/* Save file identification to allow it to be shared. */
vmp->vm_ino = args.st_ino;
vmp->vm_dev = args.st_dev;
vmp->vm_ctime = args.enst_ctime;
/* set/clear separate I&D flag */
if (args.sep_id)
vmp->vm_flags |= VMF_SEPARATE;
else
vmp->vm_flags &= ~VMF_SEPARATE;
msg->VMEN_STACK_TOP = (void *) stack_top;
msg->VMEN_FLAGS = 0;
msg->VMEN_FLAGS |= EXC_NM_RF_LOAD_TEXT;
return OK;
}
/*===========================================================================*
* new_mem *
*===========================================================================*/
static int new_mem(
struct vmproc *rmp, /* process to get a new memory map */
vir_bytes text_addr, /* text segement load address */
vir_bytes text_bytes, /* text segment size in bytes */
vir_bytes data_addr, /* data segment load address */
vir_bytes data_bytes, /* size of data (incl bss) in bytes */
vir_bytes stk_bytes, /* size of initial stack segment in bytes */
phys_bytes tot_bytes, /* total memory to allocate, including gap */
vir_bytes *stack_top, /* top of process stack */
int is_elf
)
{
/* Allocate new memory and release the old memory. Change the map and report
* the new map to the kernel. Zero the new core image's bss, gap and stack.
*/
vir_clicks text_clicks, data_clicks, gap_clicks, stack_clicks, tot_clicks;
int r, hadpt = 0;
struct vmproc *vmpold = &vmproc[VMP_EXECTMP];
int ptok = 1;
SANITYCHECK(SCL_FUNCTIONS);
assert(rmp->vm_flags & VMF_HASPT);
/* Acquire the new memory. Each of the 4 parts: text, (data+bss), gap,
* and stack occupies an integral number of clicks, starting at click
* boundary. The data and bss parts are run together with no space.
*/
text_clicks = (vir_clicks) (CLICK_CEIL(text_bytes) >> CLICK_SHIFT);
data_clicks = (vir_clicks) (CLICK_CEIL(data_bytes) >> CLICK_SHIFT);
stack_clicks = (vir_clicks) (CLICK_CEIL(stk_bytes) >> CLICK_SHIFT);
tot_clicks = (vir_clicks) (CLICK_CEIL(tot_bytes) >> CLICK_SHIFT);
gap_clicks = tot_clicks - data_clicks - stack_clicks;
if ( (int) gap_clicks < 0) {
printf("VM: new_mem: no gap?\n");
return(ENOMEM);
}
/* Keep previous process state for recovery; the sanity check functions
* know about the 'vmpold' slot, so the memory that the exec()ing
* process is still holding is referenced there.
*
* Throw away the old page table to avoid having two process slots
* using the same vm_pt.
* Just recreate it in the case that we have to revert.
*/
SANITYCHECK(SCL_DETAIL);
rmp->vm_flags &= ~VMF_HASPT;
pt_free(&rmp->vm_pt);
assert(!(vmpold->vm_flags & VMF_INUSE));
*vmpold = *rmp; /* copy current state. */
#if SANITYCHECKS
map_setparent(vmpold);
#endif
region_init(&rmp->vm_regions_avl); /* exec()ing process regions thrown out. */
rmp->vm_region_top = 0;
SANITYCHECK(SCL_DETAIL);
/* Build new process in current slot, without freeing old
* one. If it fails, revert.
*/
SANITYCHECK(SCL_DETAIL);
if((r=pt_new(&rmp->vm_pt)) != OK) {
ptok = 0;
printf("exec_newmem: no new pagetable\n");
}
SANITYCHECK(SCL_DETAIL);
if(r != OK || (r=proc_new(rmp,
VM_PROCSTART, /* where to start the process in the page table */
text_addr, /* text load address */
CLICK2ABS(text_clicks),/* how big is the text in bytes, page-aligned */
data_addr, /* data load address */
CLICK2ABS(data_clicks),/* how big is data+bss, page-aligned */
CLICK2ABS(stack_clicks),/* how big is stack, page-aligned */
CLICK2ABS(gap_clicks), /* how big is gap, page-aligned */
0,0, /* not preallocated */
VM_STACKTOP, /* regular stack top */
0, is_elf, 1)) != OK) {
SANITYCHECK(SCL_DETAIL);
printf("VM: new_mem: failed\n");
if(ptok) {
rmp->vm_flags &= ~VMF_HASPT;
pt_free(&rmp->vm_pt);
}
*rmp = *vmpold; /* undo. */
map_setparent(rmp);
clear_proc(vmpold); /* disappear. */
SANITYCHECK(SCL_DETAIL);
if(hadpt) {
if(pt_new(&rmp->vm_pt) != OK) {
/* We secretly know that making a new pagetable
* in the same slot if one was there will never fail.
*/
panic("new_mem: pt_new failed: %d", ENOMEM);
}
rmp->vm_flags |= VMF_HASPT;
SANITYCHECK(SCL_DETAIL);
if(map_writept(rmp) != OK) {
printf("VM: warning: exec undo failed\n");
}
SANITYCHECK(SCL_DETAIL);
}
return r;
}
SANITYCHECK(SCL_DETAIL);
/* new process is made; free and unreference
* page table and memory still held by exec()ing process.
*/
SANITYCHECK(SCL_DETAIL);
free_proc(vmpold);
clear_proc(vmpold); /* disappear. */
SANITYCHECK(SCL_DETAIL);
*stack_top = VM_STACKTOP;
SANITYCHECK(SCL_FUNCTIONS);
return(OK);
}
/*===========================================================================* /*===========================================================================*
* find_kernel_top * * find_kernel_top *
*===========================================================================*/ *===========================================================================*/
@ -273,6 +52,21 @@ phys_bytes find_kernel_top(void)
return CLICK2ABS(kernel_top); return CLICK2ABS(kernel_top);
} }
void regular_segs(struct vmproc *vmp)
{
int s;
memset(vmp->vm_arch.vm_seg, 0, sizeof(vmp->vm_arch.vm_seg));
vmp->vm_arch.vm_seg[T].mem_phys =
vmp->vm_arch.vm_seg[D].mem_phys = ABS2CLICK(VM_PROCSTART);
vmp->vm_arch.vm_seg[T].mem_len =
vmp->vm_arch.vm_seg[D].mem_len =
vmp->vm_arch.vm_seg[S].mem_len = ABS2CLICK(VM_DATATOP-VM_PROCSTART);
if((s=sys_newmap(vmp->vm_endpoint, vmp->vm_arch.vm_seg)) != OK)
panic("regular_segs: sys_newmap failed: %d", s);
if((s=pt_bind(&vmp->vm_pt, vmp)) != OK)
panic("regular_segs: pt_bind failed: %d", s);
}
/*===========================================================================* /*===========================================================================*
* proc_new * * proc_new *
*===========================================================================*/ *===========================================================================*/

View File

@ -27,6 +27,7 @@
void free_proc(struct vmproc *vmp) void free_proc(struct vmproc *vmp)
{ {
map_free_proc(vmp); map_free_proc(vmp);
vmp->vm_heap = NULL;
if(vmp->vm_flags & VMF_HASPT) { if(vmp->vm_flags & VMF_HASPT) {
vmp->vm_flags &= ~VMF_HASPT; vmp->vm_flags &= ~VMF_HASPT;
pt_free(&vmp->vm_pt); pt_free(&vmp->vm_pt);
@ -135,6 +136,7 @@ int do_procctl(message *msg)
pt_new(&vmp->vm_pt); pt_new(&vmp->vm_pt);
vmp->vm_flags |= VMF_HASPT; vmp->vm_flags |= VMF_HASPT;
pt_bind(&vmp->vm_pt, vmp); pt_bind(&vmp->vm_pt, vmp);
regular_segs(vmp);
return OK; return OK;
default: default:
return EINVAL; return EINVAL;

View File

@ -344,7 +344,6 @@ static int sef_cb_init_fresh(int type, sef_init_info_t *info)
CALLMAP(VM_EXIT, do_exit); CALLMAP(VM_EXIT, do_exit);
CALLMAP(VM_FORK, do_fork); CALLMAP(VM_FORK, do_fork);
CALLMAP(VM_BRK, do_brk); CALLMAP(VM_BRK, do_brk);
CALLMAP(VM_EXEC_NEWMEM, do_exec_newmem);
CALLMAP(VM_PUSH_SIG, do_push_sig); CALLMAP(VM_PUSH_SIG, do_push_sig);
CALLMAP(VM_WILLEXIT, do_willexit); CALLMAP(VM_WILLEXIT, do_willexit);
CALLMAP(VM_ADDDMA, do_adddma); CALLMAP(VM_ADDDMA, do_adddma);

View File

@ -93,7 +93,7 @@ int do_mmap(message *m)
len += VM_PAGE_SIZE - (len % VM_PAGE_SIZE); len += VM_PAGE_SIZE - (len % VM_PAGE_SIZE);
vr = NULL; vr = NULL;
if (m->VMM_ADDR) { if (m->VMM_ADDR || (m->VMM_FLAGS & MAP_FIXED)) {
/* An address is given, first try at that address. */ /* An address is given, first try at that address. */
addr = arch_vir2map(vmp, m->VMM_ADDR); addr = arch_vir2map(vmp, m->VMM_ADDR);
vr = map_page_region(vmp, addr, 0, len, MAP_NONE, vr = map_page_region(vmp, addr, 0, len, MAP_NONE,

View File

@ -65,6 +65,7 @@ int proc_new(struct vmproc *vmp, phys_bytes start, phys_bytes text_addr,
phys_bytes stack, phys_bytes gap, phys_bytes text_here, phys_bytes phys_bytes stack, phys_bytes gap, phys_bytes text_here, phys_bytes
data_here, vir_bytes stacktop, int prealloc_stack, int is_elf, int full); data_here, vir_bytes stacktop, int prealloc_stack, int is_elf, int full);
phys_bytes find_kernel_top(void); phys_bytes find_kernel_top(void);
void regular_segs(struct vmproc *);
/* break.c */ /* break.c */
int do_brk(message *msg); int do_brk(message *msg);

View File

@ -55,11 +55,6 @@ int do_push_sig(message *msg)
sp -= sizeof(struct sigcontext) sp -= sizeof(struct sigcontext)
+ 3 * sizeof(char *) + 2 * sizeof(int); + 3 * sizeof(char *) + 2 * sizeof(int);
if ((r=adjust(vmp, vmp->vm_arch.vm_seg[D].mem_len, sp)) != OK) {
printf("VM: do_push_sig: adjust() failed: %d\n", r);
return r;
}
return OK; return OK;
} }