Extend the mmap(2) interface to allow requesting protections for later

use with mprotect(2), but without enabling them immediately.

Extend the mremap(2) interface to allow duplicating mappings, i.e.
create a second range of virtual addresses references the same physical
pages. Duplicated mappings can have different effective protections.

Adjust PAX mprotect logic to disallow effective protections of W&X, but
allow one mapping W and another X protections. This obsoletes using
temporary files for purposes like JIT.

Adjust PAX logic for mmap(2) and mprotect(2) to fail if W&X is requested
and not silently drop the X protection.

Improve test cases to ensure correct operation of the changed
interfaces.
This commit is contained in:
joerg 2017-05-06 21:34:51 +00:00
parent 6c1b86451b
commit 4f77b889d0
15 changed files with 246 additions and 78 deletions

View File

@ -1,4 +1,4 @@
.\" $NetBSD: mmap.2,v 1.48 2015/02/27 16:18:00 christos Exp $
.\" $NetBSD: mmap.2,v 1.49 2017/05/06 21:34:51 joerg Exp $
.\"
.\" Copyright (c) 1991, 1993
.\" The Regents of the University of California. All rights reserved.
@ -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 when requesting no access permission.
.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 special file.
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

View File

@ -1,4 +1,4 @@
.\" $NetBSD: mprotect.2,v 1.24 2011/04/03 06:54:30 jruoho Exp $
.\" $NetBSD: mprotect.2,v 1.25 2017/05/06 21:34:51 joerg Exp $
.\"
.\" Copyright (c) 1991, 1993
.\" The Regents of the University of California. All rights reserved.
@ -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 when requesting no access permission.
.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

View File

@ -1,4 +1,4 @@
.\" $NetBSD: mremap.2,v 1.4 2011/04/28 12:00:55 wiz Exp $
.\" $NetBSD: mremap.2,v 1.5 2017/05/06 21:34:51 joerg Exp $
.\"
.\" Copyright (c) 2007 Thomas Klausner and Joerg Sonnenberger
.\" All rights reserved.
@ -25,7 +25,7 @@
.\" SUCH DAMAGE.
.\"
.\" ------------------------------------------------------------
.Dd February 14, 2008
.Dd April 28, 2017
.Dt MREMAP 2
.Os
.Sh NAME
@ -82,6 +82,9 @@ Otherwise,
and
.Ar newp
are used as hints for the position, factoring in the given alignment.
.It Dv MAP_REMAPDUP
Duplicate the mapping.
Both address ranges reference the same pages, but can have different protection flags.
.El
.Sh RETURN VALUES
.Fn mremap

View File

@ -1,4 +1,4 @@
.\" $NetBSD: uvm_map.9,v 1.6 2014/09/12 21:06:25 riastradh Exp $
.\" $NetBSD: uvm_map.9,v 1.7 2017/05/06 21:34:51 joerg Exp $
.\"
.\" Copyright (c) 1998 Matthew R. Green
.\" All rights reserved.
@ -49,6 +49,9 @@ virtual address space management interface
.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

View File

@ -1,4 +1,4 @@
/* $NetBSD: linux_misc.c,v 1.237 2017/01/28 15:01:01 christos Exp $ */
/* $NetBSD: linux_misc.c,v 1.238 2017/05/06 21:34:51 joerg Exp $ */
/*-
* Copyright (c) 1995, 1998, 1999, 2008 The NetBSD Foundation, Inc.
@ -57,7 +57,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: linux_misc.c,v 1.237 2017/01/28 15:01:01 christos Exp $");
__KERNEL_RCSID(0, "$NetBSD: linux_misc.c,v 1.238 2017/05/06 21:34:51 joerg Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -603,7 +603,7 @@ linux_sys_mprotect(struct lwp *l, const struct linux_sys_mprotect_args *uap, reg
}
}
vm_map_unlock(map);
return uvm_map_protect(map, start, end, prot, FALSE);
return uvm_map_protect_user(l, start, end, prot);
}
#endif /* USRSTACK */

View File

