diff --git a/kernel/arch/earm/protect.c b/kernel/arch/earm/protect.c index fe6df33d9..75b3ef897 100644 --- a/kernel/arch/earm/protect.c +++ b/kernel/arch/earm/protect.c @@ -138,7 +138,8 @@ void arch_boot_proc(struct boot_image *ip, struct proc *rp) /* callbacks for use in the kernel */ execi.copymem = libexec_copy_memcpy; execi.clearmem = libexec_clear_memset; - execi.allocmem_prealloc = libexec_pg_alloc; + execi.allocmem_prealloc_cleared = libexec_pg_alloc; + execi.allocmem_prealloc_junk = libexec_pg_alloc; execi.allocmem_ondemand = libexec_pg_alloc; execi.clearproc = NULL; diff --git a/kernel/arch/i386/protect.c b/kernel/arch/i386/protect.c index 22acc3350..5a98a41ad 100644 --- a/kernel/arch/i386/protect.c +++ b/kernel/arch/i386/protect.c @@ -414,7 +414,8 @@ void arch_boot_proc(struct boot_image *ip, struct proc *rp) /* callbacks for use in the kernel */ execi.copymem = libexec_copy_memcpy; execi.clearmem = libexec_clear_memset; - execi.allocmem_prealloc = libexec_pg_alloc; + execi.allocmem_prealloc_junk = libexec_pg_alloc; + execi.allocmem_prealloc_cleared = libexec_pg_alloc; execi.allocmem_ondemand = libexec_pg_alloc; execi.clearproc = NULL; diff --git a/lib/libexec/exec_elf.c b/lib/libexec/exec_elf.c index 625b3f087..24bfed966 100644 --- a/lib/libexec/exec_elf.c +++ b/lib/libexec/exec_elf.c @@ -150,7 +150,8 @@ int libexec_load_elf(struct exec_info *execi) assert(execi->copymem); assert(execi->clearmem); - assert(execi->allocmem_prealloc); + assert(execi->allocmem_prealloc_cleared); + assert(execi->allocmem_prealloc_junk); assert(execi->allocmem_ondemand); for (i = 0; i < hdr->e_phnum; i++) { @@ -167,51 +168,124 @@ int libexec_load_elf(struct exec_info *execi) for (i = 0; i < hdr->e_phnum; i++) { vir_bytes seg_membytes, page_offset, p_vaddr, vaddr; vir_bytes chunk, vfileend, vmemend; + off_t foffset, fbytes; Elf_Phdr *ph = &phdr[i]; + int try_mmap = 1; + u16_t clearend = 0; + int pagechunk; + int mmap_prot = PROT_READ; + + if(!(ph->p_flags & PF_R)) { + printf("libexec: warning: unreadable segment\n"); + } + + if(ph->p_flags & PF_W) { + mmap_prot |= PROT_WRITE; +#if ELF_DEBUG + printf("libexec: adding PROT_WRITE\n"); +#endif + } else { +#if ELF_DEBUG + printf("libexec: not adding PROT_WRITE\n"); +#endif + } + if (ph->p_type != PT_LOAD || ph->p_memsz == 0) continue; + + if((ph->p_vaddr % PAGE_SIZE) != (ph->p_offset % PAGE_SIZE)) { + printf("libexec: unaligned ELF program?\n"); + try_mmap = 0; + } + + if(!execi->memmap) { + try_mmap = 0; + } + + foffset = ph->p_offset; + fbytes = ph->p_filesz; vaddr = p_vaddr = ph->p_vaddr + execi->load_offset; seg_membytes = ph->p_memsz; + page_offset = vaddr % PAGE_SIZE; vaddr -= page_offset; + foffset -= page_offset; seg_membytes += page_offset; + fbytes += page_offset; + vfileend = p_vaddr + ph->p_filesz; + + /* if there's usable memory after the file end, we have + * to tell VM to clear the memory part of the page when it's + * mapped in + */ + if((pagechunk = (vfileend % PAGE_SIZE)) + && ph->p_filesz < ph->p_memsz) { + clearend = PAGE_SIZE - pagechunk; + } + seg_membytes = roundup(seg_membytes, PAGE_SIZE); + fbytes = roundup(fbytes, PAGE_SIZE); + if(first || startv > vaddr) startv = vaddr; first = 0; - /* make us some memory */ - if(execi->allocmem_prealloc(execi, vaddr, seg_membytes) != OK) { - if(execi->clearproc) execi->clearproc(execi); - return ENOMEM; - } - + if(try_mmap && execi->memmap(execi, vaddr, fbytes, foffset, clearend, mmap_prot) == OK) { #if ELF_DEBUG - printf("mmapped 0x%lx-0x%lx\n", vaddr, vaddr+seg_membytes); + printf("libexec: mmap 0x%lx-0x%lx done, clearend 0x%x\n", + vaddr, vaddr+fbytes, clearend); #endif - /* Copy executable section into it */ - if(execi->copymem(execi, ph->p_offset, p_vaddr, ph->p_filesz) != OK) { - if(execi->clearproc) execi->clearproc(execi); - return ENOMEM; - } + if(seg_membytes > fbytes) { + int rem_mem = seg_membytes - fbytes;; + vir_bytes remstart = vaddr + fbytes; + if(execi->allocmem_ondemand(execi, + remstart, rem_mem) != OK) { + printf("libexec: mmap extra mem failed\n"); + return ENOMEM; + } +#if ELF_DEBUG + else printf("libexec: allocated 0x%lx-0x%lx\n", + + remstart, remstart+rem_mem); +#endif + } + } else { + if(try_mmap) printf("libexec: mmap failed\n"); + + /* make us some memory */ + if(execi->allocmem_prealloc_junk(execi, vaddr, seg_membytes) != OK) { + if(execi->clearproc) execi->clearproc(execi); + return ENOMEM; + } #if ELF_DEBUG - printf("copied 0x%lx-0x%lx\n", p_vaddr, p_vaddr+ph->p_filesz); + printf("mmapped 0x%lx-0x%lx\n", vaddr, vaddr+seg_membytes); #endif - /* Clear remaining bits */ - vfileend = p_vaddr + ph->p_filesz; - vmemend = vaddr + seg_membytes; - if((chunk = p_vaddr - vaddr) > 0) { + /* Copy executable section into it */ + if(execi->copymem(execi, ph->p_offset, p_vaddr, ph->p_filesz) != OK) { + if(execi->clearproc) execi->clearproc(execi); + return ENOMEM; + } + #if ELF_DEBUG - printf("start clearing 0x%lx-0x%lx\n", vaddr, vaddr+chunk); + printf("copied 0x%lx-0x%lx\n", p_vaddr, p_vaddr+ph->p_filesz); #endif - execi->clearmem(execi, vaddr, chunk); - } - if((chunk = vmemend - vfileend) > 0) { + + /* Clear remaining bits */ + vmemend = vaddr + seg_membytes; + if((chunk = p_vaddr - vaddr) > 0) { #if ELF_DEBUG - printf("end clearing 0x%lx-0x%lx\n", vfileend, vaddr+chunk); + printf("start clearing 0x%lx-0x%lx\n", vaddr, vaddr+chunk); #endif - execi->clearmem(execi, vfileend, chunk); + 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); + } } } diff --git a/lib/libexec/exec_general.c b/lib/libexec/exec_general.c index 2ac942df9..a1afecfa7 100644 --- a/lib/libexec/exec_general.c +++ b/lib/libexec/exec_general.c @@ -18,7 +18,7 @@ #include #include -int libexec_alloc_mmap_prealloc(struct exec_info *execi, off_t vaddr, size_t len) +int libexec_alloc_mmap_prealloc_junk(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, @@ -29,6 +29,17 @@ int libexec_alloc_mmap_prealloc(struct exec_info *execi, off_t vaddr, size_t len return OK; } +int libexec_alloc_mmap_prealloc_cleared(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_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, diff --git a/lib/libexec/libexec.h b/lib/libexec/libexec.h index 8b6db7618..8597e74c3 100644 --- a/lib/libexec/libexec.h +++ b/lib/libexec/libexec.h @@ -16,6 +16,10 @@ typedef int (*libexec_allocfunc_t)(struct exec_info *execi, typedef int (*libexec_procclearfunc_t)(struct exec_info *execi); +typedef int (*libexec_mmap_t)(struct exec_info *execi, + vir_bytes vaddr, vir_bytes len, vir_bytes foffset, u16_t clearend, + int protflags); + struct exec_info { /* Filled in by libexec caller */ endpoint_t proc_e; /* Process endpoint */ @@ -33,9 +37,11 @@ struct exec_info { /* 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_prealloc_cleared; /* Alloc callback */ + libexec_allocfunc_t allocmem_prealloc_junk; /* Alloc callback */ libexec_allocfunc_t allocmem_ondemand; /* Alloc callback */ libexec_procclearfunc_t clearproc; /* Clear process callback */ + libexec_mmap_t memmap; /* mmap callback */ void *opaque; /* Callback data */ /* Filled in by libexec load function */ @@ -55,7 +61,8 @@ int libexec_load_elf(struct exec_info *execi); int libexec_copy_memcpy(struct exec_info *execi, off_t offset, off_t vaddr, size_t len); int libexec_clear_memset(struct exec_info *execi, off_t vaddr, size_t len); -int libexec_alloc_mmap_prealloc(struct exec_info *execi, off_t vaddr, size_t len); +int libexec_alloc_mmap_prealloc_cleared(struct exec_info *execi, off_t vaddr, size_t len); +int libexec_alloc_mmap_prealloc_junk(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); diff --git a/servers/rs/exec.c b/servers/rs/exec.c index d0c950f67..ffbab2c78 100644 --- a/servers/rs/exec.c +++ b/servers/rs/exec.c @@ -133,7 +133,8 @@ static int do_exec(int proc_e, char *exec, size_t exec_len, char *progname, execi.copymem = read_seg; execi.clearproc = libexec_clearproc_vm_procctl; execi.clearmem = libexec_clear_sys_memset; - execi.allocmem_prealloc = libexec_alloc_mmap_prealloc; + execi.allocmem_prealloc_cleared = libexec_alloc_mmap_prealloc_cleared; + execi.allocmem_prealloc_junk = libexec_alloc_mmap_prealloc_junk; execi.allocmem_ondemand = libexec_alloc_mmap_ondemand; for(i = 0; exec_loaders[i].load_object != NULL; i++) { diff --git a/servers/vfs/exec.c b/servers/vfs/exec.c index daad6a2fb..ce00e56c8 100644 --- a/servers/vfs/exec.c +++ b/servers/vfs/exec.c @@ -306,7 +306,8 @@ int pm_exec(endpoint_t proc_e, vir_bytes path, size_t path_len, execi.args.copymem = read_seg; execi.args.clearproc = libexec_clearproc_vm_procctl; execi.args.clearmem = libexec_clear_sys_memset; - execi.args.allocmem_prealloc = libexec_alloc_mmap_prealloc; + execi.args.allocmem_prealloc_cleared = libexec_alloc_mmap_prealloc_cleared; + execi.args.allocmem_prealloc_junk = libexec_alloc_mmap_prealloc_junk; execi.args.allocmem_ondemand = libexec_alloc_mmap_ondemand; execi.args.opaque = &execi; diff --git a/servers/vm/main.c b/servers/vm/main.c index 9cd14b444..caf148de5 100644 --- a/servers/vm/main.c +++ b/servers/vm/main.c @@ -287,7 +287,8 @@ void exec_bootproc(struct vmproc *vmp, struct boot_image *ip) execi->copymem = libexec_copy_physcopy; execi->clearproc = NULL; execi->clearmem = libexec_clear_sys_memset; - execi->allocmem_prealloc = libexec_alloc_vm_prealloc; + execi->allocmem_prealloc_junk = libexec_alloc_vm_prealloc; + execi->allocmem_prealloc_cleared = libexec_alloc_vm_prealloc; execi->allocmem_ondemand = libexec_alloc_vm_ondemand; if(libexec_load_elf(execi) != OK)