summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorderaadt <deraadt@openbsd.org>2016-05-30 21:31:27 +0000
committerderaadt <deraadt@openbsd.org>2016-05-30 21:31:27 +0000
commitf68ce5659e4a5410db8ebed33ede54310ed851e5 (patch)
tree2f32fe9273489ab6f407045376970c48792f7296 /sys
parentbackout to insert correct commit message (diff)
downloadwireguard-openbsd-f68ce5659e4a5410db8ebed33ede54310ed851e5.tar.xz
wireguard-openbsd-f68ce5659e4a5410db8ebed33ede54310ed851e5.zip
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
Diffstat (limited to 'sys')
-rw-r--r--sys/kern/exec_elf.c20
-rw-r--r--sys/kern/kern_exec.c5
-rw-r--r--sys/sys/exec.h3
-rw-r--r--sys/sys/proc.h5
-rw-r--r--sys/uvm/uvm_mmap.c36
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);