untrusted comment: verify with openbsd-79-base.pub RWTSdNN9A3yvWEfNlP0MAvvm7T8p5+RSAZdvhVXGxdubTyTECmmSNRvT2O2Hlss0edqo5PCjvKFEF/gJn+kixLctF8XKGFmdoQ8= OpenBSD 7.9 errata 004, July 16, 2026: Fix some info leaks, kernel crashes, and pinsyscall(8) / kbind(8) locking failures. Apply by doing: signify -Vep /etc/signify/openbsd-79-base.pub -x 004_elf.patch.sig \ -m - | (cd /usr/src && patch -p0) And then rebuild and install a new kernel: KK=`sysctl -n kern.osversion | cut -d# -f1` cd /usr/src/sys/arch/`machine`/compile/$KK make obj make config make make install Index: sys/kern/exec_elf.c =================================================================== RCS file: /cvs/src/sys/kern/exec_elf.c,v diff -u -p -r1.196 exec_elf.c --- sys/kern/exec_elf.c 11 Apr 2026 16:12:40 -0000 1.196 +++ sys/kern/exec_elf.c 10 Jul 2026 11:22:00 -0000 @@ -88,7 +88,6 @@ #include #include -#include #include int elf_load_file(struct proc *, char *, struct exec_package *, @@ -357,7 +356,7 @@ elf_load_file(struct proc *p, char *path } loadmap[ELF_MAX_VALID_PHDR]; int nload, idx = 0; Elf_Addr pos; - int file_align; + Elf_Off file_align = PAGE_SIZE; int loop; size_t randomizequota = ELF_RANDOMIZE_LIMIT; vaddr_t text_start = -1, text_end = 0; @@ -410,11 +409,16 @@ elf_load_file(struct proc *p, char *path loadmap[idx].vaddr = trunc_page(ph[i].p_vaddr); loadmap[idx].memsz = round_page (ph[i].p_vaddr + ph[i].p_memsz - loadmap[idx].vaddr); - file_align = ph[i].p_align; + if (ph[i].p_align > file_align) + file_align = ph[i].p_align; idx++; } } nload = idx; + if (nload == 0) { + error = EINVAL; + goto bad1; + } /* * Load the interpreter where a non-fixed mmap(NULL, ...) @@ -737,10 +741,6 @@ exec_elf_makecmds(struct proc *p, struct } else addr = ELF_NO_ADDR; - /* Static binaries may not call pinsyscalls() */ - if (interp == NULL) - p->p_vmspace->vm_map.flags |= VM_MAP_PINSYSCALL_ONCE; - /* * Calculates size of text and data segments * by starting at first and going to end of last. @@ -943,17 +943,19 @@ exec_elf_fixup(struct proc *p, struct ex struct elf_args *ap; AuxInfo ai[ELF_AUX_ENTRIES], *a; + interp = epp->ep_interp; + + /* disable kbind() and pinsyscalls() in programs that don't use ld.so */ + if (interp == NULL) { + p->p_p->ps_kbind_addr = BOGO_PC; + p->p_vmspace->vm_map.flags |= VM_MAP_PINSYSCALL_ONCE; + } + ap = epp->ep_args; if (ap == NULL) { return (0); } - interp = epp->ep_interp; - - /* disable kbind in programs that don't use ld.so */ - if (interp == NULL) - p->p_p->ps_kbind_addr = BOGO_PC; - if (interp && (error = elf_load_file(p, interp, epp, ap)) != 0) { free(ap, M_TEMP, sizeof *ap); @@ -1037,7 +1039,7 @@ elf_os_pt_note_name(Elf_Note *np, int *t for (i = 0; i < nitems(elf_note_names); i++) { size_t namlen = strlen(elf_note_names[i].name); - if (np->namesz < namlen) + if (np->namesz <= namlen) continue; /* verify name padding (after the NUL) is NUL */ for (j = namlen + 1; j < elfround(np->namesz); j++) @@ -1095,14 +1097,26 @@ elf_os_pt_note(struct proc *p, struct ex for (offset = 0; offset < ph->p_filesz; offset += total) { Elf_Note *np2 = (Elf_Note *)((char *)np + offset); + size_t remaining = ph->p_filesz - offset; int name, type; - if (offset + sizeof(Elf_Note) > ph->p_filesz) + if (sizeof(Elf_Note) > remaining) + break; + remaining -= sizeof(Elf_Note); + + if (elfround(np2->namesz) < np2->namesz || + elfround(np2->descsz) < np2->descsz) break; + + if (elfround(np2->namesz) > remaining) + break; + remaining -= elfround(np2->namesz); + if (elfround(np2->descsz) > remaining) + break; + remaining -= elfround(np2->descsz); + total = sizeof(Elf_Note) + elfround(np2->namesz) + elfround(np2->descsz); - if (offset + total > ph->p_filesz) - break; name = elf_os_pt_note_name(np2, &type); if (name == ELF_NOTE_NAME_OPENBSD && type == NT_OPENBSD_PROF) @@ -1555,6 +1569,7 @@ coredump_note_elf(struct proc *p, void * notesize = sizeof(nhdr) + elfround(namesize) + elfround(sizeof(intreg)); if (iocookie) { + memset(&intreg, 0, sizeof(intreg)); error = process_read_regs(p, &intreg); if (error) return (error); @@ -1574,6 +1589,7 @@ coredump_note_elf(struct proc *p, void * #ifdef PT_GETFPREGS notesize = sizeof(nhdr) + elfround(namesize) + elfround(sizeof(freg)); if (iocookie) { + memset(&freg, 0, sizeof(freg)); error = process_read_fpregs(p, &freg); if (error) return (error); Index: sys/kern/kern_exec.c =================================================================== RCS file: /cvs/src/sys/kern/kern_exec.c,v diff -u -p -r1.268 kern_exec.c --- sys/kern/kern_exec.c 16 Sep 2025 12:15:06 -0000 1.268 +++ sys/kern/kern_exec.c 10 Jul 2026 11:22:00 -0000 @@ -90,11 +90,31 @@ int exec_sigcode_map(struct process *); int exec_timekeep_map(struct process *); /* + * Free exec-package allocations owned by image-format loaders. + */ +void exec_free_package(struct exec_package *); + +/* * If non-zero, stackgap_random specifies the upper limit of the random gap size * added to the fixed stack position. Must be n^2. */ int stackgap_random = STACKGAP_RANDOM; +void +exec_free_package(struct exec_package *pack) +{ + if (pack->ep_interp != NULL) { + pool_put(&namei_pool, pack->ep_interp); + pack->ep_interp = NULL; + } + free(pack->ep_args, M_TEMP, sizeof(*pack->ep_args)); + pack->ep_args = NULL; + free(pack->ep_pins, M_PINSYSCALL, + pack->ep_npins * sizeof(*pack->ep_pins)); + pack->ep_pins = NULL; + pack->ep_npins = 0; +} + /* * check exec: * given an "executable" described in the exec package's namei info, @@ -222,6 +242,7 @@ check_exec(struct proc *p, struct exec_p * and release their references */ kill_vmcmds(&epp->ep_vmcmds); + exec_free_package(epp); bad2: /* @@ -586,10 +607,7 @@ sys_execve(struct proc *p, void *v, regi atomic_clearbits_int(&pr->ps_flags, PS_PLEDGE); p->p_pledge = 0; pr->ps_pledge = 0; - /* XXX XXX XXX XXX */ - /* Clear our unveil paths out so the child - * starts afresh - */ + /* Clear our unveil paths out so the child starts afresh */ unveil_destroy(pr); pr->ps_uvdone = 0; } @@ -767,10 +785,7 @@ bad: /* fdrelease unlocks p->p_fd. */ (void) fdrelease(p, pack.ep_fd); } - if (pack.ep_interp != NULL) - pool_put(&namei_pool, pack.ep_interp); - free(pack.ep_args, M_TEMP, sizeof *pack.ep_args); - free(pack.ep_pins, M_PINSYSCALL, pack.ep_npins * sizeof(u_int)); + exec_free_package(&pack); /* close and put the exec'd file */ vn_close(pack.ep_vp, FREAD, cred, p); pool_put(&namei_pool, nid.ni_cnd.cn_pnbuf); @@ -790,9 +805,7 @@ exec_abort: * of our namei data and vnode, and exit noting failure */ uvm_unmap(&vm->vm_map, VM_MIN_ADDRESS, VM_MAXUSER_ADDRESS); - if (pack.ep_interp != NULL) - pool_put(&namei_pool, pack.ep_interp); - free(pack.ep_args, M_TEMP, sizeof *pack.ep_args); + exec_free_package(&pack); pool_put(&namei_pool, nid.ni_cnd.cn_pnbuf); vn_close(pack.ep_vp, FREAD, cred, p); km_free(argp, NCARGS, &kv_exec, &kp_pageable);