tech-kern archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: PAX mprotect and JIT
On Sat, Feb 25, 2017 at 10:35:27PM +0100, Joerg Sonnenberger wrote:
> (2) A hack for allow mprotect to switch between W and X, but still
> honoring W^X. This is a hack and needs to be carefully rethought,
> since I believe the way pax is currently implemented is wrong. Consider
> it a PoC.
Attached is a new version of the patch. This introduces the new concept
of protection limits. It is the initial permissions of a mapping as
requested by the user (or the driver in case of in-kernel mappings).
mprotect is allowed if the new permissions are allowed for all parts of
the mapping, independent of any restrictions PAX might have added. As
such, RWX mapping requests will result in an effective permission of RW,
but mprotect can be used to turn them into RX later. The test case
depends on the earlier mremap patch and verifies basic operation.
Patch is tested on amd64 so far, other architectures might need a few
more changes for UVM_MAPFLAG.
Joerg
Index: sys/arch/xen/xen/privcmd.c
===================================================================
RCS file: /home/joerg/repo/netbsd/src/sys/arch/xen/xen/privcmd.c,v
retrieving revision 1.49
diff -u -p -r1.49 privcmd.c
--- sys/arch/xen/xen/privcmd.c 17 Oct 2014 16:37:02 -0000 1.49
+++ sys/arch/xen/xen/privcmd.c 24 Mar 2017 15:07:34 -0000
@@ -566,7 +566,7 @@ privcmd_map_obj(struct vm_map *map, vadd
obj->npages = npages;
obj->domid = domid;
mutex_exit(obj->uobj.vmobjlock);
- uvmflag = UVM_MAPFLAG(prot, prot, UVM_INH_NONE, UVM_ADV_NORMAL,
+ uvmflag = UVM_MAPFLAG(prot, prot, prot, UVM_INH_NONE, UVM_ADV_NORMAL,
UVM_FLAG_FIXED | UVM_FLAG_NOMERGE);
error = uvm_map(map, &newstart, size, &obj->uobj, 0, 0, uvmflag);
Index: sys/external/bsd/drm2/dist/drm/i915/i915_gem.c
===================================================================
RCS file: /home/joerg/repo/netbsd/src/sys/external/bsd/drm2/dist/drm/i915/i915_gem.c,v
retrieving revision 1.33
diff -u -p -r1.33 i915_gem.c
--- sys/external/bsd/drm2/dist/drm/i915/i915_gem.c 26 Nov 2015 13:15:34 -0000 1.33
+++ sys/external/bsd/drm2/dist/drm/i915/i915_gem.c 24 Mar 2017 14:47:25 -0000
@@ -1777,9 +1777,8 @@ i915_gem_mmap_ioctl(struct drm_device *d
/* XXX errno NetBSD->Linux */
ret = -uvm_map(&curproc->p_vmspace->vm_map, &addr, args->size,
obj->gemo_shm_uao, args->offset, 0,
- UVM_MAPFLAG((VM_PROT_READ | VM_PROT_WRITE),
- (VM_PROT_READ | VM_PROT_WRITE), UVM_INH_COPY, UVM_ADV_NORMAL,
- 0));
+ UVM_MAPFLAG(UVM_PROT_RW, UVM_PROT_RW, UVM_PROT_RW, UVM_INH_COPY,
+ UVM_ADV_NORMAL, 0));
if (ret) {
drm_gem_object_unreference_unlocked(obj);
return ret;
Index: sys/kern/exec_subr.c
===================================================================
RCS file: /home/joerg/repo/netbsd/src/sys/kern/exec_subr.c,v
retrieving revision 1.76
diff -u -p -r1.76 exec_subr.c
--- sys/kern/exec_subr.c 22 May 2016 14:26:09 -0000 1.76
+++ sys/kern/exec_subr.c 24 Mar 2017 14:48:05 -0000
@@ -162,7 +162,7 @@ vmcmd_map_pagedvn(struct lwp *l, struct
struct vnode *vp = cmd->ev_vp;
struct proc *p = l->l_proc;
int error;
- vm_prot_t prot, maxprot;
+ vm_prot_t prot, maxprot, limprot;
KASSERT(vp->v_iflag & VI_TEXT);
@@ -180,7 +180,7 @@ vmcmd_map_pagedvn(struct lwp *l, struct
return EINVAL;
prot = cmd->ev_prot;
- maxprot = UVM_PROT_ALL;
+ limprot = maxprot = UVM_PROT_ALL;
PAX_MPROTECT_ADJUST(l, &prot, &maxprot);
/*
@@ -203,9 +203,13 @@ vmcmd_map_pagedvn(struct lwp *l, struct
uobj = &vp->v_uobj;
vref(vp);
+ prot = cmd->ev_prot;
+ limprot = maxprot = UVM_PROT_ALL;
+ PAX_MPROTECT_ADJUST(l, &prot, &maxprot);
+
error = uvm_map(&p->p_vmspace->vm_map, &cmd->ev_addr, cmd->ev_len,
uobj, cmd->ev_offset, 0,
- UVM_MAPFLAG(prot, maxprot, UVM_INH_COPY,
+ UVM_MAPFLAG(prot, maxprot, limprot, UVM_INH_COPY,
UVM_ADV_NORMAL, UVM_FLAG_COPYONW|UVM_FLAG_FIXED));
if (error) {
uobj->pgops->pgo_detach(uobj);
@@ -225,6 +229,7 @@ vmcmd_map_readvn(struct lwp *l, struct e
struct proc *p = l->l_proc;
int error;
long diff;
+ vm_prot_t prot, maxprot, limprot;
if (cmd->ev_len == 0)
return 0;
@@ -234,9 +239,13 @@ vmcmd_map_readvn(struct lwp *l, struct e
cmd->ev_offset -= diff;
cmd->ev_len += diff;
+ prot = VM_PROT_ALL;
+ limprot = maxprot = VM_PROT_ALL;
+ PAX_MPROTECT_ADJUST(l, &prot, &maxprot);
+
error = uvm_map(&p->p_vmspace->vm_map, &cmd->ev_addr,
round_page(cmd->ev_len), NULL, UVM_UNKNOWN_OFFSET, 0,
- UVM_MAPFLAG(UVM_PROT_ALL, UVM_PROT_ALL, UVM_INH_COPY,
+ UVM_MAPFLAG(prot, maxprot, limprot, UVM_INH_COPY,
UVM_ADV_NORMAL,
UVM_FLAG_FIXED|UVM_FLAG_OVERLAY|UVM_FLAG_COPYONW));
@@ -311,19 +320,19 @@ vmcmd_map_zero(struct lwp *l, struct exe
struct proc *p = l->l_proc;
int error;
long diff;
- vm_prot_t prot, maxprot;
+ vm_prot_t prot, maxprot, limprot;
diff = cmd->ev_addr - trunc_page(cmd->ev_addr);
cmd->ev_addr -= diff; /* required by uvm_map */
cmd->ev_len += diff;
prot = cmd->ev_prot;
- maxprot = UVM_PROT_ALL;
+ limprot = maxprot = UVM_PROT_ALL;
PAX_MPROTECT_ADJUST(l, &prot, &maxprot);
error = uvm_map(&p->p_vmspace->vm_map, &cmd->ev_addr,
round_page(cmd->ev_len), NULL, UVM_UNKNOWN_OFFSET, 0,
- UVM_MAPFLAG(prot, maxprot, UVM_INH_COPY,
+ UVM_MAPFLAG(prot, maxprot, limprot, UVM_INH_COPY,
UVM_ADV_NORMAL,
UVM_FLAG_FIXED|UVM_FLAG_COPYONW));
if (cmd->ev_flags & VMCMD_STACK)
Index: sys/kern/init_main.c
===================================================================
RCS file: /home/joerg/repo/netbsd/src/sys/kern/init_main.c,v
retrieving revision 1.490
diff -u -p -r1.490 init_main.c
--- sys/kern/init_main.c 16 Jan 2017 09:28:40 -0000 1.490
+++ sys/kern/init_main.c 24 Mar 2017 14:41:25 -0000
@@ -943,7 +943,7 @@ start_init(void *arg)
addr = (vaddr_t)STACK_ALLOC(USRSTACK, PAGE_SIZE);
if (uvm_map(&p->p_vmspace->vm_map, &addr, PAGE_SIZE,
NULL, UVM_UNKNOWN_OFFSET, 0,
- UVM_MAPFLAG(UVM_PROT_RW, UVM_PROT_RW, UVM_INH_COPY,
+ UVM_MAPFLAG(UVM_PROT_RW, UVM_PROT_RW, UVM_PROT_RW, UVM_INH_COPY,
UVM_ADV_NORMAL,
UVM_FLAG_FIXED|UVM_FLAG_OVERLAY|UVM_FLAG_COPYONW)) != 0)
panic("init: couldn't allocate argument space");
Index: sys/kern/kern_exec.c
===================================================================
RCS file: /home/joerg/repo/netbsd/src/sys/kern/kern_exec.c,v
retrieving revision 1.441
diff -u -p -r1.441 kern_exec.c
--- sys/kern/kern_exec.c 25 Jan 2017 17:57:14 -0000 1.441
+++ sys/kern/kern_exec.c 24 Mar 2017 14:41:18 -0000
@@ -1927,7 +1927,7 @@ exec_sigcode_map(struct proc *p, const s
va = vm_map_min(kernel_map);
if ((error = uvm_map(kernel_map, &va, round_page(sz),
uobj, 0, 0,
- UVM_MAPFLAG(UVM_PROT_RW, UVM_PROT_RW,
+ UVM_MAPFLAG(UVM_PROT_RW, UVM_PROT_RW, UVM_PROT_RW,
UVM_INH_SHARE, UVM_ADV_RANDOM, 0)))) {
printf("kernel mapping failed %d\n", error);
(*uobj->pgops->pgo_detach)(uobj);
@@ -1962,8 +1962,8 @@ exec_sigcode_map(struct proc *p, const s
(*uobj->pgops->pgo_reference)(uobj);
error = uvm_map(&p->p_vmspace->vm_map, &va, round_page(sz),
uobj, 0, 0,
- UVM_MAPFLAG(UVM_PROT_RX, UVM_PROT_RX, UVM_INH_SHARE,
- UVM_ADV_RANDOM, 0));
+ UVM_MAPFLAG(UVM_PROT_RX, UVM_PROT_RX, UVM_PROT_RX,
+ UVM_INH_SHARE, UVM_ADV_RANDOM, 0));
if (error) {
DPRINTF(("%s, %d: map %p "
"uvm_map %#"PRIxVSIZE"@%#"PRIxVADDR" failed %d\n",
Index: sys/kern/kern_lwp.c
===================================================================
RCS file: /home/joerg/repo/netbsd/src/sys/kern/kern_lwp.c,v
retrieving revision 1.187
diff -u -p -r1.187 kern_lwp.c
--- sys/kern/kern_lwp.c 14 Jan 2017 19:32:10 -0000 1.187
+++ sys/kern/kern_lwp.c 24 Mar 2017 14:45:51 -0000
@@ -1785,7 +1785,7 @@ lwp_ctl_alloc(vaddr_t *uaddr)
p->p_vmspace->vm_map.flags & VM_MAP_TOPDOWN);
error = uvm_map(&p->p_vmspace->vm_map, &lp->lp_uva,
LWPCTL_UAREA_SZ, lp->lp_uao, 0, 0, UVM_MAPFLAG(UVM_PROT_RW,
- UVM_PROT_RW, UVM_INH_NONE, UVM_ADV_NORMAL, 0));
+ UVM_PROT_RW, UVM_PROT_RW, UVM_INH_NONE, UVM_ADV_NORMAL, 0));
if (error != 0) {
uao_detach(lp->lp_uao);
lp->lp_uao = NULL;
@@ -1819,7 +1819,7 @@ lwp_ctl_alloc(vaddr_t *uaddr)
lcp->lcp_kaddr = vm_map_min(kernel_map);
error = uvm_map(kernel_map, &lcp->lcp_kaddr, PAGE_SIZE,
uao, lp->lp_cur, PAGE_SIZE,
- UVM_MAPFLAG(UVM_PROT_RW, UVM_PROT_RW,
+ UVM_MAPFLAG(UVM_PROT_RW, UVM_PROT_RW, UVM_PROT_RW,
UVM_INH_NONE, UVM_ADV_RANDOM, 0));
if (error != 0) {
mutex_exit(&lp->lp_lock);
Index: sys/kern/sysv_shm.c
===================================================================
RCS file: /home/joerg/repo/netbsd/src/sys/kern/sysv_shm.c,v
retrieving revision 1.131
diff -u -p -r1.131 sysv_shm.c
--- sys/kern/sysv_shm.c 26 Nov 2015 13:15:34 -0000 1.131
+++ sys/kern/sysv_shm.c 24 Mar 2017 14:45:30 -0000
@@ -459,7 +459,7 @@ sys_shmat(struct lwp *l, const struct sy
uobj = shmseg->_shm_internal;
uao_reference(uobj);
error = uvm_map(&vm->vm_map, &attach_va, size, uobj, 0, 0,
- UVM_MAPFLAG(prot, prot, UVM_INH_SHARE, UVM_ADV_RANDOM, flags));
+ UVM_MAPFLAG(prot, prot, prot, UVM_INH_SHARE, UVM_ADV_RANDOM, flags));
if (error)
goto err_detach;
if (shm_use_phys || (shmseg->shm_perm.mode & SHMSEG_WIRED)) {
Index: sys/uvm/uvm_bio.c
===================================================================
RCS file: /home/joerg/repo/netbsd/src/sys/uvm/uvm_bio.c,v
retrieving revision 1.89
diff -u -p -r1.89 uvm_bio.c
--- sys/uvm/uvm_bio.c 21 Mar 2017 02:24:35 -0000 1.89
+++ sys/uvm/uvm_bio.c 24 Mar 2017 14:06:07 -0000
@@ -207,8 +207,9 @@ ubc_init(void)
if (uvm_map(kernel_map, (vaddr_t *)&ubc_object.kva,
ubc_nwins << ubc_winshift, &ubc_object.uobj, 0, (vsize_t)va,
- UVM_MAPFLAG(UVM_PROT_ALL, UVM_PROT_ALL, UVM_INH_NONE,
- UVM_ADV_RANDOM, UVM_FLAG_NOMERGE)) != 0) {
+ UVM_MAPFLAG(UVM_PROT_ALL, UVM_PROT_ALL, UVM_PROT_ALL,
+ UVM_INH_NONE, UVM_ADV_RANDOM,
+ UVM_FLAG_NOMERGE)) != 0) {
panic("ubc_init: failed to map ubc_object");
}
}
Index: sys/uvm/uvm_extern.h
===================================================================
RCS file: /home/joerg/repo/netbsd/src/sys/uvm/uvm_extern.h,v
retrieving revision 1.203
diff -u -p -r1.203 uvm_extern.h
--- sys/uvm/uvm_extern.h 4 Jan 2017 23:59:49 -0000 1.203
+++ sys/uvm/uvm_extern.h 24 Mar 2017 15:30:56 -0000
@@ -120,7 +120,7 @@
#define UVM_ADV_NOREUSE 0x5 /* pages will be used only once */
#define UVM_ADV_MASK 0x7 /* mask */
-/* bits 0xffff0000: mapping flags */
+/* bits 0x0fff0000: mapping flags */
#define UVM_FLAG_FIXED 0x010000 /* find space */
#define UVM_FLAG_OVERLAY 0x020000 /* establish overlay */
#define UVM_FLAG_NOMERGE 0x040000 /* don't merge map entries */
@@ -131,15 +131,22 @@
#define UVM_FLAG_WAITVA 0x800000 /* wait for va */
#define UVM_FLAG_VAONLY 0x2000000 /* unmap: no pages are mapped */
#define UVM_FLAG_COLORMATCH 0x4000000 /* match color given in off */
+/* 0x08000000: unused */
+
+/* bits 0x70000000: limits for max protection */
+
+/* 0x80000000: unused */
/* macros to extract info */
#define UVM_PROTECTION(X) ((X) & UVM_PROT_MASK)
#define UVM_INHERIT(X) (((X) & UVM_INH_MASK) >> 4)
#define UVM_MAXPROTECTION(X) (((X) >> 8) & UVM_PROT_MASK)
+#define UVM_LIMITPROTECTION(X) (((X) >> 28) & UVM_PROT_MASK)
#define UVM_ADVICE(X) (((X) >> 12) & UVM_ADV_MASK)
-#define UVM_MAPFLAG(PROT,MAXPROT,INH,ADVICE,FLAGS) \
- (((MAXPROT) << 8)|(PROT)|(INH)|((ADVICE) << 12)|(FLAGS))
+#define UVM_MAPFLAG(PROT,MAXPROT,LIMPROT,INH,ADVICE,FLAGS) \
+ (((MAXPROT) << 8) | (PROT) | (INH) | ((ADVICE) << 12) | \
+ (FLAGS)| ((LIMPROT) << 28))
/* magic offset value: offset not known(obj) or don't care(!obj) */
#define UVM_UNKNOWN_OFFSET ((voff_t) -1)
Index: sys/uvm/uvm_km.c
===================================================================
RCS file: /home/joerg/repo/netbsd/src/sys/uvm/uvm_km.c,v
retrieving revision 1.142
diff -u -p -r1.142 uvm_km.c
--- sys/uvm/uvm_km.c 19 Mar 2017 23:44:34 -0000 1.142
+++ sys/uvm/uvm_km.c 24 Mar 2017 14:05:37 -0000
@@ -287,8 +287,9 @@ uvm_km_bootstrap(vaddr_t start, vaddr_t
error = uvm_map_prepare(&kernel_map_store,
base, start - base,
NULL, UVM_UNKNOWN_OFFSET, 0,
- UVM_MAPFLAG(UVM_PROT_ALL, UVM_PROT_ALL, UVM_INH_NONE,
- UVM_ADV_RANDOM, UVM_FLAG_FIXED), &args);
+ UVM_MAPFLAG(UVM_PROT_ALL, UVM_PROT_ALL, UVM_PROT_ALL,
+ UVM_INH_NONE, UVM_ADV_RANDOM, UVM_FLAG_FIXED),
+ &args);
if (!error) {
kernel_image_mapent_store.flags =
UVM_MAP_KERNEL | UVM_MAP_STATIC | UVM_MAP_NOMERGE;
@@ -308,7 +309,7 @@ uvm_km_bootstrap(vaddr_t start, vaddr_t
error = uvm_map_prepare(&kernel_map_store,
kmembase, kmemsize,
NULL, UVM_UNKNOWN_OFFSET, 0,
- UVM_MAPFLAG(UVM_PROT_ALL, UVM_PROT_ALL, UVM_INH_NONE,
+ UVM_MAPFLAG(UVM_PROT_ALL, UVM_PROT_ALL, UVM_PROT_ALL, UVM_INH_NONE,
UVM_ADV_RANDOM, UVM_FLAG_FIXED), &args);
if (!error) {
kernel_kmem_mapent_store.flags =
@@ -396,7 +397,7 @@ uvm_km_suballoc(struct vm_map *map, vadd
*/
if (uvm_map(map, vmin, size, NULL, UVM_UNKNOWN_OFFSET, 0,
- UVM_MAPFLAG(UVM_PROT_ALL, UVM_PROT_ALL, UVM_INH_NONE,
+ UVM_MAPFLAG(UVM_PROT_ALL, UVM_PROT_ALL, UVM_PROT_ALL, UVM_INH_NONE,
UVM_ADV_RANDOM, mapflags)) != 0) {
panic("%s: unable to allocate space in parent map", __func__);
}
@@ -619,8 +620,8 @@ uvm_km_alloc(struct vm_map *map, vsize_t
vaprot = (flags & UVM_KMF_EXEC) ? UVM_PROT_ALL : UVM_PROT_RW;
if (__predict_false(uvm_map(map, &kva, size, obj, UVM_UNKNOWN_OFFSET,
- align, UVM_MAPFLAG(vaprot, UVM_PROT_ALL, UVM_INH_NONE,
- UVM_ADV_RANDOM,
+ align, UVM_MAPFLAG(vaprot, UVM_PROT_ALL, UVM_PROT_ALL,
+ UVM_INH_NONE, UVM_ADV_RANDOM,
(flags & (UVM_KMF_TRYLOCK | UVM_KMF_NOWAIT | UVM_KMF_WAITVA
| UVM_KMF_COLORMATCH)))) != 0)) {
UVMHIST_LOG(maphist, "<- done (no VM)",0,0,0,0);
Index: sys/uvm/uvm_map.c
===================================================================
RCS file: /home/joerg/repo/netbsd/src/sys/uvm/uvm_map.c,v
retrieving revision 1.343
diff -u -p -r1.343 uvm_map.c
--- sys/uvm/uvm_map.c 15 Mar 2017 20:25:41 -0000 1.343
+++ sys/uvm/uvm_map.c 24 Mar 2017 14:52:19 -0000
@@ -190,12 +190,13 @@ int user_va0_disable = __USER_VA0_DISABL
extern struct vm_map *pager_map;
#define UVM_ET_ISCOMPATIBLE(ent, type, uobj, meflags, \
- prot, maxprot, inh, adv, wire) \
+ prot, maxprot, limprot, inh, adv, wire) \
((ent)->etype == (type) && \
(((ent)->flags ^ (meflags)) & (UVM_MAP_NOMERGE)) == 0 && \
(ent)->object.uvm_obj == (uobj) && \
(ent)->protection == (prot) && \
(ent)->max_protection == (maxprot) && \
+ (ent)->lim_protection == (limprot) && \
(ent)->inheritance == (inh) && \
(ent)->advice == (adv) && \
(ent)->wired_count == (wire))
@@ -1255,6 +1256,7 @@ uvm_map_enter(struct vm_map *map, const
const uvm_flag_t flags = args->uma_flags;
const vm_prot_t prot = UVM_PROTECTION(flags);
const vm_prot_t maxprot = UVM_MAXPROTECTION(flags);
+ const vm_prot_t limprot = UVM_LIMITPROTECTION(flags);
const vm_inherit_t inherit = UVM_INHERIT(flags);
const int amapwaitflag = (flags & UVM_FLAG_NOWAIT) ?
AMAP_EXTEND_NOWAIT : 0;
@@ -1303,7 +1305,7 @@ uvm_map_enter(struct vm_map *map, const
if (prev_entry->end == start &&
prev_entry != &map->header &&
UVM_ET_ISCOMPATIBLE(prev_entry, newetype, uobj, 0,
- prot, maxprot, inherit, advice, 0)) {
+ prot, maxprot, limprot, inherit, advice, 0)) {
if (uobj && prev_entry->offset +
(prev_entry->end - prev_entry->start) != uoffset)
@@ -1360,7 +1362,7 @@ forwardmerge:
if (prev_entry->next->start == (start + size) &&
prev_entry->next != &map->header &&
UVM_ET_ISCOMPATIBLE(prev_entry->next, newetype, uobj, 0,
- prot, maxprot, inherit, advice, 0)) {
+ prot, maxprot, limprot, inherit, advice, 0)) {
if (uobj && prev_entry->next->offset != uoffset + size)
goto nomerge;
@@ -1522,6 +1524,7 @@ nomerge:
new_entry->protection = prot;
new_entry->max_protection = maxprot;
+ new_entry->lim_protection = limprot;
new_entry->inheritance = inherit;
new_entry->wired_count = 0;
new_entry->advice = advice;
@@ -2399,8 +2402,8 @@ uvm_map_reserve(struct vm_map *map, vsiz
*/
if (uvm_map(map, raddr, size, NULL, offset, align,
- UVM_MAPFLAG(UVM_PROT_NONE, UVM_PROT_NONE, UVM_INH_NONE,
- UVM_ADV_RANDOM, UVM_FLAG_NOMERGE|flags)) != 0) {
+ UVM_MAPFLAG(UVM_PROT_NONE, UVM_PROT_NONE, UVM_PROT_NONE,
+ UVM_INH_NONE, UVM_ADV_RANDOM, UVM_FLAG_NOMERGE|flags)) != 0) {
UVMHIST_LOG(maphist, "<- done (no VM)", 0,0,0,0);
return (false);
}
@@ -2988,7 +2991,11 @@ uvm_map_protect(struct vm_map *map, vadd
error = EINVAL;
goto out;
}
- if ((new_prot & current->max_protection) != new_prot) {
+ if ((new_prot & current->lim_protection) != new_prot) {
+ error = EACCES;
+ goto out;
+ }
+ if (!set_max && (new_prot & current->max_protection) != new_prot) {
error = EACCES;
goto out;
}
@@ -3021,10 +3028,8 @@ uvm_map_protect(struct vm_map *map, vadd
UVM_MAP_CLIP_END(map, current, end);
old_prot = current->protection;
if (set_max)
- current->protection =
- (current->max_protection = new_prot) & old_prot;
- else
- current->protection = new_prot;
+ current->max_protection = new_prot;
+ current->protection = new_prot;
/*
* update physical map if necessary. worry about copy-on-write
@@ -4523,7 +4528,8 @@ uvm_mapent_trymerge(struct vm_map *map,
(!copying && next->aref.ar_amap == NULL)) &&
UVM_ET_ISCOMPATIBLE(next, newetype,
uobj, entry->flags, entry->protection,
- entry->max_protection, entry->inheritance, entry->advice,
+ entry->max_protection, entry->lim_protection,
+ entry->inheritance, entry->advice,
entry->wired_count) &&
(uobj == NULL || entry->offset + size == next->offset)) {
int error;
@@ -4562,7 +4568,8 @@ uvm_mapent_trymerge(struct vm_map *map,
(!copying && prev->aref.ar_amap == NULL)) &&
UVM_ET_ISCOMPATIBLE(prev, newetype,
uobj, entry->flags, entry->protection,
- entry->max_protection, entry->inheritance, entry->advice,
+ entry->max_protection, entry->lim_protection,
+ entry->inheritance, entry->advice,
entry->wired_count) &&
(uobj == NULL ||
prev->offset + prev->end - prev->start == entry->offset)) {
@@ -4744,13 +4751,14 @@ uvm_map_printit(struct vm_map *map, bool
(long long)entry->offset, entry->aref.ar_amap,
entry->aref.ar_pageoff);
(*pr)(
- "\tsubmap=%c, cow=%c, nc=%c, prot(max)=%d/%d, inh=%d, "
+ "\tsubmap=%c, cow=%c, nc=%c, prot(max,lim)=%d/%d/%d, inh=%d, "
"wc=%d, adv=%d\n",
(entry->etype & UVM_ET_SUBMAP) ? 'T' : 'F',
(entry->etype & UVM_ET_COPYONWRITE) ? 'T' : 'F',
(entry->etype & UVM_ET_NEEDSCOPY) ? 'T' : 'F',
entry->protection, entry->max_protection,
- entry->inheritance, entry->wired_count, entry->advice);
+ entry->lim_protection, entry->inheritance,
+ entry->wired_count, entry->advice);
}
}
Index: sys/uvm/uvm_map.h
===================================================================
RCS file: /home/joerg/repo/netbsd/src/sys/uvm/uvm_map.h,v
retrieving revision 1.73
diff -u -p -r1.73 uvm_map.h
--- sys/uvm/uvm_map.h 25 May 2016 17:43:58 -0000 1.73
+++ sys/uvm/uvm_map.h 24 Mar 2017 14:07:05 -0000
@@ -142,6 +142,7 @@ struct vm_map_entry {
int etype; /* entry type */
vm_prot_t protection; /* protection code */
vm_prot_t max_protection; /* maximum protection */
+ vm_prot_t lim_protection; /* limit for max_protection */
vm_inherit_t inheritance; /* inheritance */
int wired_count; /* can be paged if == 0 */
struct vm_aref aref; /* anonymous overlay */
Index: sys/uvm/uvm_mmap.c
===================================================================
RCS file: /home/joerg/repo/netbsd/src/sys/uvm/uvm_mmap.c,v
retrieving revision 1.162
diff -u -p -r1.162 uvm_mmap.c
--- sys/uvm/uvm_mmap.c 9 Aug 2016 12:17:04 -0000 1.162
+++ sys/uvm/uvm_mmap.c 24 Mar 2017 15:55:11 -0000
@@ -64,7 +64,7 @@ __KERNEL_RCSID(0, "$NetBSD: uvm_mmap.c,v
#include <uvm/uvm_device.h>
static int uvm_mmap(struct vm_map *, vaddr_t *, vsize_t, vm_prot_t, vm_prot_t,
- int, int, struct uvm_object *, voff_t, vsize_t);
+ vm_prot_t, int, int, struct uvm_object *, voff_t, vsize_t);
static int
range_test(struct vm_map *map, vaddr_t addr, vsize_t size, bool ismmap)
@@ -287,7 +287,7 @@ sys_mmap(struct lwp *l, const struct sys
vaddr_t addr;
off_t pos;
vsize_t size, pageoff, newsize;
- vm_prot_t prot, maxprot;
+ vm_prot_t prot, maxprot, limprot;
int flags, fd, advice;
vaddr_t defaddr;
struct file *fp = NULL;
@@ -411,6 +411,8 @@ sys_mmap(struct lwp *l, const struct sys
pos = 0;
}
+ KASSERT((prot & maxprot) == prot);
+ limprot = prot = maxprot = prot & maxprot;
PAX_MPROTECT_ADJUST(l, &prot, &maxprot);
pax_aslr_mmap(l, &addr, orig_addr, flags);
@@ -420,7 +422,8 @@ sys_mmap(struct lwp *l, const struct sys
*/
error = uvm_mmap(&p->p_vmspace->vm_map, &addr, size, prot, maxprot,
- flags, advice, uobj, pos, p->p_rlimit[RLIMIT_MEMLOCK].rlim_cur);
+ limprot, flags, advice, uobj, pos,
+ p->p_rlimit[RLIMIT_MEMLOCK].rlim_cur);
/* remember to add offset */
*retval = (register_t)(addr + pageoff);
@@ -603,7 +606,7 @@ sys_mprotect(struct lwp *l, const struct
struct proc *p = l->l_proc;
vaddr_t addr;
vsize_t size, pageoff;
- vm_prot_t prot;
+ vm_prot_t oprot, prot, maxprot;
int error;
/*
@@ -612,7 +615,10 @@ sys_mprotect(struct lwp *l, const struct
addr = (vaddr_t)SCARG(uap, addr);
size = (vsize_t)SCARG(uap, len);
- prot = SCARG(uap, prot) & VM_PROT_ALL;
+ maxprot = prot = oprot = SCARG(uap, prot) & VM_PROT_ALL;
+ PAX_MPROTECT_ADJUST(l, &prot, &maxprot);
+ if (prot != oprot)
+ return EPERM;
/*
* align the address to a page boundary and adjust the size accordingly.
@@ -628,7 +634,7 @@ sys_mprotect(struct lwp *l, const struct
return EINVAL;
error = uvm_map_protect(&p->p_vmspace->vm_map, addr, addr + size, prot,
- false);
+ true);
return error;
}
@@ -915,8 +921,8 @@ sys_munlockall(struct lwp *l, const void
int
uvm_mmap(struct vm_map *map, vaddr_t *addr, vsize_t size, vm_prot_t prot,
- vm_prot_t maxprot, int flags, int advice, struct uvm_object *uobj,
- voff_t foff, vsize_t locklimit)
+ vm_prot_t maxprot, vm_prot_t limprot, int flags, int advice,
+ struct uvm_object *uobj, voff_t foff, vsize_t locklimit)
{
vaddr_t align = 0;
int error;
@@ -1002,7 +1008,7 @@ uvm_mmap(struct vm_map *map, vaddr_t *ad
}
}
- uvmflag = UVM_MAPFLAG(prot, maxprot,
+ uvmflag = UVM_MAPFLAG(prot, maxprot, limprot,
(flags & MAP_SHARED) ? UVM_INH_SHARE : UVM_INH_COPY, advice,
uvmflag);
error = uvm_map(map, addr, size, uobj, foff, align, uvmflag);
@@ -1084,7 +1090,7 @@ uvm_mmap_dev(struct proc *p, void **addr
return EINVAL;
error = uvm_mmap(&p->p_vmspace->vm_map, (vaddr_t *)addrp,
- (vsize_t)len, prot, prot, flags, UVM_ADV_RANDOM, uobj, off,
+ (vsize_t)len, prot, prot, prot, flags, UVM_ADV_RANDOM, uobj, off,
p->p_rlimit[RLIMIT_MEMLOCK].rlim_cur);
return error;
}
@@ -1104,7 +1110,7 @@ uvm_mmap_anon(struct proc *p, void **add
p->p_vmspace->vm_map.flags & VM_MAP_TOPDOWN);
error = uvm_mmap(&p->p_vmspace->vm_map, (vaddr_t *)addrp,
- (vsize_t)len, prot, prot, flags, UVM_ADV_NORMAL, NULL, 0,
+ (vsize_t)len, prot, prot, prot, flags, UVM_ADV_NORMAL, NULL, 0,
p->p_rlimit[RLIMIT_MEMLOCK].rlim_cur);
return error;
}
Index: sys/uvm/uvm_mremap.c
===================================================================
RCS file: /home/joerg/repo/netbsd/src/sys/uvm/uvm_mremap.c,v
retrieving revision 1.18
diff -u -p -r1.18 uvm_mremap.c
--- sys/uvm/uvm_mremap.c 26 Nov 2015 13:15:34 -0000 1.18
+++ sys/uvm/uvm_mremap.c 24 Mar 2017 14:10:45 -0000
@@ -94,6 +94,7 @@ uvm_mapent_extend(struct vm_map *map, va
reserved_entry->flags &= ~UVM_MAP_NOMERGE;
reserved_entry->protection = entry->protection;
reserved_entry->max_protection = entry->max_protection;
+ reserved_entry->lim_protection = entry->lim_protection;
reserved_entry->inheritance = entry->inheritance;
reserved_entry->advice = entry->advice;
reserved_entry->wired_count = 0; /* XXX should inherit? */
Index: sys/uvm/uvm_unix.c
===================================================================
RCS file: /home/joerg/repo/netbsd/src/sys/uvm/uvm_unix.c,v
retrieving revision 1.47
diff -u -p -r1.47 uvm_unix.c
--- sys/uvm/uvm_unix.c 7 Apr 2016 12:07:36 -0000 1.47
+++ sys/uvm/uvm_unix.c 24 Mar 2017 14:33:02 -0000
@@ -104,7 +104,7 @@ sys_obreak(struct lwp *l, const struct s
error = uvm_map(&vm->vm_map, &obreak, nbreak - obreak, NULL,
UVM_UNKNOWN_OFFSET, 0,
- UVM_MAPFLAG(prot, maxprot,
+ UVM_MAPFLAG(prot, maxprot, maxprot,
UVM_INH_COPY,
UVM_ADV_NORMAL, UVM_FLAG_AMAPPAD|UVM_FLAG_FIXED|
UVM_FLAG_OVERLAY|UVM_FLAG_COPYONW));
Index: tests/lib/libc/sys/t_mprotect.c
===================================================================
RCS file: /home/joerg/repo/netbsd/src/tests/lib/libc/sys/t_mprotect.c,v
retrieving revision 1.6
diff -u -p -r1.6 t_mprotect.c
--- tests/lib/libc/sys/t_mprotect.c 25 Mar 2017 01:39:20 -0000 1.6
+++ tests/lib/libc/sys/t_mprotect.c 31 Mar 2017 12:59:25 -0000
@@ -171,7 +171,7 @@ ATF_TC_BODY(mprotect_exec, tc)
* a SIGSEGV on architectures that can enforce --x permissions.
*/
- map = mmap(NULL, page, PROT_WRITE|PROT_READ, MAP_ANON, -1, 0);
+ map = mmap(NULL, page, PROT_EXEC|PROT_WRITE|PROT_READ, MAP_ANON, -1, 0);
ATF_REQUIRE(map != MAP_FAILED);
memcpy(map, (void *)return_one,
@@ -312,6 +312,76 @@ ATF_TC_BODY(mprotect_write, tc)
ATF_REQUIRE(munmap(map, page) == 0);
}
+ATF_TC(mprotect_mremap_exec);
+ATF_TC_HEAD(mprotect_mremap_exec, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test mremap(2)+mprotect(2) executable space protections");
+}
+
+/*
+ * Trivial function -- should fit into a page
+ */
+ATF_TC_BODY(mprotect_mremap_exec, tc)
+{
+ void *map, *map2;
+ pid_t pid;
+ int sta;
+
+ /*
+ * Map a page read/write/exec and duplicate it.
+ * Map the copy executable.
+ * Copy a trivial assembly function to the writeable mapping.
+ * Try to execute it. This should never create a SIGSEGV.
+ */
+
+ map = mmap(NULL, page, PROT_EXEC|PROT_WRITE|PROT_READ, MAP_ANON, -1, 0);
+ ATF_REQUIRE(map != MAP_FAILED);
+ map2 = mremap(map, page, NULL, page, MAP_REMAPDUP);
+ ATF_REQUIRE(map2 != MAP_FAILED);
+ ATF_REQUIRE(mprotect(map, page, PROT_WRITE|PROT_READ) == 0);
+ ATF_REQUIRE(mprotect(map2, page, PROT_EXEC|PROT_READ) == 0);
+
+ memcpy(map, (void *)return_one,
+ (uintptr_t)return_one_end - (uintptr_t)return_one);
+ __builtin___clear_cache(map, (void *)((uintptr_t)map + page));
+
+ ATF_REQUIRE(((int (*)(void))map2)() == 1);
+
+ /* Double check that the executable mapping is not writeable. */
+ pid = fork();
+ ATF_REQUIRE(pid >= 0);
+
+ if (pid == 0) {
+ ATF_REQUIRE(signal(SIGSEGV, sighandler) != SIG_ERR);
+ ATF_REQUIRE(strlcpy(map2, "XXX", 3) == 0);
+ }
+
+ (void)wait(&sta);
+
+ ATF_REQUIRE(WIFEXITED(sta) != 0);
+ ATF_REQUIRE(WEXITSTATUS(sta) == SIGSEGV);
+
+ if (exec_prot_support() == PERPAGE_XP) {
+ /* Double check that the writeable mapping is not executable. */
+ pid = fork();
+ ATF_REQUIRE(pid >= 0);
+
+ if (pid == 0) {
+ ATF_REQUIRE(signal(SIGSEGV, sighandler) != SIG_ERR);
+ ATF_REQUIRE(((int (*)(void))map)() == 1);
+ }
+
+ (void)wait(&sta);
+
+ ATF_REQUIRE(WIFEXITED(sta) != 0);
+ ATF_REQUIRE(WEXITSTATUS(sta) == SIGSEGV);
+ }
+
+ ATF_REQUIRE(munmap(map, page) == 0);
+ ATF_REQUIRE(munmap(map2, page) == 0);
+}
+
ATF_TP_ADD_TCS(tp)
{
page = sysconf(_SC_PAGESIZE);
@@ -322,6 +392,7 @@ ATF_TP_ADD_TCS(tp)
ATF_TP_ADD_TC(tp, mprotect_exec);
ATF_TP_ADD_TC(tp, mprotect_pax);
ATF_TP_ADD_TC(tp, mprotect_write);
+ ATF_TP_ADD_TC(tp, mprotect_mremap_exec);
return atf_no_error();
}
Home |
Main Index |
Thread Index |
Old Index