further libexec generalization
. new mode for sys_memset: include process so memset can be done in physical or virtual address space. . add a mode to mmap() that lets a process allocate uninitialized memory. . this allows an exec()er (RS, VFS, etc.) to request uninitialized memory from VM and selectively clear the ranges that don't come from a file, leaving no uninitialized memory left for the process to see. . use callbacks for clearing the process, clearing memory in the process, and copying into the process; so that the libexec code can be used from rs, vfs, and in the future, kernel (to load vm) and vm (to load boot-time processes)
This commit is contained in:
+40
-32
@@ -220,7 +220,6 @@ int elf_has_interpreter(char *exec_hdr, /* executable header */
|
||||
|
||||
int libexec_load_elf(struct exec_info *execi)
|
||||
{
|
||||
int r;
|
||||
Elf_Ehdr *hdr = NULL;
|
||||
Elf_Phdr *phdr = NULL;
|
||||
int e, i = 0;
|
||||
@@ -240,25 +239,26 @@ int libexec_load_elf(struct exec_info *execi)
|
||||
*/
|
||||
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;
|
||||
|
||||
assert(execi->copymem);
|
||||
assert(execi->clearmem);
|
||||
assert(execi->allocmem_prealloc);
|
||||
assert(execi->allocmem_ondemand);
|
||||
|
||||
if(execi->clearproc) execi->clearproc(execi);
|
||||
|
||||
for (i = 0; i < hdr->e_phnum; i++) {
|
||||
vir_bytes seg_membytes, page_offset, vaddr;
|
||||
vir_bytes chunk, vfileend, vmemend;
|
||||
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;
|
||||
@@ -268,34 +268,46 @@ int libexec_load_elf(struct exec_info *execi)
|
||||
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);
|
||||
/* make us some memory */
|
||||
if(execi->allocmem_prealloc(execi, vaddr, seg_membytes) != OK) {
|
||||
if(execi->clearproc) execi->clearproc(execi);
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
#if ELF_DEBUG
|
||||
printf("mmapped 0x%lx-0x%lx\n", vaddr, vaddr+seg_membytes);
|
||||
#endif
|
||||
|
||||
/* 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);
|
||||
if(execi->copymem(execi, ph->p_offset, ph->p_vaddr, ph->p_filesz) != OK) {
|
||||
if(execi->clearproc) execi->clearproc(execi);
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
#if ELF_DEBUG
|
||||
printf("copied 0x%lx-0x%lx\n", ph->p_vaddr, ph->p_vaddr+ph->p_filesz);
|
||||
#endif
|
||||
|
||||
/* Clear remaining bits */
|
||||
vfileend = ph->p_vaddr + ph->p_filesz;
|
||||
vmemend = vaddr + seg_membytes;
|
||||
if((chunk = ph->p_vaddr - vaddr) > 0) {
|
||||
#if ELF_DEBUG
|
||||
printf("start clearing 0x%lx-0x%lx\n", vaddr, vaddr+chunk);
|
||||
#endif
|
||||
execi->clearmem(execi, vaddr, chunk);
|
||||
}
|
||||
if((chunk = vmemend - vfileend) > 0) {
|
||||
#if ELF_DEBUG
|
||||
printf("end clearing 0x%lx-0x%lx\n", vfileend, vaddr+chunk);
|
||||
#endif
|
||||
execi->clearmem(execi, vfileend, chunk);
|
||||
}
|
||||
}
|
||||
|
||||
/* 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);
|
||||
if(execi->allocmem_ondemand(execi, stacklow, execi->stack_size) != OK) {
|
||||
if(execi->clearproc) execi->clearproc(execi);
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
@@ -303,10 +315,6 @@ int libexec_load_elf(struct exec_info *execi)
|
||||
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);
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,8 +12,43 @@
|
||||
#include <minix/ipc.h>
|
||||
#include <minix/com.h>
|
||||
#include <minix/callnr.h>
|
||||
#include <minix/vm.h>
|
||||
#include <minix/syslib.h>
|
||||
#include <sys/mman.h>
|
||||
#include <machine/elf.h>
|
||||
|
||||
int libexec_alloc_mmap_prealloc(struct exec_info *execi, off_t vaddr, size_t len)
|
||||
{
|
||||
if(minix_mmap_for(execi->proc_e, (void *) vaddr, len,
|
||||
PROT_READ|PROT_WRITE|PROT_EXEC,
|
||||
MAP_ANON|MAP_PREALLOC|MAP_UNINITIALIZED|MAP_FIXED, -1, 0) == MAP_FAILED) {
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
int libexec_alloc_mmap_ondemand(struct exec_info *execi, off_t vaddr, size_t len)
|
||||
{
|
||||
if(minix_mmap_for(execi->proc_e, (void *) vaddr, len,
|
||||
PROT_READ|PROT_WRITE|PROT_EXEC,
|
||||
MAP_ANON|MAP_FIXED, -1, 0) == MAP_FAILED) {
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
int libexec_clearproc_vm_procctl(struct exec_info *execi)
|
||||
{
|
||||
return vm_procctl(execi->proc_e, VMPPARAM_CLEAR);
|
||||
}
|
||||
|
||||
int libexec_clear_sys_memset(struct exec_info *execi, off_t vaddr, size_t len)
|
||||
{
|
||||
return sys_memset(execi->proc_e, 0, vaddr, len);
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
+18
-4
@@ -11,6 +11,11 @@ typedef int (*libexec_loadfunc_t)(struct exec_info *execi,
|
||||
typedef int (*libexec_clearfunc_t)(struct exec_info *execi,
|
||||
off_t vaddr, size_t len);
|
||||
|
||||
typedef int (*libexec_allocfunc_t)(struct exec_info *execi,
|
||||
off_t vaddr, size_t len);
|
||||
|
||||
typedef int (*libexec_procclearfunc_t)(struct exec_info *execi);
|
||||
|
||||
struct exec_info {
|
||||
/* Filled in by libexec caller */
|
||||
endpoint_t proc_e; /* Process endpoint */
|
||||
@@ -21,11 +26,16 @@ struct exec_info {
|
||||
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 */
|
||||
|
||||
/* Callback pointers for use by libexec */
|
||||
libexec_loadfunc_t copymem; /* Copy callback */
|
||||
libexec_clearfunc_t clearmem; /* Clear callback */
|
||||
libexec_allocfunc_t allocmem_prealloc; /* Alloc callback */
|
||||
libexec_allocfunc_t allocmem_ondemand; /* Alloc callback */
|
||||
libexec_procclearfunc_t clearproc; /* Clear process callback */
|
||||
void *opaque; /* Callback data */
|
||||
|
||||
/* Filled in by libexec load function */
|
||||
vir_bytes load_base; /* Where executable is loaded */
|
||||
vir_bytes pc; /* Entry point of exec file */
|
||||
@@ -45,7 +55,11 @@ void libexec_patch_ptr(char stack[ARG_MAX], vir_bytes base);
|
||||
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);
|
||||
|
||||
int libexec_alloc_mmap_prealloc(struct exec_info *execi, off_t vaddr, size_t len);
|
||||
int libexec_alloc_mmap_ondemand(struct exec_info *execi, off_t vaddr, size_t len);
|
||||
int libexec_clearproc_vm_procctl(struct exec_info *execi);
|
||||
int libexec_clear_sys_memset(struct exec_info *execi, off_t vaddr, size_t len);
|
||||
|
||||
#endif /* !_LIBEXEC_H_ */
|
||||
|
||||
Reference in New Issue
Block a user