From c7841c6b8e41ea0567d5320a13f33856d6feaca7 Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Mon, 13 Apr 2020 19:20:39 +0000 Subject: [PATCH] Relax restrictions on private mappings of POSIX shm objects. When creating a private mapping of a POSIX shared memory object, VM_PROT_WRITE should always be included in maxprot regardless of permissions on the underlying FD. Otherwise it is possible to open a shm object read-only, map it with MAP_PRIVATE and PROT_WRITE, and violate the invariant in vm_map_insert() that (prot & maxprot) == prot. Reported by: syzkaller Reviewed by: kevans, kib MFC after: 1 week Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D24398 --- sys/kern/uipc_shm.c | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/sys/kern/uipc_shm.c b/sys/kern/uipc_shm.c index 886a0bad8746..a5f550f35e62 100644 --- a/sys/kern/uipc_shm.c +++ b/sys/kern/uipc_shm.c @@ -1136,23 +1136,28 @@ shm_mmap(struct file *fp, vm_map_t map, vm_offset_t *addr, vm_size_t objsize, /* * If FWRITE's set, we can allow VM_PROT_WRITE unless it's a shared - * mapping with a write seal applied. + * mapping with a write seal applied. Private mappings are always + * writeable. */ - if ((fp->f_flag & FWRITE) != 0 && ((flags & MAP_SHARED) == 0 || - (shmfd->shm_seals & F_SEAL_WRITE) == 0)) + if ((flags & MAP_SHARED) == 0) { + cap_maxprot |= VM_PROT_WRITE; maxprot |= VM_PROT_WRITE; + writecnt = false; + } else { + if ((fp->f_flag & FWRITE) != 0 && + (shmfd->shm_seals & F_SEAL_WRITE) == 0) + maxprot |= VM_PROT_WRITE; + writecnt = (prot & VM_PROT_WRITE) != 0; + if (writecnt && (shmfd->shm_seals & F_SEAL_WRITE) != 0) { + error = EPERM; + goto out; + } - writecnt = (flags & MAP_SHARED) != 0 && (prot & VM_PROT_WRITE) != 0; - - if (writecnt && (shmfd->shm_seals & F_SEAL_WRITE) != 0) { - error = EPERM; - goto out; - } - - /* Don't permit shared writable mappings on read-only descriptors. */ - if (writecnt && (maxprot & VM_PROT_WRITE) == 0) { - error = EACCES; - goto out; + /* Don't permit shared writable mappings on read-only descriptors. */ + if (writecnt && (maxprot & VM_PROT_WRITE) == 0) { + error = EACCES; + goto out; + } } maxprot &= cap_maxprot;