Require EFT shared objects have a PT_PHDR entry to be considered
authorkurt <kurt@openbsd.org>
Tue, 27 Jan 2015 00:33:21 +0000 (00:33 +0000)
committerkurt <kurt@openbsd.org>
Tue, 27 Jan 2015 00:33:21 +0000 (00:33 +0000)
a pie binary. The kernel will now reject executing a typical shared
library with EINVAL. This breaks compatibility with initial static pie
binaries and requires a recent user-land prior to upgrading. In
addition, more fine grained errors can be returned from execve(2)
when errors occur while attempting to execute ELF objects.

okay guenther@, kettenis@, deraadt@

sys/kern/exec_elf.c

index 8954eab..36882bd 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: exec_elf.c,v 1.109 2015/01/20 19:43:21 kettenis Exp $ */
+/*     $OpenBSD: exec_elf.c,v 1.110 2015/01/27 00:33:21 kurt Exp $     */
 
 /*
  * Copyright (c) 1996 Per Fogelstrom
@@ -514,7 +514,7 @@ ELFNAME2(exec,makecmds)(struct proc *p, struct exec_package *epp)
        Elf_Ehdr *eh = epp->ep_hdr;
        Elf_Phdr *ph, *pp, *base_ph = NULL;
        Elf_Addr phdr = 0, exe_base = 0;
-       int error, i;
+       int error, i, has_phdr = 0;
        char *interp = NULL;
        u_long pos = 0, phsize;
        size_t randomizequota = ELF_RANDOMIZE_LIMIT;
@@ -563,13 +563,17 @@ ELFNAME2(exec,makecmds)(struct proc *p, struct exec_package *epp)
                } else if (pp->p_type == PT_LOAD) {
                        if (base_ph == NULL)
                                base_ph = pp;
+               } else if (pp->p_type == PT_PHDR) {
+                       has_phdr = 1;
                }
        }
 
        if (eh->e_type == ET_DYN) {
-               /* need load sections for PIE */
-               if (base_ph == NULL)
+               /* need phdr and load sections for PIE */
+               if (!has_phdr || base_ph == NULL) {
+                       error = EINVAL;
                        goto bad;
+               }
                /* randomize exe_base for PIE */
                exe_base = uvm_map_pie(base_ph->p_align);
        }
@@ -762,7 +766,9 @@ bad:
                pool_put(&namei_pool, interp);
        free(ph, M_TEMP, phsize);
        kill_vmcmds(&epp->ep_vmcmds);
-       return (ENOEXEC);
+       if (error == 0)
+               return (ENOEXEC);
+       return (error);
 }
 
 /*