diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 2019-11-29 06:34:47 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 2019-11-29 06:34:47 +0000 |
commit | f67b268725d23fd3229f73b136ba575514edf1a1 (patch) | |
tree | 707fd46fa1309120b07da0ff3342c12297961096 /sys/kern | |
parent | 6760a6095c934a222278e6d1c4e2209b9b96f736 (diff) |
Repurpose the "syscalls must be on a writeable page" mechanism to
enforce a new policy: system calls must be in pre-registered regions.
We have discussed more strict checks than this, but none satisfy the
cost/benefit based upon our understanding of attack methods, anyways
let's see what the next iteration looks like.
This is intended to harden (translation: attackers must put extra
effort into attacking) against a mixture of W^X failures and JIT bugs
which allow syscall misinterpretation, especially in environments with
polymorphic-instruction/variable-sized instructions. It fits in a bit
with libc/libcrypto/ld.so random relink on boot and no-restart-at-crash
behaviour, particularily for remote problems. Less effective once on-host
since someone the libraries can be read.
For static-executables the kernel registers the main program's
PIE-mapped exec section valid, as well as the randomly-placed sigtramp
page. For dynamic executables ELF ld.so's exec segment is also
labelled valid; ld.so then has enough information to register libc's
exec section as valid via call-once msyscall(2)
For dynamic binaries, we continue to to permit the main program exec
segment because "go" (and potentially a few other applications) have
embedded system calls in the main program. Hopefully at least go gets
fixed soon.
We declare the concept of embedded syscalls a bad idea for numerous
reasons, as we notice the ecosystem has many of
static-syscall-in-base-binary which are dynamically linked against
libraries which in turn use libc, which contains another set of
syscall stubs. We've been concerned about adding even one additional
syscall entry point... but go's approach tends to double the entry-point
attack surface.
This was started at a nano-hackathon in Bob Beck's basement 2 weeks
ago during a long discussion with mortimer trying to hide from the SSL
scream-conversations, and finished in more comfortable circumstances
next to a wood-stove at Elk Lakes cabin with UVM scream-conversations.
ok guenther kettenis mortimer, lots of feedback from others
conversations about go with jsing tb sthen
Diffstat (limited to 'sys/kern')
-rw-r--r-- | sys/kern/exec_elf.c | 17 | ||||
-rw-r--r-- | sys/kern/exec_subr.c | 7 | ||||
-rw-r--r-- | sys/kern/init_main.c | 5 | ||||
-rw-r--r-- | sys/kern/kern_exec.c | 4 |
4 files changed, 25 insertions, 8 deletions
diff --git a/sys/kern/exec_elf.c b/sys/kern/exec_elf.c index 24adf0dbed6..87f0a4583c8 100644 --- a/sys/kern/exec_elf.c +++ b/sys/kern/exec_elf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: exec_elf.c,v 1.151 2019/05/13 19:21:31 bluhm Exp $ */ +/* $OpenBSD: exec_elf.c,v 1.152 2019/11/29 06:34:45 deraadt Exp $ */ /* * Copyright (c) 1996 Per Fogelstrom @@ -456,7 +456,7 @@ elf_load_file(struct proc *p, char *path, struct exec_package *epp, addr = ph[i].p_vaddr - base_ph->p_vaddr; } elf_load_psection(&epp->ep_vmcmds, nd.ni_vp, - &ph[i], &addr, &size, &prot, flags); + &ph[i], &addr, &size, &prot, flags | VMCMD_SYSCALL); /* If entry is within this section it must be text */ if (eh.e_entry >= ph[i].p_vaddr && eh.e_entry < (ph[i].p_vaddr + size)) { @@ -621,6 +621,19 @@ 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() + */ + p->p_vmspace->vm_map.flags |= VM_MAP_SYSCALL_ONCE; + } /* * Calculates size of text and data segments diff --git a/sys/kern/exec_subr.c b/sys/kern/exec_subr.c index f32be4bddf4..0a1bad77f12 100644 --- a/sys/kern/exec_subr.c +++ b/sys/kern/exec_subr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: exec_subr.c,v 1.56 2019/06/21 09:39:48 visa Exp $ */ +/* $OpenBSD: exec_subr.c,v 1.57 2019/11/29 06:34:45 deraadt Exp $ */ /* $NetBSD: exec_subr.c,v 1.9 1994/12/04 03:10:42 mycroft Exp $ */ /* @@ -167,6 +167,7 @@ vmcmd_map_pagedvn(struct proc *p, struct exec_vmcmd *cmd) * call this routine. */ struct uvm_object *uobj; + unsigned int syscalls = 0; int error; /* @@ -193,11 +194,13 @@ vmcmd_map_pagedvn(struct proc *p, struct exec_vmcmd *cmd) /* * do the map */ + if ((cmd->ev_flags & VMCMD_SYSCALL) && (cmd->ev_prot & PROT_EXEC)) + syscalls |= UVM_FLAG_SYSCALL; error = uvm_map(&p->p_vmspace->vm_map, &cmd->ev_addr, cmd->ev_len, uobj, cmd->ev_offset, 0, UVM_MAPFLAG(cmd->ev_prot, PROT_MASK, MAP_INHERIT_COPY, - MADV_NORMAL, UVM_FLAG_COPYONW|UVM_FLAG_FIXED)); + MADV_NORMAL, UVM_FLAG_COPYONW | UVM_FLAG_FIXED | syscalls)); /* * check for error diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c index 558d99b28f3..dc03e801b16 100644 --- a/sys/kern/init_main.c +++ b/sys/kern/init_main.c @@ -1,4 +1,4 @@ -/* $OpenBSD: init_main.c,v 1.292 2019/11/04 17:51:22 anton Exp $ */ +/* $OpenBSD: init_main.c,v 1.293 2019/11/29 06:34:45 deraadt Exp $ */ /* $NetBSD: init_main.c,v 1.84.4.1 1996/06/02 09:08:06 mrg Exp $ */ /* @@ -651,7 +651,8 @@ start_init(void *arg) if (uvm_map(&p->p_vmspace->vm_map, &addr, PAGE_SIZE, NULL, UVM_UNKNOWN_OFFSET, 0, UVM_MAPFLAG(PROT_READ | PROT_WRITE, PROT_MASK, MAP_INHERIT_COPY, - MADV_NORMAL, UVM_FLAG_FIXED|UVM_FLAG_OVERLAY|UVM_FLAG_COPYONW|UVM_FLAG_STACK))) + MADV_NORMAL, + UVM_FLAG_FIXED|UVM_FLAG_OVERLAY|UVM_FLAG_COPYONW|UVM_FLAG_STACK|UVM_FLAG_SYSCALL))) panic("init: couldn't allocate argument space"); for (pathp = &initpaths[0]; (path = *pathp) != NULL; pathp++) { diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index b71c8a9843c..3af40a9a400 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_exec.c,v 1.209 2019/11/05 08:18:47 mpi Exp $ */ +/* $OpenBSD: kern_exec.c,v 1.210 2019/11/29 06:34:45 deraadt Exp $ */ /* $NetBSD: kern_exec.c,v 1.75 1996/02/09 18:59:28 christos Exp $ */ /*- @@ -856,7 +856,7 @@ exec_sigcode_map(struct process *pr, struct emul *e) if (uvm_map(&pr->ps_vmspace->vm_map, &pr->ps_sigcode, round_page(sz), e->e_sigobject, 0, 0, UVM_MAPFLAG(PROT_READ | PROT_EXEC, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_INHERIT_COPY, - MADV_RANDOM, UVM_FLAG_COPYONW))) { + MADV_RANDOM, UVM_FLAG_COPYONW | UVM_FLAG_SYSCALL))) { uao_detach(e->e_sigobject); return (ENOMEM); } |