diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 2016-05-30 21:31:31 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 2016-05-30 21:31:31 +0000 |
commit | 19cbe43a59839a6617d12978da003ac9863407f3 (patch) | |
tree | 27d26f790d5dbb1249d48369e6294d0a27c44837 | |
parent | 31a77d86aebee5bb9ee927869a2f82b112b8978b (diff) |
Identify W^X labelled binaries at execve() time based upon WX_OPENBSD_WXNEEDED
flag set by ld -zwxneeded. Such binaries are allowed to run only on wxallowed
mountpoints. They do not report mmap/mprotect problems.
Rate limit mmap/mprotect reports from other binaries.
These semantics are chosen to encourage progress in the ports ecosystem,
without overwhelming the developers who work in the area.
ok sthen kettenis
-rw-r--r-- | sys/kern/exec_elf.c | 20 | ||||
-rw-r--r-- | sys/kern/kern_exec.c | 5 | ||||
-rw-r--r-- | sys/sys/exec.h | 3 | ||||
-rw-r--r-- | sys/sys/proc.h | 5 | ||||
-rw-r--r-- | sys/uvm/uvm_mmap.c | 36 |
5 files changed, 48 insertions, 21 deletions
diff --git a/sys/kern/exec_elf.c b/sys/kern/exec_elf.c index f0093ea45fd..2bf3ce991ec 100644 --- a/sys/kern/exec_elf.c +++ b/sys/kern/exec_elf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: exec_elf.c,v 1.123 2016/05/30 21:25:48 deraadt Exp $ */ +/* $OpenBSD: exec_elf.c,v 1.124 2016/05/30 21:31:29 deraadt Exp $ */ /* * Copyright (c) 1996 Per Fogelstrom @@ -76,6 +76,7 @@ #include <sys/namei.h> #include <sys/vnode.h> #include <sys/core.h> +#include <sys/syslog.h> #include <sys/exec.h> #include <sys/exec_elf.h> #include <sys/file.h> @@ -880,6 +881,23 @@ ELFNAME(os_pt_note)(struct proc *p, struct exec_package *epp, Elf_Ehdr *eh, goto out1; for (ph = hph; ph < &hph[eh->e_phnum]; ph++) { + if (ph->p_type == PT_OPENBSD_WXNEEDED) { + int wxallowed = (epp->ep_vp->v_mount && + (epp->ep_vp->v_mount->mnt_flag & MNT_WXALLOWED)); + + if (!wxallowed) { + log(LOG_NOTICE, + "%s(%d): W^X binary outside wxallowed mountpoint\n", + epp->ep_name, p->p_pid); + error = ENOEXEC; + goto out1; + } + epp->ep_flags |= EXEC_WXNEEDED; + break; + } + } + + 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) diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index 694015e9617..87af7e4f4c7 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_exec.c,v 1.180 2016/05/30 21:25:48 deraadt Exp $ */ +/* $OpenBSD: kern_exec.c,v 1.181 2016/05/30 21:31:29 deraadt Exp $ */ /* $NetBSD: kern_exec.c,v 1.75 1996/02/09 18:59:28 christos Exp $ */ /*- @@ -707,6 +707,9 @@ sys_execve(struct proc *p, void *v, register_t *retval) if ((pack.ep_flags & EXEC_HASFD) && pack.ep_fd < 255) p->p_descfd = pack.ep_fd; + if (pack.ep_flags & EXEC_WXNEEDED) + p->p_p->ps_flags |= PS_WXNEEDED; + /* * Call exec hook. Emulation code may NOT store reference to anything * from &pack. diff --git a/sys/sys/exec.h b/sys/sys/exec.h index 87b4aedbd01..cd0a8c48c3d 100644 --- a/sys/sys/exec.h +++ b/sys/sys/exec.h @@ -1,4 +1,4 @@ -/* $OpenBSD: exec.h,v 1.33 2016/05/30 21:25:48 deraadt Exp $ */ +/* $OpenBSD: exec.h,v 1.34 2016/05/30 21:31:27 deraadt Exp $ */ /* $NetBSD: exec.h,v 1.59 1996/02/09 18:25:09 christos Exp $ */ /*- @@ -142,6 +142,7 @@ struct exec_package { #define EXEC_HASARGL 0x0004 /* has fake args vector */ #define EXEC_SKIPARG 0x0008 /* don't copy user-supplied argv[0] */ #define EXEC_DESTR 0x0010 /* destructive ops performed */ +#define EXEC_WXNEEDED 0x0020 /* executable will violate W^X */ #ifdef _KERNEL /* diff --git a/sys/sys/proc.h b/sys/sys/proc.h index 143a2e477a0..9b5263ec889 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -1,4 +1,4 @@ -/* $OpenBSD: proc.h,v 1.222 2016/05/30 21:25:48 deraadt Exp $ */ +/* $OpenBSD: proc.h,v 1.223 2016/05/30 21:31:27 deraadt Exp $ */ /* $NetBSD: proc.h,v 1.44 1996/04/22 01:23:21 christos Exp $ */ /*- @@ -190,6 +190,8 @@ struct process { struct rusage ps_cru; /* sum of stats for reaped children */ struct itimerval ps_timer[3]; /* timers, indexed by ITIMER_* */ + u_int64_t ps_wxcounter; + /* End area that is zeroed on creation. */ #define ps_endzero ps_startcopy @@ -259,6 +261,7 @@ struct process { #define PS_ZOMBIE 0x00040000 /* Dead and ready to be waited for */ #define PS_NOBROADCASTKILL 0x00080000 /* Process excluded from kill -1. */ #define PS_PLEDGE 0x00100000 /* Has called pledge(2) */ +#define PS_WXNEEDED 0x00200000 /* Process may violate W^X */ #define PS_BITS \ ("\20" "\01CONTROLT" "\02EXEC" "\03INEXEC" "\04EXITING" "\05SUGID" \ diff --git a/sys/uvm/uvm_mmap.c b/sys/uvm/uvm_mmap.c index 9aa0d2d08ca..171eaa2f228 100644 --- a/sys/uvm/uvm_mmap.c +++ b/sys/uvm/uvm_mmap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uvm_mmap.c,v 1.128 2016/05/30 21:25:48 deraadt Exp $ */ +/* $OpenBSD: uvm_mmap.c,v 1.129 2016/05/30 21:31:30 deraadt Exp $ */ /* $NetBSD: uvm_mmap.c,v 1.49 2001/02/18 21:19:08 chs Exp $ */ /* @@ -312,30 +312,32 @@ int uvm_wxabort; * W^X violations are only allowed on permitted filesystems. */ static inline int -uvm_wxcheck(struct proc *p) +uvm_wxcheck(struct proc *p, char *call) { #if (defined(__mips64__) || defined(__hppa)) /* XXX got/plt repairs still needed */ return 0; #endif - int mpwx = (p->p_p->ps_textvp->v_mount && + int wxallowed = (p->p_p->ps_textvp->v_mount && (p->p_p->ps_textvp->v_mount->mnt_flag & MNT_WXALLOWED)); - if (!mpwx) { + if (wxallowed && (p->p_p->ps_flags & PS_WXNEEDED)) + return (0); + + /* Report W^X failures, and potentially SIGABRT */ + if (p->p_p->ps_wxcounter++ == 0) + log(LOG_NOTICE, "%s(%d): %s W^X violation\n", + p->p_comm, p->p_pid, call); + if (uvm_wxabort) { struct sigaction sa; - log(LOG_NOTICE, "%s(%d): mmap W^X violation\n", - p->p_comm, p->p_pid); - if (uvm_wxabort) { - /* Send uncatchable SIGABRT for coredump */ - memset(&sa, 0, sizeof sa); - sa.sa_handler = SIG_DFL; - setsigvec(p, SIGABRT, &sa); - psignal(p, SIGABRT); - } - return (ENOTSUP); + /* Send uncatchable SIGABRT for coredump */ + memset(&sa, 0, sizeof sa); + sa.sa_handler = SIG_DFL; + setsigvec(p, SIGABRT, &sa); + psignal(p, SIGABRT); } - return (0); + return (0); /* ENOTSUP later */ } /* @@ -385,7 +387,7 @@ sys_mmap(struct proc *p, void *v, register_t *retval) if ((prot & PROT_MASK) != prot) return (EINVAL); if ((prot & (PROT_WRITE | PROT_EXEC)) == (PROT_WRITE | PROT_EXEC) && - (error = uvm_wxcheck(p))) + (error = uvm_wxcheck(p, "mmap"))) return (error); if ((flags & MAP_FLAGMASK) != flags) @@ -702,7 +704,7 @@ sys_mprotect(struct proc *p, void *v, register_t *retval) if ((prot & PROT_MASK) != prot) return (EINVAL); if ((prot & (PROT_WRITE | PROT_EXEC)) == (PROT_WRITE | PROT_EXEC) && - (error = uvm_wxcheck(p))) + (error = uvm_wxcheck(p, "mprotect"))) return (error); error = pledge_protexec(p, prot); |