Add stricter checking of some mmap() arguments:

- Fail with EINVAL if an invalid protection mask is passed to mmap().
- Fail with EINVAL if an unknown flag is passed to mmap().
- Fail with EINVAL if both MAP_PRIVATE and MAP_SHARED are passed to mmap().
- Require one of either MAP_PRIVATE or MAP_SHARED for non-anonymous
  mappings.

Reviewed by:	alc, kib
MFC after:	2 weeks
Differential Revision:	https://reviews.freebsd.org/D698
This commit is contained in:
John Baldwin 2014-09-15 17:20:13 +00:00
parent a7fecb4d3a
commit 5fd3f8b3b6
2 changed files with 44 additions and 4 deletions
lib/libc/sys
sys/vm

@ -28,7 +28,7 @@
.\" @(#)mmap.2 8.4 (Berkeley) 5/11/95 .\" @(#)mmap.2 8.4 (Berkeley) 5/11/95
.\" $FreeBSD$ .\" $FreeBSD$
.\" .\"
.Dd June 19, 2014 .Dd September 15, 2014
.Dt MMAP 2 .Dt MMAP 2
.Os .Os
.Sh NAME .Sh NAME
@ -372,6 +372,29 @@ The
argument argument
is not a valid open file descriptor. is not a valid open file descriptor.
.It Bq Er EINVAL .It Bq Er EINVAL
An invalid value was passed in the
.Fa prot
argument.
.It Bq Er EINVAL
An undefined option was set in the
.Fa flags
argument.
.It Bq Er EINVAL
Both
.Dv MAP_PRIVATE
and
.Dv MAP_SHARED
were specified.
.It Bq Er EINVAL
None of
.Dv MAP_ANON ,
.Dv MAP_PRIVATE ,
.Dv MAP_SHARED ,
or
.Dv MAP_STACK
was specified.
At least one of these flags must be included.
.It Bq Er EINVAL
.Dv MAP_FIXED .Dv MAP_FIXED
was specified and the was specified and the
.Fa addr .Fa addr

@ -203,17 +203,17 @@ sys_mmap(td, uap)
struct vnode *vp; struct vnode *vp;
vm_offset_t addr; vm_offset_t addr;
vm_size_t size, pageoff; vm_size_t size, pageoff;
vm_prot_t cap_maxprot, prot, maxprot; vm_prot_t cap_maxprot, maxprot;
void *handle; void *handle;
objtype_t handle_type; objtype_t handle_type;
int align, error, flags; int align, error, flags, prot;
off_t pos; off_t pos;
struct vmspace *vms = td->td_proc->p_vmspace; struct vmspace *vms = td->td_proc->p_vmspace;
cap_rights_t rights; cap_rights_t rights;
addr = (vm_offset_t) uap->addr; addr = (vm_offset_t) uap->addr;
size = uap->len; size = uap->len;
prot = uap->prot & VM_PROT_ALL; prot = uap->prot;
flags = uap->flags; flags = uap->flags;
pos = uap->pos; pos = uap->pos;
@ -244,8 +244,23 @@ sys_mmap(td, uap)
flags |= MAP_ANON; flags |= MAP_ANON;
pos = 0; pos = 0;
} }
/* XXX: MAP_RENAME, MAP_NORESERVE */
if ((flags & ~(MAP_SHARED | MAP_PRIVATE | MAP_FIXED | MAP_HASSEMAPHORE |
MAP_STACK | MAP_NOSYNC | MAP_ANON | MAP_EXCL | MAP_NOCORE |
MAP_PREFAULT_READ |
#ifdef MAP_32BIT
MAP_32BIT |
#endif
MAP_ALIGNMENT_MASK)) != 0)
return (EINVAL);
if ((flags & (MAP_EXCL | MAP_FIXED)) == MAP_EXCL) if ((flags & (MAP_EXCL | MAP_FIXED)) == MAP_EXCL)
return (EINVAL); return (EINVAL);
if ((flags & (MAP_ANON | MAP_SHARED | MAP_PRIVATE)) == 0 ||
(flags & (MAP_SHARED | MAP_PRIVATE)) == (MAP_SHARED | MAP_PRIVATE))
return (EINVAL);
if (prot != PROT_NONE &&
(prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC)) != 0)
return (EINVAL);
/* /*
* Align the file position to a page boundary, * Align the file position to a page boundary,
@ -415,6 +430,8 @@ sys_mmap(td, uap)
map: map:
td->td_fpop = fp; td->td_fpop = fp;
maxprot &= cap_maxprot; maxprot &= cap_maxprot;
/* This relies on VM_PROT_* matching PROT_*. */
error = vm_mmap(&vms->vm_map, &addr, size, prot, maxprot, error = vm_mmap(&vms->vm_map, &addr, size, prot, maxprot,
flags, handle_type, handle, pos); flags, handle_type, handle, pos);
td->td_fpop = NULL; td->td_fpop = NULL;