From 5fd3f8b3b697d1ff60f5ef3b15e4feae3f28a070 Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Mon, 15 Sep 2014 17:20:13 +0000 Subject: [PATCH] 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 --- lib/libc/sys/mmap.2 | 25 ++++++++++++++++++++++++- sys/vm/vm_mmap.c | 23 ++++++++++++++++++++--- 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/lib/libc/sys/mmap.2 b/lib/libc/sys/mmap.2 index 3dd830326ad0..4a561ea1921a 100644 --- a/lib/libc/sys/mmap.2 +++ b/lib/libc/sys/mmap.2 @@ -28,7 +28,7 @@ .\" @(#)mmap.2 8.4 (Berkeley) 5/11/95 .\" $FreeBSD$ .\" -.Dd June 19, 2014 +.Dd September 15, 2014 .Dt MMAP 2 .Os .Sh NAME @@ -372,6 +372,29 @@ The argument is not a valid open file descriptor. .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 was specified and the .Fa addr diff --git a/sys/vm/vm_mmap.c b/sys/vm/vm_mmap.c index 1ae7189b97ca..630a79f3f6cc 100644 --- a/sys/vm/vm_mmap.c +++ b/sys/vm/vm_mmap.c @@ -203,17 +203,17 @@ sys_mmap(td, uap) struct vnode *vp; vm_offset_t addr; vm_size_t size, pageoff; - vm_prot_t cap_maxprot, prot, maxprot; + vm_prot_t cap_maxprot, maxprot; void *handle; objtype_t handle_type; - int align, error, flags; + int align, error, flags, prot; off_t pos; struct vmspace *vms = td->td_proc->p_vmspace; cap_rights_t rights; addr = (vm_offset_t) uap->addr; size = uap->len; - prot = uap->prot & VM_PROT_ALL; + prot = uap->prot; flags = uap->flags; pos = uap->pos; @@ -244,8 +244,23 @@ sys_mmap(td, uap) flags |= MAP_ANON; 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) 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, @@ -415,6 +430,8 @@ sys_mmap(td, uap) map: td->td_fpop = fp; maxprot &= cap_maxprot; + + /* This relies on VM_PROT_* matching PROT_*. */ error = vm_mmap(&vms->vm_map, &addr, size, prot, maxprot, flags, handle_type, handle, pos); td->td_fpop = NULL;