summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>2016-05-30 21:31:31 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>2016-05-30 21:31:31 +0000
commit19cbe43a59839a6617d12978da003ac9863407f3 (patch)
tree27d26f790d5dbb1249d48369e6294d0a27c44837
parent31a77d86aebee5bb9ee927869a2f82b112b8978b (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.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);