A few developers are starting to push for some W^X compliance in
the ports tree.
The following diff is in snapshots. In the near future, different
versions of this diff with different semantics may be show up in
other snapshots. The purpose of this change in snapshots is to
help developers establish priorities as to what they try to get
repaired first.
This is a very lightly restrictice policy which will provide alerts
about programs which perform W^X violations. Those alerts are rate
limited. If sysctl kern.wxabort=1, then the processes are killed,
typically generating a core file.
Upon seeing messages like this some of you may feel like you need to
report the problem. Please do not complain to the ports group; they
will already be aware of the problem, and will become overwhelmed.
If anyone decides to engage an upstream developer about their software
performing W^X violations, please be respectful, detailed, and calm.
The major W^X violators which remain are not simple pieces of
software, and their authors will not make improvements in this area in
a fortnight. It is going to take a lot of patience.
At least with these changes we bring the scope of the problem to light,
and hopefully find some upstreams who agree to improve.
Index: sys/exec.h
===================================================================
RCS file: /cvs/src/sys/sys/exec.h,v
retrieving revision 1.31
diff -u -p -u -r1.31 exec.h
--- sys/exec.h 28 Sep 2015 20:32:59 -0000 1.31
+++ sys/exec.h 28 May 2016 16:24:56 -0000
@@ -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
/*
Index: sys/proc.h
===================================================================
RCS file: /cvs/src/sys/sys/proc.h,v
retrieving revision 1.220
diff -u -p -u -r1.220 proc.h
--- sys/proc.h 10 May 2016 18:39:53 -0000 1.220
+++ sys/proc.h 29 May 2016 16:30:27 -0000
@@ -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" \
Index: kern/exec_elf.c
===================================================================
RCS file: /cvs/src/sys/kern/exec_elf.c,v
retrieving revision 1.121
diff -u -p -u -r1.121 exec_elf.c
--- kern/exec_elf.c 10 May 2016 18:39:51 -0000 1.121
+++ kern/exec_elf.c 28 May 2016 16:23:33 -0000
@@ -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>
@@ -878,6 +879,23 @@ ELFNAME(os_pt_note)(struct proc *p, stru
if ((error = ELFNAME(read_from)(p, epp->ep_vp, eh->e_phoff,
(caddr_t)hph, phsize)) != 0)
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 ||
Index: kern/kern_exec.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_exec.c,v
retrieving revision 1.178
diff -u -p -u -r1.178 kern_exec.c
--- kern/kern_exec.c 23 May 2016 20:11:47 -0000 1.178
+++ kern/kern_exec.c 28 May 2016 16:19:21 -0000
@@ -707,6 +707,9 @@ sys_execve(struct proc *p, void *v, regi
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.
Index: uvm/uvm_mmap.c
===================================================================
RCS file: /cvs/src/sys/uvm/uvm_mmap.c,v
retrieving revision 1.126
diff -u -p -u -r1.126 uvm_mmap.c
--- uvm/uvm_mmap.c 27 May 2016 19:45:04 -0000 1.126
+++ uvm/uvm_mmap.c 29 May 2016 16:32:40 -0000
@@ -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, regist
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, re
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);