@ -1,4 +1,4 @@
/* $NetBSD: exec_subr.c,v 1.76 2016/05/22 14:26:09 christos Exp $ */
/* $NetBSD: exec_subr.c,v 1.77 2017/05/06 21:34:51 joerg Exp $ */
/*
* Copyright (c) 1993, 1994, 1996 Christopher G. Demetriou
@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: exec_subr.c,v 1.76 2016/05/22 14:26:09 christos Exp $");
__KERNEL_RCSID(0, "$NetBSD: exec_subr.c,v 1.77 2017/05/06 21:34:51 joerg Exp $");
#include "opt_pax.h"
@ -180,8 +180,11 @@ vmcmd_map_pagedvn(struct lwp *l, struct exec_vmcmd *cmd)
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 EACCES;
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_vmcmd *cmd)
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 EACCES;
if ((error = PAX_MPROTECT_VALIDATE(l, prot)))
return error;
#ifdef PMAP_NEED_PROCWR
/*
@ -318,8 +324,11 @@ vmcmd_map_zero(struct lwp *l, struct exec_vmcmd *cmd)
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 EACCES;
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,

View File

@ -1,4 +1,4 @@
/* $NetBSD: kern_pax.c,v 1.58 2017/02/18 01:29:09 chs Exp $ */
/* $NetBSD: kern_pax.c,v 1.59 2017/05/06 21:34:51 joerg Exp $ */
/*
* Copyright (c) 2015 The NetBSD Foundation, Inc.
@ -57,7 +57,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: kern_pax.c,v 1.58 2017/02/18 01:29:09 chs Exp $");
__KERNEL_RCSID(0, "$NetBSD: kern_pax.c,v 1.59 2017/05/06 21:34:51 joerg Exp $");
#include "opt_pax.h"
@ -423,42 +423,48 @@ pax_mprotect_elf_flags_active(uint32_t flags)
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;
if ((*prot & (VM_PROT_WRITE|VM_PROT_EXECUTE)) != VM_PROT_EXECUTE) {
return (active|extra) & maxprot;
}
int
pax_mprotect_validate(
#ifdef PAX_MPROTECT_DEBUG
const char *file, size_t line,
#endif
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_EXECUTE) && pax_mprotect_debug) {
printf("%s: %s,%zu: %d.%d (%s): -x\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_EXECUTE;
*maxprot &= ~VM_PROT_EXECUTE;
} else {
#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",
__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;
}
/*

View File

@ -1,4 +1,4 @@
/* $NetBSD: mman.h,v 1.51 2017/04/29 01:17:47 christos Exp $ */
/* $NetBSD: mman.h,v 1.52 2017/05/06 21:34:52 joerg Exp $ */
/*-
* Copyright (c) 1982, 1986, 1993
@ -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.
@ -75,6 +85,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 */

View File

