tech-kern archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
PAX mprotect and JIT v2
Hi all,
this is the second version of changes to improve the JIT support in
current. This version extends mmap(2)'s protection field to allow
specifying additional protections that can be enabled by mprotect later.
With the changes mprotect allows setting any permissions originally
requested and not more. I.e. if a page was originally mapped with
PROT_READ, it will never be writeable or executable. The PAX integration
is now split into two separate parts:
(1) Compute the maximum protection level for a mapping.
(2) Verify that a requested protection level is valid.
mmap and mprotect will now explicitly return an error if the requested
protection is not invalid, they won't silently truncate protections.
Stricter PAX mprotect changes would be implementable without further
interface changes, i.e. like the current "never make a writeable page
executable", but I'm not including anything like that as I find it of
questionable usefulness.
The patch also includes the mremap part as well as test cases.
Joerg
Index: lib/libc/sys/mmap.2
===================================================================
RCS file: /home/joerg/repo/netbsd/src/lib/libc/sys/mmap.2,v
retrieving revision 1.48
diff -u -p -r1.48 mmap.2
--- lib/libc/sys/mmap.2 27 Feb 2015 16:18:00 -0000 1.48
+++ lib/libc/sys/mmap.2 27 Apr 2017 15:07:48 -0000
@@ -29,7 +29,7 @@
.\"
.\" @(#)mmap.2 8.4 (Berkeley) 5/11/95
.\"
-.Dd February 27, 2015
+.Dd April 27, 2017
.Dt MMAP 2
.Os
.Sh NAME
@@ -85,8 +85,14 @@ Pages may be read.
.It Dv PROT_WRITE
Pages may be written.
.It Dv PROT_NONE
-Pages may not be accessed.
+Placeholder requesting any access permissions.
.El
+As a NetBSD extension,
+.Dv PROT_MPROTECT
+can be used to request additional permissions for later use with
+.Fn mprotect 2 .
+This is necessary for switching pages between writeable and executable
+when PAX mprotect restrictions are in place.
.Pp
.Bf -symbolic
Note that, due to hardware limitations, on some platforms
@@ -238,6 +244,7 @@ was specified as part of the
parameter and
.Fa fd
was not open for reading.
+.Pp
The flags
.Dv MAP_SHARED
and
@@ -249,6 +256,8 @@ and
parameters and
.Fa fd
was not open for writing.
+.Pp
+PAX mprotect restrictions prohibit the requested protection.
.It Bq Er EBADF
.Fa fd
is not a valid open file descriptor.
@@ -265,6 +274,7 @@ was specified and the
.Fa addr
parameter was not page aligned or was outside of the
valid address range for a process.
+.Pp
.Dv MAP_ANON was specified and
.Fa fd
was not \-1.
@@ -276,6 +286,7 @@ did not reference a regular or character
was specified and the
.Fa addr
parameter wasn't available.
+.Pp
.Dv MAP_ANON
was specified and insufficient memory was available.
.It Bq Er EOVERFLOW
Index: lib/libc/sys/mprotect.2
===================================================================
RCS file: /home/joerg/repo/netbsd/src/lib/libc/sys/mprotect.2,v
retrieving revision 1.24
diff -u -p -r1.24 mprotect.2
--- lib/libc/sys/mprotect.2 3 Apr 2011 06:54:30 -0000 1.24
+++ lib/libc/sys/mprotect.2 27 Apr 2017 15:08:05 -0000
@@ -29,7 +29,7 @@
.\"
.\" @(#)mprotect.2 8.1 (Berkeley) 6/9/93
.\"
-.Dd April 3, 2011
+.Dd April 27, 2017
.Dt MPROTECT 2
.Os
.Sh NAME
@@ -64,7 +64,7 @@ Pages may be read.
.It Dv PROT_WRITE
Pages may be written.
.It Dv PROT_NONE
-No permissions.
+Placeholder requesting any access permissions.
.El
.Sh RETURN VALUES
Upon successful completion,
@@ -75,11 +75,19 @@ is set to indicate the error.
.Sh ERRORS
.Bl -tag -width Er
.It Bq Er EACCES
-A memory protection violation occurred, or the
+A memory protection violation occurred.
+.Pp
+The
.Dv PROT_EXEC
flag was attempted on pages which belong to a filesystem mounted with the
.Dv NOEXEC
flag.
+.Pp
+The new protection is less restrictive than the protection originally
+set with
+.Xr mmap 2 .
+.Pp
+PAX mprotect restrictions prohibit the requested protection.
.It Bq Er EINVAL
An invalid memory range, or invalid parameters were provided.
.It Bq Er ENOMEM
Index: share/man/man9/uvm_map.9
===================================================================
RCS file: /home/joerg/repo/netbsd/src/share/man/man9/uvm_map.9,v
retrieving revision 1.6
diff -u -p -r1.6 uvm_map.9
--- share/man/man9/uvm_map.9 12 Sep 2014 21:06:25 -0000 1.6
+++ share/man/man9/uvm_map.9 27 Apr 2017 14:26:37 -0000
@@ -49,6 +49,9 @@ virtual address space management interfa
.Fn uvm_map_protect "struct vm_map *map" "vaddr_t start" "vaddr_t end" \
"vm_prot_t new_prot" "bool set_max"
.Ft int
+.Fn uvm_map_protect_user "struct lwp *l" "vaddr_t start" "vaddr_t end" \
+"vm_prot_t new_prot"
+.Ft int
.Fn uvm_deallocate "struct vm_map *map" "vaddr_t start" "vsize_t size"
.Ft struct vmspace *
.Fn uvmspace_alloc "vaddr_t min" "vaddr_t max"
@@ -308,6 +311,12 @@ if
is true.
This function returns a standard UVM return value.
.Pp
+.Fn uvm_map_protect_user
+verifies that the new permissions honor PAX restrictions if applicable
+and forwards to
+.Fn uvm_map_protect
+on passing.
+.Pp
.Fn uvm_deallocate
deallocates kernel memory in map
.Fa map
Index: sys/compat/linux/common/linux_misc.c
===================================================================
RCS file: /home/joerg/repo/netbsd/src/sys/compat/linux/common/linux_misc.c,v
retrieving revision 1.237
diff -u -p -r1.237 linux_misc.c
--- sys/compat/linux/common/linux_misc.c 28 Jan 2017 15:01:01 -0000 1.237
+++ sys/compat/linux/common/linux_misc.c 27 Apr 2017 14:00:19 -0000
@@ -603,7 +603,7 @@ linux_sys_mprotect(struct lwp *l, const
}
}
vm_map_unlock(map);
- return uvm_map_protect(map, start, end, prot, FALSE);
+ return uvm_map_protect_user(l, start, end, prot);
}
#endif /* USRSTACK */
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 21 Apr 2017 12:14:00 -0000
@@ -180,8 +180,11 @@ vmcmd_map_pagedvn(struct lwp *l, struct
return EINVAL;
prot = cmd->ev_prot;
- maxprot = UVM_PROT_ALL;
- PAX_MPROTECT_ADJUST(l, &prot, &maxprot);
+ maxprot = PAX_MPROTECT_MAXPROTECT(l, prot, 0, UVM_PROT_ALL);
+ if ((prot & maxprot) != prot)
+ return EPERM;
+ if ((error = PAX_MPROTECT_VALIDATE(l, prot)))
+ return error;
/*
* check the file system's opinion about mmapping the file
@@ -260,8 +263,11 @@ vmcmd_readvn(struct lwp *l, struct exec_
return error;
prot = cmd->ev_prot;
- maxprot = VM_PROT_ALL;
- PAX_MPROTECT_ADJUST(l, &prot, &maxprot);
+ maxprot = PAX_MPROTECT_MAXPROTECT(l, prot, 0, UVM_PROT_ALL);
+ if ((prot & maxprot) != prot)
+ return EPERM;
+ if ((error = PAX_MPROTECT_VALIDATE(l, prot)))
+ return error;
#ifdef PMAP_NEED_PROCWR
/*
@@ -318,8 +324,11 @@ vmcmd_map_zero(struct lwp *l, struct exe
cmd->ev_len += diff;
prot = cmd->ev_prot;
- maxprot = UVM_PROT_ALL;
- PAX_MPROTECT_ADJUST(l, &prot, &maxprot);
+ maxprot = PAX_MPROTECT_MAXPROTECT(l, prot, 0, UVM_PROT_ALL);
+ if ((prot & maxprot) != prot)
+ return EPERM;
+ if ((error = PAX_MPROTECT_VALIDATE(l, prot)))
+ return error;
error = uvm_map(&p->p_vmspace->vm_map, &cmd->ev_addr,
round_page(cmd->ev_len), NULL, UVM_UNKNOWN_OFFSET, 0,
Index: sys/kern/kern_pax.c
===================================================================
RCS file: /home/joerg/repo/netbsd/src/sys/kern/kern_pax.c,v
retrieving revision 1.58
diff -u -p -r1.58 kern_pax.c
--- sys/kern/kern_pax.c 18 Feb 2017 01:29:09 -0000 1.58
+++ sys/kern/kern_pax.c 27 Apr 2017 14:57:41 -0000
@@ -423,42 +423,48 @@ pax_mprotect_elf_flags_active(uint32_t f
return true;
}
-void
-pax_mprotect_adjust(
+vm_prot_t
+pax_mprotect_maxprotect(
#ifdef PAX_MPROTECT_DEBUG
const char *file, size_t line,
#endif
- struct lwp *l, vm_prot_t *prot, vm_prot_t *maxprot)
+ struct lwp *l, vm_prot_t active, vm_prot_t extra, vm_prot_t maxprot)
{
uint32_t flags;
flags = l->l_proc->p_pax;
if (!pax_flags_active(flags, P_PAX_MPROTECT))
- return;
+ return maxprot;
+
+ return (active|extra) & maxprot;
+}
- if ((*prot & (VM_PROT_WRITE|VM_PROT_EXECUTE)) != VM_PROT_EXECUTE) {
+int
+pax_mprotect_validate(
#ifdef PAX_MPROTECT_DEBUG
- struct proc *p = l->l_proc;
- if ((*prot & VM_PROT_EXECUTE) && pax_mprotect_debug) {
- printf("%s: %s,%zu: %d.%d (%s): -x\n",
- __func__, file, line,
- p->p_pid, l->l_lid, p->p_comm);
- }
+ const char *file, size_t line,
#endif
- *prot &= ~VM_PROT_EXECUTE;
- *maxprot &= ~VM_PROT_EXECUTE;
- } else {
+ struct lwp *l, vm_prot_t prot)
+{
+ uint32_t flags;
+
+ flags = l->l_proc->p_pax;
+ if (!pax_flags_active(flags, P_PAX_MPROTECT))
+ return 0;
+
+ if ((prot & (VM_PROT_WRITE|VM_PROT_EXECUTE)) ==
+ (VM_PROT_WRITE|VM_PROT_EXECUTE)) {
#ifdef PAX_MPROTECT_DEBUG
struct proc *p = l->l_proc;
- if ((*prot & VM_PROT_WRITE) && pax_mprotect_debug) {
- printf("%s: %s,%zu: %d.%d (%s): -w\n",
+
+ if (pax_mprotect_debug)
+ printf("%s: %s,%zu: %d.%d (%s): WX rejected\n",
__func__, file, line,
p->p_pid, l->l_lid, p->p_comm);
- }
#endif
- *prot &= ~VM_PROT_WRITE;
- *maxprot &= ~VM_PROT_WRITE;
+ return EACCES;
}
+ return 0;
}
/*
Index: sys/sys/mman.h
===================================================================
RCS file: /home/joerg/repo/netbsd/src/sys/sys/mman.h,v
retrieving revision 1.50
diff -u -p -r1.50 mman.h
--- sys/sys/mman.h 1 Jun 2016 00:46:44 -0000 1.50
+++ sys/sys/mman.h 21 Apr 2017 21:16:55 -0000
@@ -64,6 +64,16 @@ typedef __off_t off_t; /* file offset
#define PROT_WRITE 0x02 /* pages can be written */
#define PROT_EXEC 0x04 /* pages can be executed */
+#ifdef _NETBSD_SOURCE
+/*
+ * PAX mprotect prohibits setting protection bits
+ * missing from the original mmap call unless explicitly
+ * requested with PROT_MPROTECT.
+ */
+#define PROT_MPROTECT(x) ((x) << 3)
+#define PROT_MPROTECT_EXTRACT(x) (((x) >> 3) & 0x7)
+#endif
+
/*
* Flags contain sharing type and options.
* Sharing types; choose one.
@@ -82,6 +92,7 @@ typedef __off_t off_t; /* file offset
/*
* Other flags
*/
+#define MAP_REMAPDUP 0x0004 /* mremap only: duplicate the mapping */
#define MAP_FIXED 0x0010 /* map addr must be exactly as requested */
#define MAP_RENAME 0x0020 /* Sun: rename private pages to file */
#define MAP_NORESERVE 0x0040 /* Sun: don't reserve needed swap area */
Index: sys/sys/pax.h
===================================================================
RCS file: /home/joerg/repo/netbsd/src/sys/sys/pax.h,v
retrieving revision 1.25
diff -u -p -r1.25 pax.h
--- sys/sys/pax.h 3 Sep 2016 12:20:58 -0000 1.25
+++ sys/sys/pax.h 21 Apr 2017 12:38:29 -0000
@@ -63,23 +63,34 @@ void pax_setup_elf_flags(struct exec_pac
# define pax_setup_elf_flags(e, flags) __USE(flags)
#endif
-void pax_mprotect_adjust(
+vm_prot_t pax_mprotect_maxprotect(
#ifdef PAX_MPROTECT_DEBUG
const char *, size_t,
#endif
- struct lwp *, vm_prot_t *, vm_prot_t *);
+ struct lwp *, vm_prot_t, vm_prot_t, vm_prot_t);
+int pax_mprotect_validate(
+#ifdef PAX_MPROTECT_DEBUG
+ const char *, size_t,
+#endif
+ struct lwp *, vm_prot_t);
+
#ifndef PAX_MPROTECT
-# define PAX_MPROTECT_ADJUST(a, b, c)
+# define PAX_MPROTECT_MAXPROTECT(l, active, extra, max) (max)
+# define PAX_MPROTECT_VALIDATE(l, prot) (0)
# define pax_mprotect_prot(l) 0
#else
# ifdef PAX_MPROTECT_DEBUG
-# define PAX_MPROTECT_ADJUST(a, b, c) \
- pax_mprotect_adjust(__FILE__, __LINE__, (a), (b), (c))
+# define PAX_MPROTECT_MAXPROTECT(l, active, extra, max) \
+ pax_mprotect_maxprotect(__FILE__, __LINE__, (l), (active), (extra), (max))
+# define PAX_MPROTECT_VALIDATE(l, prot) \
+ pax_mprotect_validate(__FILE__, __LINE__, (l), (prot))
# else
-# define PAX_MPROTECT_ADJUST(a, b, c) \
- pax_mprotect_adjust((a), (b), (c))
+# define PAX_MPROTECT_MAXPROTECT(l, active, extra, max) \
+ pax_mprotect_maxprotect((l), (active), (extra), (max))
+# define PAX_MPROTECT_VALIDATE(l, prot) \
+ pax_mprotect_validate((l), (prot))
# endif
-extern int pax_mprotect_prot(struct lwp *);
+int pax_mprotect_prot(struct lwp *);
#endif
int pax_segvguard(struct lwp *, struct vnode *, const char *, bool);
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 27 Apr 2017 13:59:58 -0000
@@ -662,6 +662,8 @@ bool uvm_map_checkprot(struct vm_map *
vaddr_t, vm_prot_t);
int uvm_map_protect(struct vm_map *, vaddr_t,
vaddr_t, vm_prot_t, bool);
+int uvm_map_protect_user(struct lwp *, vaddr_t, vaddr_t,
+ vm_prot_t);
struct vmspace *uvmspace_alloc(vaddr_t, vaddr_t, bool);
void uvmspace_init(struct vmspace *, struct pmap *,
vaddr_t, vaddr_t, bool);
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 27 Apr 2017 14:23:19 -0000
@@ -69,6 +69,7 @@
__KERNEL_RCSID(0, "$NetBSD: uvm_map.c,v 1.343 2017/03/15 20:25:41 christos Exp $");
#include "opt_ddb.h"
+#include "opt_pax.h"
#include "opt_uvmhist.h"
#include "opt_uvm.h"
#include "opt_sysv.h"
@@ -80,6 +81,7 @@ __KERNEL_RCSID(0, "$NetBSD: uvm_map.c,v
#include <sys/pool.h>
#include <sys/kernel.h>
#include <sys/mount.h>
+#include <sys/pax.h>
#include <sys/vnode.h>
#include <sys/filedesc.h>
#include <sys/lockdebug.h>
@@ -2951,6 +2953,24 @@ uvm_map_submap(struct vm_map *map, vaddr
}
/*
+ * uvm_map_protect_user: change map protection on behalf of the user.
+ * Enforces PAX settings as necessary.
+ */
+int
+uvm_map_protect_user(struct lwp *l, vaddr_t start, vaddr_t end,
+ vm_prot_t new_prot)
+{
+ int error;
+
+ if ((error = PAX_MPROTECT_VALIDATE(l, new_prot)))
+ return error;
+
+ return uvm_map_protect(&l->l_proc->p_vmspace->vm_map, start, end,
+ new_prot, false);
+}
+
+
+/*
* uvm_map_protect: change map protection
*
* => set_max means set max_protection.
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 27 Apr 2017 14:57:22 -0000
@@ -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, extraprot;
int flags, fd, advice;
vaddr_t defaddr;
struct file *fp = NULL;
@@ -304,6 +304,7 @@ sys_mmap(struct lwp *l, const struct sys
addr = (vaddr_t)SCARG(uap, addr);
size = (vsize_t)SCARG(uap, len);
prot = SCARG(uap, prot) & VM_PROT_ALL;
+ extraprot = PROT_MPROTECT_EXTRACT(SCARG(uap, prot));
flags = SCARG(uap, flags);
fd = SCARG(uap, fd);
pos = SCARG(uap, pos);
@@ -411,7 +412,11 @@ sys_mmap(struct lwp *l, const struct sys
pos = 0;
}
- PAX_MPROTECT_ADJUST(l, &prot, &maxprot);
+ maxprot = PAX_MPROTECT_MAXPROTECT(l, prot, extraprot, maxprot);
+ if (((prot | extraprot) & maxprot) != (prot | extraprot))
+ return EACCES;
+ if ((error = PAX_MPROTECT_VALIDATE(l, prot)))
+ return error;
pax_aslr_mmap(l, &addr, orig_addr, flags);
@@ -627,8 +632,7 @@ sys_mprotect(struct lwp *l, const struct
if (error)
return EINVAL;
- error = uvm_map_protect(&p->p_vmspace->vm_map, addr, addr + size, prot,
- false);
+ error = uvm_map_protect_user(l, addr, addr + size, prot);
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 21 Apr 2017 11:38:09 -0000
@@ -120,6 +120,7 @@ uvm_mremap(struct vm_map *oldmap, vaddr_
vaddr_t align = 0;
int error = 0;
const bool fixed = (flags & MAP_FIXED) != 0;
+ const bool duplicate = (flags & MAP_REMAPDUP) != 0;
if (fixed) {
newva = *newvap;
@@ -165,7 +166,8 @@ uvm_mremap(struct vm_map *oldmap, vaddr_
* check the easy cases first.
*/
- if ((!fixed || newva == oldva) && newmap == oldmap &&
+ if (!duplicate &&
+ (!fixed || newva == oldva) && newmap == oldmap &&
(align == 0 || (oldva & (align - 1)) == 0)) {
vaddr_t va;
@@ -240,7 +242,7 @@ extend:
* remove original entries unless we did in-place extend.
*/
- if (oldva != newva || oldmap != newmap) {
+ if (!duplicate && (oldva != newva || oldmap != newmap)) {
uvm_unmap(oldmap, oldva, oldva + oldsize);
}
done:
@@ -278,7 +280,7 @@ sys_mremap(struct lwp *l, const struct s
newva = (vaddr_t)SCARG(uap, new_address);
newsize = (vsize_t)(SCARG(uap, new_size));
- if ((flags & ~(MAP_FIXED | MAP_ALIGNMENT_MASK)) != 0) {
+ if ((flags & ~(MAP_FIXED | MAP_REMAPDUP | MAP_ALIGNMENT_MASK)) != 0) {
error = EINVAL;
goto done;
}
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 21 Apr 2017 12:04:38 -0000
@@ -97,10 +97,10 @@ sys_obreak(struct lwp *l, const struct s
*/
if (nbreak > obreak) {
- vm_prot_t prot = UVM_PROT_READ | UVM_PROT_WRITE;
- vm_prot_t maxprot = UVM_PROT_ALL;
-
- PAX_MPROTECT_ADJUST(l, &prot, &maxprot);
+ vm_prot_t prot = UVM_PROT_RW;
+ vm_prot_t maxprot;
+
+ maxprot = PAX_MPROTECT_MAXPROTECT(l, prot, 0, UVM_PROT_ALL);
error = uvm_map(&vm->vm_map, &obreak, nbreak - obreak, NULL,
UVM_UNKNOWN_OFFSET, 0,
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 21 Apr 2017 20:58:45 -0000
@@ -161,7 +161,6 @@ ATF_TC_BODY(mprotect_exec, tc)
break;
}
-
/*
* Map a page read/write and copy a trivial assembly function inside.
* We will then change the mapping rights:
@@ -171,7 +170,8 @@ 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_MPROTECT(PROT_EXEC) | PROT_WRITE|PROT_READ,
+ MAP_ANON, -1, 0);
ATF_REQUIRE(map != MAP_FAILED);
memcpy(map, (void *)return_one,
@@ -312,6 +312,77 @@ 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_MPROTECT(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 +393,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