From 298b41b52327711ea55805d23e26e8c918afae51 Mon Sep 17 00:00:00 2001 From: Ben Gras Date: Mon, 4 Feb 2013 01:49:48 +0100 Subject: [PATCH] libexec: detect short files if an exec() fails partway through reading in the sections, the target process is already gone and a defunct process remains. sanity checking the binary beforehand helps that. test10 mutilates binaries and exec()s them on purpose; making an exec() fail cleanly in such cases seems like acceptable behaviour. fixes test10 on ARM. Change-Id: I1ed9bb200ce469d4d349073cadccad5503b2fcb0 --- kernel/arch/earm/protect.c | 2 +- kernel/arch/i386/protect.c | 2 +- lib/libexec/exec_elf.c | 9 +++++++++ lib/libexec/libexec.h | 1 + servers/rs/exec.c | 2 +- servers/vfs/exec.c | 1 + servers/vm/main.c | 1 + test/test10.c | 6 +++++- 8 files changed, 20 insertions(+), 4 deletions(-) diff --git a/kernel/arch/earm/protect.c b/kernel/arch/earm/protect.c index c2afc447e..7a6f759b2 100644 --- a/kernel/arch/earm/protect.c +++ b/kernel/arch/earm/protect.c @@ -131,7 +131,7 @@ void arch_boot_proc(struct boot_image *ip, struct proc *rp) execi.stack_size = 32 * 1024; /* not too crazy as it must be preallocated */ execi.proc_e = ip->endpoint; execi.hdr = (char *) mod->mod_start; /* phys mem direct */ - execi.hdr_len = mod->mod_end - mod->mod_start; + execi.filesize = execi.hdr_len = mod->mod_end - mod->mod_start; strcpy(execi.progname, ip->proc_name); execi.frame_len = 0; diff --git a/kernel/arch/i386/protect.c b/kernel/arch/i386/protect.c index a95397c48..7594e2361 100644 --- a/kernel/arch/i386/protect.c +++ b/kernel/arch/i386/protect.c @@ -407,7 +407,7 @@ void arch_boot_proc(struct boot_image *ip, struct proc *rp) execi.stack_size = 16 * 1024; /* not too crazy as it must be preallocated */ execi.proc_e = ip->endpoint; execi.hdr = (char *) mod->mod_start; /* phys mem direct */ - execi.hdr_len = mod->mod_end - mod->mod_start; + execi.filesize = execi.hdr_len = mod->mod_end - mod->mod_start; strlcpy(execi.progname, ip->proc_name, sizeof(execi.progname)); execi.frame_len = 0; diff --git a/lib/libexec/exec_elf.c b/lib/libexec/exec_elf.c index a2096f1de..4645ec638 100644 --- a/lib/libexec/exec_elf.c +++ b/lib/libexec/exec_elf.c @@ -156,6 +156,15 @@ int libexec_load_elf(struct exec_info *execi) assert(execi->allocmem_prealloc); assert(execi->allocmem_ondemand); + for (i = 0; i < hdr->e_phnum; i++) { + Elf_Phdr *ph = &phdr[i]; + off_t file_limit = ph->p_offset + ph->p_filesz; + /* sanity check binary before wiping out the target process */ + if(execi->filesize < file_limit) { + return ENOEXEC; + } + } + if(execi->clearproc) execi->clearproc(execi); for (i = 0; i < hdr->e_phnum; i++) { diff --git a/lib/libexec/libexec.h b/lib/libexec/libexec.h index 69da9cb29..8b6db7618 100644 --- a/lib/libexec/libexec.h +++ b/lib/libexec/libexec.h @@ -28,6 +28,7 @@ struct exec_info { int allow_setuid; /* Allow set{u,g}id execution? */ vir_bytes stack_size; /* Desired stack size */ vir_bytes load_offset; /* Desired load offset */ + off_t filesize; /* How big is the file */ /* Callback pointers for use by libexec */ libexec_loadfunc_t copymem; /* Copy callback */ diff --git a/servers/rs/exec.c b/servers/rs/exec.c index 7dd908de1..d0c950f67 100644 --- a/servers/rs/exec.c +++ b/servers/rs/exec.c @@ -124,7 +124,7 @@ static int do_exec(int proc_e, char *exec, size_t exec_len, char *progname, execi.stack_size = DEFAULT_STACK_LIMIT; execi.proc_e = proc_e; execi.hdr = exec; - execi.hdr_len = exec_len; + execi.filesize = execi.hdr_len = exec_len; strncpy(execi.progname, progname, PROC_NAME_LEN-1); execi.progname[PROC_NAME_LEN-1] = '\0'; execi.frame_len = frame_len; diff --git a/servers/vfs/exec.c b/servers/vfs/exec.c index cf49447bf..b3f6f56ce 100644 --- a/servers/vfs/exec.c +++ b/servers/vfs/exec.c @@ -312,6 +312,7 @@ int pm_exec(endpoint_t proc_e, vir_bytes path, size_t path_len, execi.args.proc_e = proc_e; execi.args.frame_len = frame_len; + execi.args.filesize = execi.vp->v_size; for (i = 0; exec_loaders[i].load_object != NULL; i++) { r = (*exec_loaders[i].load_object)(&execi.args); diff --git a/servers/vm/main.c b/servers/vm/main.c index d40a0b621..f2b7c2f5f 100644 --- a/servers/vm/main.c +++ b/servers/vm/main.c @@ -276,6 +276,7 @@ void exec_bootproc(struct vmproc *vmp, struct boot_image *ip) strlcpy(execi->progname, ip->proc_name, sizeof(execi->progname)); execi->frame_len = 0; execi->opaque = &vmexeci; + execi->filesize = ip->len; vmexeci.ip = ip; vmexeci.vmp = vmp; diff --git a/test/test10.c b/test/test10.c index 152b560bf..040b0f33a 100644 --- a/test/test10.c +++ b/test/test10.c @@ -77,7 +77,11 @@ int n; if ((pid = fork()) != 0) { wait(&n); /* wait for some child (any one) */ } else { - execl(name[n], name[n], (char *) 0); + /* a successful exec or a successful detection of a broken executable + * is ok + */ + if(execl(name[n], name[n], (char *) 0) < 0 && errno == ENOEXEC) + exit(0); errct++; printf("Child execl didn't take. file=%s errno=%d\n", name[n], errno); rmfiles(); -- 2.11.4.GIT