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:
parent
6c1b86451b
commit
4f77b889d0
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user