diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 2016-05-27 19:45:05 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 2016-05-27 19:45:05 +0000 |
commit | 78b5afaf3f7a760112fbfce28204da6440738775 (patch) | |
tree | 0a7f3cad12fe378e14e0b60deee9ab6a5bcd3e7d /sys | |
parent | 7460ea7c8796fa4a440ed3fc75c19fe120c96c5d (diff) |
W^X violations are no longer permitted by default. A kernel log message
is generated, and mprotect/mmap return ENOTSUP. If the sysctl(8) flag
kern.wxabort is set then a SIGABRT occurs instead, for gdb use or coredump
creation.
W^X violating programs can be permitted on a ffs/nfs filesystem-basis,
using the "wxallowed" mount option. One day far in the future
upstream software developers will understand that W^X violations are a
tremendously risky practice and that style of programming will be
banished outright. Until then, we recommend most users need to use the
wxallowed option on their /usr/local filesystem. At least your other
filesystems don't permit such programs.
ok jca kettenis mlarkin natano
Diffstat (limited to 'sys')
-rw-r--r-- | sys/kern/kern_sysctl.c | 5 | ||||
-rw-r--r-- | sys/kern/vfs_syscalls.c | 6 | ||||
-rw-r--r-- | sys/sys/mount.h | 3 | ||||
-rw-r--r-- | sys/sys/sysctl.h | 6 | ||||
-rw-r--r-- | sys/uvm/uvm_mmap.c | 42 |
5 files changed, 53 insertions, 9 deletions
diff --git a/sys/kern/kern_sysctl.c b/sys/kern/kern_sysctl.c index b3c854376fe..24c783637e2 100644 --- a/sys/kern/kern_sysctl.c +++ b/sys/kern/kern_sysctl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_sysctl.c,v 1.304 2016/05/23 15:59:19 deraadt Exp $ */ +/* $OpenBSD: kern_sysctl.c,v 1.305 2016/05/27 19:45:04 deraadt Exp $ */ /* $NetBSD: kern_sysctl.c,v 1.17 1996/05/20 17:49:05 mrg Exp $ */ /*- @@ -278,6 +278,7 @@ kern_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, extern int usermount, nosuidcoredump; extern int maxlocksperuid; extern int pool_debug; + extern int uvm_wxabort; /* all sysctl names at this level are terminal except a ton of them */ if (namelen != 1) { @@ -590,6 +591,8 @@ kern_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, } return(0); } + case KERN_WXABORT: + return (sysctl_int(oldp, oldlenp, newp, newlen, &uvm_wxabort)); case KERN_CONSDEV: if (cn_tab != NULL) dev = cn_tab->cn_dev; diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index 7a0aa126a59..6798f32f8a5 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vfs_syscalls.c,v 1.254 2016/05/15 05:04:28 semarie Exp $ */ +/* $OpenBSD: vfs_syscalls.c,v 1.255 2016/05/27 19:45:04 deraadt Exp $ */ /* $NetBSD: vfs_syscalls.c,v 1.71 1996/04/23 10:29:02 mycroft Exp $ */ /* @@ -252,10 +252,10 @@ update: mp->mnt_flag |= MNT_RDONLY; else if (mp->mnt_flag & MNT_RDONLY) mp->mnt_flag |= MNT_WANTRDWR; - mp->mnt_flag &=~ (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | + mp->mnt_flag &=~ (MNT_NOSUID | MNT_NOEXEC | MNT_WXALLOWED | MNT_NODEV | MNT_SYNCHRONOUS | MNT_ASYNC | MNT_SOFTDEP | MNT_NOATIME | MNT_FORCE); - mp->mnt_flag |= flags & (MNT_NOSUID | MNT_NOEXEC | + mp->mnt_flag |= flags & (MNT_NOSUID | MNT_NOEXEC | MNT_WXALLOWED | MNT_NODEV | MNT_SYNCHRONOUS | MNT_ASYNC | MNT_SOFTDEP | MNT_NOATIME | MNT_FORCE); /* diff --git a/sys/sys/mount.h b/sys/sys/mount.h index 7e55c0e8162..2ab1cc7821a 100644 --- a/sys/sys/mount.h +++ b/sys/sys/mount.h @@ -1,4 +1,4 @@ -/* $OpenBSD: mount.h,v 1.125 2016/05/25 13:31:44 deraadt Exp $ */ +/* $OpenBSD: mount.h,v 1.126 2016/05/27 19:45:04 deraadt Exp $ */ /* $NetBSD: mount.h,v 1.48 1996/02/18 11:55:47 fvdl Exp $ */ /* @@ -369,6 +369,7 @@ struct mount { #define MNT_NOSUID 0x00000008 /* don't honor setuid bits on fs */ #define MNT_NODEV 0x00000010 /* don't interpret special files */ #define MNT_ASYNC 0x00000040 /* file system written asynchronously */ +#define MNT_WXALLOWED 0x00000800 /* filesystem allows W|X mappings */ /* * exported mount flags. diff --git a/sys/sys/sysctl.h b/sys/sys/sysctl.h index 9f01bc20c50..04ec9e8fcbd 100644 --- a/sys/sys/sysctl.h +++ b/sys/sys/sysctl.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sysctl.h,v 1.162 2016/05/23 15:48:57 deraadt Exp $ */ +/* $OpenBSD: sysctl.h,v 1.163 2016/05/27 19:45:04 deraadt Exp $ */ /* $NetBSD: sysctl.h,v 1.16 1996/04/09 20:55:36 cgd Exp $ */ /* @@ -174,7 +174,7 @@ struct ctlname { #define KERN_CPTIME2 71 /* array: cp_time2 */ #define KERN_CACHEPCT 72 /* buffer cache % of physmem */ #define KERN_FILE 73 /* struct: file entries */ -/* was KERN_RTHREADS 74 */ +#define KERN_WXABORT 74 /* int: w^x sigabrt & core */ #define KERN_CONSDEV 75 /* dev_t: console terminal device */ #define KERN_NETLIVELOCKS 76 /* int: number of network livelocks */ #define KERN_POOL_DEBUG 77 /* int: enable pool_debug */ @@ -261,7 +261,7 @@ struct ctlname { { "cp_time2", CTLTYPE_STRUCT }, \ { "bufcachepercent", CTLTYPE_INT }, \ { "file", CTLTYPE_STRUCT }, \ - { "gap", 0 }, \ + { "wxabort", CTLTYPE_INT }, \ { "consdev", CTLTYPE_STRUCT }, \ { "netlivelocks", CTLTYPE_INT }, \ { "pool_debug", CTLTYPE_INT }, \ diff --git a/sys/uvm/uvm_mmap.c b/sys/uvm/uvm_mmap.c index e5651310afc..0ac5a9ea325 100644 --- a/sys/uvm/uvm_mmap.c +++ b/sys/uvm/uvm_mmap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uvm_mmap.c,v 1.125 2016/05/11 21:52:51 deraadt Exp $ */ +/* $OpenBSD: uvm_mmap.c,v 1.126 2016/05/27 19:45:04 deraadt Exp $ */ /* $NetBSD: uvm_mmap.c,v 1.49 2001/02/18 21:19:08 chs Exp $ */ /* @@ -62,6 +62,7 @@ #include <sys/vnode.h> #include <sys/conf.h> #include <sys/signalvar.h> +#include <sys/syslog.h> #include <sys/stat.h> #include <sys/specdev.h> #include <sys/stdint.h> @@ -305,6 +306,38 @@ sys_mincore(struct proc *p, void *v, register_t *retval) return (error); } +int uvm_wxabort; + +/* + * W^X violations are only allowed on permitted filesystems. + */ +static inline int +uvm_wxcheck(struct proc *p) +{ +#if (defined(__mips64__) || defined(__hppa)) + /* XXX got/plt repairs still needed */ + return 0; +#endif + int mpwx = (p->p_p->ps_textvp->v_mount && + (p->p_p->ps_textvp->v_mount->mnt_flag & MNT_WXALLOWED)); + + if (!mpwx) { + 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); + } + return (0); +} + /* * sys_mmap: mmap system call. * @@ -351,6 +384,10 @@ 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))) + return (error); + if ((flags & MAP_FLAGMASK) != flags) return (EINVAL); if (flags & MAP_OLDCOPY) @@ -664,6 +701,9 @@ 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))) + return (error); error = pledge_protexec(p, prot); if (error) |