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

Reply via email to