@ -1,4 +1,4 @@
/* $NetBSD: pax.h,v 1.25 2016/09/03 12:20:58 christos Exp $ */
/* $NetBSD: pax.h,v 1.26 2017/05/06 21:34:52 joerg Exp $ */
/*-
* Copyright (c) 2006 Elad Efrat <elad@NetBSD.org>
@ -63,23 +63,34 @@ void pax_setup_elf_flags(struct exec_package *, uint32_t);
# 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);

View File

@ -1,4 +1,4 @@
/* $NetBSD: uvm_extern.h,v 1.203 2017/01/04 23:59:49 christos Exp $ */
/* $NetBSD: uvm_extern.h,v 1.204 2017/05/06 21:34:52 joerg Exp $ */
/*
* Copyright (c) 1997 Charles D. Cranor and Washington University.
@ -662,6 +662,8 @@ bool uvm_map_checkprot(struct vm_map *, vaddr_t,
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);

View File

@ -1,4 +1,4 @@
/* $NetBSD: uvm_map.c,v 1.343 2017/03/15 20:25:41 christos Exp $ */
/* $NetBSD: uvm_map.c,v 1.344 2017/05/06 21:34:52 joerg Exp $ */
/*
* Copyright (c) 1997 Charles D. Cranor and Washington University.
@ -66,9 +66,10 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: uvm_map.c,v 1.343 2017/03/15 20:25:41 christos Exp $");
__KERNEL_RCSID(0, "$NetBSD: uvm_map.c,v 1.344 2017/05/06 21:34:52 joerg 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 1.343 2017/03/15 20:25:41 christos Exp $
#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>
@ -2950,6 +2952,24 @@ uvm_map_submap(struct vm_map *map, vaddr_t start, vaddr_t end,
return error;
}
/*
* 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
*

View File

@ -1,4 +1,4 @@
/* $NetBSD: uvm_mmap.c,v 1.163 2017/04/29 01:18:35 christos Exp $ */
/* $NetBSD: uvm_mmap.c,v 1.164 2017/05/06 21:34:52 joerg Exp $ */
/*
* Copyright (c) 1997 Charles D. Cranor and Washington University.
@ -46,7 +46,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: uvm_mmap.c,v 1.163 2017/04/29 01:18:35 christos Exp $");
__KERNEL_RCSID(0, "$NetBSD: uvm_mmap.c,v 1.164 2017/05/06 21:34:52 joerg Exp $");
#include "opt_compat_netbsd.h"
#include "opt_pax.h"
@ -287,7 +287,7 @@ sys_mmap(struct lwp *l, const struct sys_mmap_args *uap, register_t *retval)
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_mmap_args *uap, register_t *retval)
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);
@ -396,7 +397,11 @@ sys_mmap(struct lwp *l, const struct sys_mmap_args *uap, register_t *retval)
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);
@ -612,8 +617,7 @@ sys_mprotect(struct lwp *l, const struct sys_mprotect_args *uap,
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;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: uvm_mremap.c,v 1.18 2015/11/26 13:15:34 martin Exp $ */
/* $NetBSD: uvm_mremap.c,v 1.19 2017/05/06 21:34:52 joerg Exp $ */
/*-
* Copyright (c)2006,2007,2009 YAMAMOTO Takashi,
@ -27,7 +27,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: uvm_mremap.c,v 1.18 2015/11/26 13:15:34 martin Exp $");
__KERNEL_RCSID(0, "$NetBSD: uvm_mremap.c,v 1.19 2017/05/06 21:34:52 joerg Exp $");
#include <sys/param.h>
#include <sys/mman.h>
@ -120,6 +120,7 @@ uvm_mremap(struct vm_map *oldmap, vaddr_t oldva, vsize_t oldsize,
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_t oldva, vsize_t oldsize,
* 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 sys_mremap_args *uap, register_t *retval)
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;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: uvm_unix.c,v 1.47 2016/04/07 12:07:36 christos Exp $ */
/* $NetBSD: uvm_unix.c,v 1.48 2017/05/06 21:34:52 joerg Exp $ */
/*
* Copyright (c) 1997 Charles D. Cranor and Washington University.
@ -45,7 +45,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: uvm_unix.c,v 1.47 2016/04/07 12:07:36 christos Exp $");
__KERNEL_RCSID(0, "$NetBSD: uvm_unix.c,v 1.48 2017/05/06 21:34:52 joerg Exp $");
#include "opt_pax.h"
@ -97,10 +97,10 @@ sys_obreak(struct lwp *l, const struct sys_obreak_args *uap, register_t *retval)
*/
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,

View File

@ -1,4 +1,4 @@
/* $NetBSD: t_mprotect.c,v 1.6 2017/03/25 01:39:20 pgoyette Exp $ */
/* $NetBSD: t_mprotect.c,v 1.7 2017/05/06 21:34:52 joerg Exp $ */
/*-
* Copyright (c) 2011 The NetBSD Foundation, Inc.
@ -29,7 +29,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__RCSID("$NetBSD: t_mprotect.c,v 1.6 2017/03/25 01:39:20 pgoyette Exp $");
__RCSID("$NetBSD: t_mprotect.c,v 1.7 2017/05/06 21:34:52 joerg Exp $");
#include <sys/param.h>
#include <sys/mman.h>
@ -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();
}