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);