From: deraadt Date: Thu, 27 Oct 2022 22:48:17 +0000 (+0000) Subject: Unfortunately there are still ugly text-relocation binaries in the wild. X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=414b58f502531453c1de62424edde00c1622ad83;p=openbsd Unfortunately there are still ugly text-relocation binaries in the wild. Libraries are less of a concern, because ld.so can fix them in the right order. So we must scan DYNAMIC for the TEXTREL marker, and not make X LOADs immutable. ld.so will apply changes to the text segment. In upcoming diff, crt0 and ld.so will then apply immutability. ok kettenis --- diff --git a/sys/kern/exec_elf.c b/sys/kern/exec_elf.c index 0c2d0816cb6..c521c7986f5 100644 --- a/sys/kern/exec_elf.c +++ b/sys/kern/exec_elf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: exec_elf.c,v 1.172 2022/10/27 16:01:18 deraadt Exp $ */ +/* $OpenBSD: exec_elf.c,v 1.173 2022/10/27 22:48:17 deraadt Exp $ */ /* * Copyright (c) 1996 Per Fogelstrom @@ -189,17 +189,21 @@ elf_load_psection(struct exec_vmcmd_set *vcset, struct vnode *vp, * initially. The dynamic linker will make these read-only * and add back X permission after relocation processing. * Static executables with W|X segments will probably crash. - * Apply immutability as much as possible, but not for RELRO - * or PT_OPENBSD_MUTABLE sections, or LOADS marked - * PF_OPENBSD_MUTABLE, or LOADS which violate W^X. Userland - * (meaning crt0 or ld.so) will repair those regions. */ *prot |= (ph->p_flags & PF_R) ? PROT_READ : 0; *prot |= (ph->p_flags & PF_W) ? PROT_WRITE : 0; if ((ph->p_flags & PF_W) == 0) *prot |= (ph->p_flags & PF_X) ? PROT_EXEC : 0; + + /* + * Apply immutability as much as possible, but not text-segments + * of textrel binaries, or RELRO or PT_OPENBSD_MUTABLE sections, + * or LOADS marked PF_OPENBSD_MUTABLE, or LOADS which violate W^X. + * Userland (meaning crt0 or ld.so) will repair those regions. + */ if ((ph->p_flags & (PF_X | PF_W)) != (PF_X | PF_W) && - (ph->p_flags & PF_OPENBSD_MUTABLE) == 0) + ((ph->p_flags & PF_OPENBSD_MUTABLE) == 0) && + ((flags & VMCMD_TEXTREL) == 0 && (ph->p_flags & PF_X) == 0)) flags |= VMCMD_IMMUTABLE; msize = ph->p_memsz + diff; @@ -482,7 +486,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, names = 0; + int error, i, has_phdr = 0, names = 0, textrel = 0; char *interp = NULL; u_long phsize; size_t randomizequota = ELF_RANDOMIZE_LIMIT; @@ -543,6 +547,15 @@ 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 ((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; + if (eh->e_type == ET_DYN) { /* need phdr and load sections for PIE */ if (!has_phdr || base_ph == NULL) { @@ -551,16 +564,39 @@ exec_elf_makecmds(struct proc *p, struct exec_package *epp) } /* randomize exe_base for PIE */ exe_base = uvm_map_pie(base_ph->p_align); - } - /* - * 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 ((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; + /* + * Check if DYNAMIC contains DT_TEXTREL + */ + for (i = 0, pp = ph; i < eh->e_phnum; i++, pp++) { + Elf32_Dyn *dt; + int j; + + switch (pp->p_type) { + case PT_DYNAMIC: + if (pp->p_filesz > 64*1024) + break; + dt = malloc(pp->p_filesz, M_TEMP, M_WAITOK); + error = vn_rdwr(UIO_READ, epp->ep_vp, + (caddr_t)dt, pp->p_filesz, pp->p_offset, + UIO_SYSSPACE, IO_UNIT, p->p_ucred, NULL, p); + if (error) { + free(dt, M_TEMP, pp->p_filesz); + break; + } + for (j = 0; j * sizeof(*dt) < pp->p_filesz; j++) { + if (dt[j].d_tag == DT_TEXTREL) { + textrel = VMCMD_TEXTREL; + break; + } + } + free(dt, M_TEMP, pp->p_filesz); + break; + default: + break; + } + } + } /* * Load all the necessary sections @@ -598,7 +634,7 @@ exec_elf_makecmds(struct proc *p, struct exec_package *epp) * for DATA_PLT, is fine for TEXT_PLT. */ elf_load_psection(&epp->ep_vmcmds, epp->ep_vp, - pp, &addr, &size, &prot, flags | syscall); + pp, &addr, &size, &prot, flags | textrel | syscall); /* * Update exe_base in case alignment was off. diff --git a/sys/sys/exec.h b/sys/sys/exec.h index 2e410c0f7e8..40c71732d6a 100644 --- a/sys/sys/exec.h +++ b/sys/sys/exec.h @@ -1,4 +1,4 @@ -/* $OpenBSD: exec.h,v 1.49 2022/10/21 18:10:52 deraadt Exp $ */ +/* $OpenBSD: exec.h,v 1.50 2022/10/27 22:48:17 deraadt Exp $ */ /* $NetBSD: exec.h,v 1.59 1996/02/09 18:25:09 christos Exp $ */ /*- @@ -94,6 +94,7 @@ struct exec_vmcmd { #define VMCMD_STACK 0x0004 /* create with UVM_FLAG_STACK */ #define VMCMD_SYSCALL 0x0008 /* create with UVM_FLAG_SYSCALL */ #define VMCMD_IMMUTABLE 0x0010 /* create with UVM_ET_IMMUTABLE */ +#define VMCMD_TEXTREL 0x0020 /* terrible binary contains terrible textrel */ }; #define EXEC_DEFAULT_VMCMD_SETSIZE 12 /* # of cmds in set to start */