diff options
Diffstat (limited to 'sys/kern/exec_elf.c')
-rw-r--r-- | sys/kern/exec_elf.c | 132 |
1 files changed, 77 insertions, 55 deletions
diff --git a/sys/kern/exec_elf.c b/sys/kern/exec_elf.c index 6258ed68a04..9b5b8eb3acf 100644 --- a/sys/kern/exec_elf.c +++ b/sys/kern/exec_elf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: exec_elf.c,v 1.153 2019/12/09 18:19:09 deraadt Exp $ */ +/* $OpenBSD: exec_elf.c,v 1.154 2020/01/25 01:28:38 deraadt Exp $ */ /* * Copyright (c) 1996 Per Fogelstrom @@ -103,8 +103,8 @@ int coredump_elf(struct proc *, void *); void *elf_copyargs(struct exec_package *, struct ps_strings *, void *, void *); int exec_elf_fixup(struct proc *, struct exec_package *); -int elf_os_pt_note(struct proc *, struct exec_package *, Elf_Ehdr *, - char *, size_t, size_t); +int elf_os_pt_note_name(Elf_Note *); +int elf_os_pt_note(struct proc *, struct exec_package *, Elf_Ehdr *, int *); extern char sigcode[], esigcode[], sigcoderet[]; #ifdef SYSCALL_DEBUG @@ -150,6 +150,20 @@ struct emul emul_elf = { sigcoderet }; +#define ELF_NOTE_NAME_OPENBSD 0x01 +#define ELF_NOTE_NAME_GO 0x02 + +struct elf_note_name { + char *name; + int id; +} elf_note_names[] = { + { "OpenBSD", ELF_NOTE_NAME_OPENBSD }, + { "Go", ELF_NOTE_NAME_GO } +}; + +#define ELFROUNDSIZE sizeof(Elf_Word) +#define elfround(x) roundup((x), ELFROUNDSIZE) + /* * Copy arguments onto the stack in the normal way, but add some * space for extra information in case of dynamic binding. @@ -515,7 +529,7 @@ exec_elf_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, has_phdr = 0; + int error, i, has_phdr = 0, names = 0; char *interp = NULL; u_long phsize; size_t randomizequota = ELF_RANDOMIZE_LIMIT; @@ -596,10 +610,10 @@ exec_elf_makecmds(struct proc *p, struct exec_package *epp) * Verify this is an OpenBSD executable. If it's marked that way * via a PT_NOTE then also check for a PT_OPENBSD_WXNEEDED segment. */ - if (eh->e_ident[EI_OSABI] != ELFOSABI_OPENBSD && (error = - elf_os_pt_note(p, epp, epp->ep_hdr, "OpenBSD", 8, 4)) != 0) { + if ((error = elf_os_pt_note(p, epp, epp->ep_hdr, &names)) != 0) goto bad; - } + if (eh->e_ident[EI_OSABI] == ELFOSABI_OPENBSD) + names |= ELF_NOTE_NAME_OPENBSD; /* * Load all the necessary sections @@ -621,17 +635,14 @@ exec_elf_makecmds(struct proc *p, struct exec_package *epp) } } else addr = ELF_NO_ADDR; - /* - * static binary: main program does system calls - * dynamic binary: regular main program won't do system - * calls, unfortunately go binaries do... - */ - flags |= VMCMD_SYSCALL; - if (interp == NULL) { - /* - * static binary: no ld.so, no late request for - * syscalls inside libc.so block msyscall() - */ + + /* Permit system calls in specific main-programs */ + if (names & ELF_NOTE_NAME_GO) { + /* go main-binaries; we await a libc future */ + flags |= VMCMD_SYSCALL; + } else if (interp == NULL) { + /* statics. Also block the ld.so syscall-grant */ + flags |= VMCMD_SYSCALL; p->p_vmspace->vm_map.flags |= VM_MAP_SYSCALL_ONCE; } @@ -862,13 +873,35 @@ exec_elf_fixup(struct proc *p, struct exec_package *epp) } int -elf_os_pt_note(struct proc *p, struct exec_package *epp, Elf_Ehdr *eh, - char *os_name, size_t name_size, size_t desc_size) +elf_os_pt_note_name(Elf_Note *np) +{ + int i, j; + + for (i = 0; i < nitems(elf_note_names); i++) { + size_t namlen = strlen(elf_note_names[i].name); + if (np->namesz < namlen) + continue; + /* verify name padding (after the NUL) is NUL */ + for (j = namlen + 1; j < elfround(np->namesz); j++) + if (((char *)(np + 1))[j] != '\0') + continue; + /* verify desc padding is NUL */ + for (j = np->descsz; j < elfround(np->descsz); j++) + if (((char *)(np + 1))[j] != '\0') + continue; + if (strcmp((char *)(np + 1), elf_note_names[i].name) == 0) + return elf_note_names[i].id; + } + return (0); +} + +int +elf_os_pt_note(struct proc *p, struct exec_package *epp, Elf_Ehdr *eh, int *namesp) { Elf_Phdr *hph, *ph; Elf_Note *np = NULL; - size_t phsize; - int error; + size_t phsize, offset, pfilesz = 0, total; + int error, names = 0; hph = mallocarray(eh->e_phnum, sizeof(Elf_Phdr), M_TEMP, M_WAITOK); phsize = eh->e_phnum * sizeof(Elf_Phdr); @@ -879,50 +912,42 @@ elf_os_pt_note(struct proc *p, struct exec_package *epp, Elf_Ehdr *eh, for (ph = hph; ph < &hph[eh->e_phnum]; ph++) { if (ph->p_type == PT_OPENBSD_WXNEEDED) { epp->ep_flags |= EXEC_WXNEEDED; - break; + continue; } - } - for (ph = hph; ph < &hph[eh->e_phnum]; ph++) { - if (ph->p_type != PT_NOTE || - ph->p_filesz > 1024 || - ph->p_filesz < sizeof(Elf_Note) + name_size) + if (ph->p_type != PT_NOTE || ph->p_filesz > 1024) continue; - np = malloc(ph->p_filesz, M_TEMP, M_WAITOK); + if (np && ph->p_filesz != pfilesz) { + free(np, M_TEMP, pfilesz); + np = NULL; + } + if (!np) + np = malloc(ph->p_filesz, M_TEMP, M_WAITOK); + pfilesz = ph->p_filesz; if ((error = elf_read_from(p, epp->ep_vp, ph->p_offset, np, ph->p_filesz)) != 0) goto out2; -#if 0 - if (np->type != ELF_NOTE_TYPE_OSVERSION) { - free(np, M_TEMP, ph->p_filesz); - np = NULL; - continue; - } -#endif - - /* Check the name and description sizes. */ - if (np->namesz != name_size || - np->descsz != desc_size) - goto out3; - - if (memcmp((np + 1), os_name, name_size)) - goto out3; + for (offset = 0; offset < ph->p_filesz; offset += total) { + Elf_Note *np2 = (Elf_Note *)((char *)np + offset); - /* XXX: We could check for the specific emulation here */ - /* All checks succeeded. */ - error = 0; - goto out2; + if (offset + sizeof(Elf_Note) > ph->p_filesz) + break; + total = sizeof(Elf_Note) + elfround(np2->namesz) + + elfround(np2->descsz); + if (offset + total > ph->p_filesz) + break; + names |= elf_os_pt_note_name(np2); + } } -out3: - error = ENOEXEC; out2: - free(np, M_TEMP, ph->p_filesz); + free(np, M_TEMP, pfilesz); out1: free(hph, M_TEMP, phsize); - return error; + *namesp = names; + return ((names & ELF_NOTE_NAME_OPENBSD) ? 0 : ENOEXEC); } /* @@ -957,9 +982,6 @@ int coredump_note_elf(struct proc *, void *, size_t *); int coredump_writenote_elf(struct proc *, void *, Elf_Note *, const char *, void *); -#define ELFROUNDSIZE sizeof(Elf_Word) -#define elfround(x) roundup((x), ELFROUNDSIZE) - int coredump_elf(struct proc *p, void *cookie) { |