Current-Users archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: W^X mmap
Hi,
On 10/12/2016 14:02, Michael van Elst wrote:
coypu%SDF.ORG@localhost writes:
Why doesn't the following code get rejected by pax mprotect?
a = mmap(NULL, BUFSIZ, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANON, -1, 2);
It gets 'rejected' by silently dropping the PROT_EXEC flag.
I find this awful: programs trying to use e.g JIT will fail to detect
that it really is not supported, and crash later instead.
I am attaching here a patch returning errors instead.
Thanks to this patch, www/firefox works without having to set the "m:
mprotect(2) restrictions, explicit disable" flag on its executable
binaries (tested on netbsd-7/amd64).
POSIX would require mmap to fail with errno = EACCES.
In the patch attached I have used ENOTSUP, because this is what OpenBSD
seems to be using:
http://man.openbsd.org/mmap.2
I also think EACCES (or EPERM?) would be better though, so I will be
happy to replace it if considered more appropriate.
I have changed the logic deciding which flags to drop. It used to be,
independently of whether PROT_READ is set:
- if PROT_WRITE, or PROT_WRITE and PROT_EXECUTE are set, then execution
is silently denied;
- otherwise, writing is silently denied.
(which doesn't make much sense to me)
Now there would be only one case instead:
- if PROT_WRITE and PROT_EXECUTE are set, execution is denied and an
error is returned.
Another thing I will really need to know before committing this, is
whether the changes should really be applied to sys_mmap() only.
Finally, I left a XXX where there might be a side-effect, if applied in
sys/kern/exec_subr.c, after calling vn_rdwr().
Cheers,
--
khorben
diff --git a/sys/kern/exec_subr.c b/sys/kern/exec_subr.c
index efd0b5e..b523288 100644
--- a/sys/kern/exec_subr.c
+++ b/sys/kern/exec_subr.c
@@ -185,7 +185,9 @@ vmcmd_map_pagedvn(struct lwp *l, struct exec_vmcmd *cmd)
prot = cmd->ev_prot;
maxprot = UVM_PROT_ALL;
#ifdef PAX_MPROTECT
- pax_mprotect(l, &prot, &maxprot);
+ error = pax_mprotect(l, &prot, &maxprot);
+ if (error)
+ return error;
#endif /* PAX_MPROTECT */
/*
@@ -267,7 +269,10 @@ vmcmd_readvn(struct lwp *l, struct exec_vmcmd *cmd)
prot = cmd->ev_prot;
maxprot = VM_PROT_ALL;
#ifdef PAX_MPROTECT
- pax_mprotect(l, &prot, &maxprot);
+ /* XXX side-effects with vn_rdwr()? */
+ error = pax_mprotect(l, &prot, &maxprot);
+ if (error)
+ return error;
#endif /* PAX_MPROTECT */
#ifdef PMAP_NEED_PROCWR
@@ -327,7 +332,9 @@ vmcmd_map_zero(struct lwp *l, struct exec_vmcmd *cmd)
prot = cmd->ev_prot;
maxprot = UVM_PROT_ALL;
#ifdef PAX_MPROTECT
- pax_mprotect(l, &prot, &maxprot);
+ error = pax_mprotect(l, &prot, &maxprot);
+ if (error)
+ return error;
#endif /* PAX_MPROTECT */
error = uvm_map(&p->p_vmspace->vm_map, &cmd->ev_addr,
diff --git a/sys/kern/kern_pax.c b/sys/kern/kern_pax.c
index 2b1bc12..e84838a 100644
--- a/sys/kern/kern_pax.c
+++ b/sys/kern/kern_pax.c
@@ -263,26 +263,28 @@ pax_init(void)
}
#ifdef PAX_MPROTECT
-void
+int
pax_mprotect(struct lwp *l, vm_prot_t *prot, vm_prot_t *maxprot)
{
uint32_t f;
if (!pax_mprotect_enabled)
- return;
+ return 0;
f = l->l_proc->p_pax;
if ((pax_mprotect_global && (f & ELF_NOTE_PAX_NOMPROTECT) != 0) ||
(!pax_mprotect_global && (f & ELF_NOTE_PAX_MPROTECT) == 0))
- return;
+ return 0;
- if ((*prot & (VM_PROT_WRITE|VM_PROT_EXECUTE)) != VM_PROT_EXECUTE) {
+ if ((*prot & (VM_PROT_WRITE|VM_PROT_EXECUTE))
+ == (VM_PROT_WRITE|VM_PROT_EXECUTE)) {
*prot &= ~VM_PROT_EXECUTE;
*maxprot &= ~VM_PROT_EXECUTE;
- } else {
- *prot &= ~VM_PROT_WRITE;
- *maxprot &= ~VM_PROT_WRITE;
+ log(LOG_ALERT, "PaX MPROTECT: [%d] Enforcing W^X\n",
+ l->l_proc->p_pid);
+ return ENOTSUP;
}
+ return 0;
}
#endif /* PAX_MPROTECT */
diff --git a/sys/sys/pax.h b/sys/sys/pax.h
index 0c28b46..e8b1d13 100644
--- a/sys/sys/pax.h
+++ b/sys/sys/pax.h
@@ -47,7 +47,7 @@ struct vmspace;
void pax_init(void);
-void pax_mprotect(struct lwp *, vm_prot_t *, vm_prot_t *);
+int pax_mprotect(struct lwp *, vm_prot_t *, vm_prot_t *);
int pax_segvguard(struct lwp *, struct vnode *, const char *, bool);
#define PAX_ASLR_DELTA(delta, lsb, len) \
diff --git a/sys/uvm/uvm_mmap.c b/sys/uvm/uvm_mmap.c
index 8043f0f..5291ab5 100644
--- a/sys/uvm/uvm_mmap.c
+++ b/sys/uvm/uvm_mmap.c
@@ -416,7 +416,10 @@ sys_mmap(struct lwp *l, const struct sys_mmap_args *uap, register_t *retval)
}
#ifdef PAX_MPROTECT
- pax_mprotect(l, &prot, &maxprot);
+ error = pax_mprotect(l, &prot, &maxprot);
+ if (error) {
+ goto out;
+ }
#endif /* PAX_MPROTECT */
#ifdef PAX_ASLR
diff --git a/sys/uvm/uvm_unix.c b/sys/uvm/uvm_unix.c
index 7ac5579..b6d1c7e 100644
--- a/sys/uvm/uvm_unix.c
+++ b/sys/uvm/uvm_unix.c
@@ -103,7 +103,11 @@ sys_obreak(struct lwp *l, const struct sys_obreak_args *uap, register_t *retval)
vm_prot_t maxprot = UVM_PROT_ALL;
#ifdef PAX_MPROTECT
- pax_mprotect(l, &prot, &maxprot);
+ error = pax_mprotect(l, &prot, &maxprot);
+ if (error) {
+ mutex_exit(&p->p_auxlock);
+ return (error);
+ }
#endif /* PAX_MPROTECT */
error = uvm_map(&vm->vm_map, &old, new - old, NULL,
Home |
Main Index |
Thread Index |
Old Index