The branch main has been updated by kib: URL: https://cgit.FreeBSD.org/src/commit/?id=f1ad4340e4adfbe9e64b4e2e9e9b19d87fa84eef
commit f1ad4340e4adfbe9e64b4e2e9e9b19d87fa84eef Author: Konstantin Belousov <k...@freebsd.org> AuthorDate: 2025-06-11 08:36:20 +0000 Commit: Konstantin Belousov <k...@freebsd.org> CommitDate: 2025-06-12 20:32:26 +0000 vm/vm_mmap.c: provide extended errors for most places Reviewed by: brooks Sponsored by: The FreeBSD Foundation Differential revision: https://reviews.freebsd.org/D50792 --- sys/vm/vm_mmap.c | 103 +++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 81 insertions(+), 22 deletions(-) diff --git a/sys/vm/vm_mmap.c b/sys/vm/vm_mmap.c index 492233215d4b..8444a8cbf021 100644 --- a/sys/vm/vm_mmap.c +++ b/sys/vm/vm_mmap.c @@ -231,35 +231,53 @@ kern_mmap(struct thread *td, const struct mmap_req *mrp) */ if (!SV_CURPROC_FLAG(SV_AOUT)) { if ((len == 0 && p->p_osrel >= P_OSREL_MAP_ANON) || - ((flags & MAP_ANON) != 0 && (fd != -1 || pos != 0))) + ((flags & MAP_ANON) != 0 && (fd != -1 || pos != 0))) { + SET_ERROR2(EINVAL, + "offset not zero/fd not -1 for MAP_ANON", + fd, pos); return (EINVAL); + } } else { if ((flags & MAP_ANON) != 0) pos = 0; } if (flags & MAP_STACK) { - if ((fd != -1) || - ((prot & (PROT_READ | PROT_WRITE)) != (PROT_READ | PROT_WRITE))) + if ((fd != -1) || ((prot & (PROT_READ | PROT_WRITE)) != + (PROT_READ | PROT_WRITE))) { + SET_ERROR1(EINVAL, "MAP_STACK with prot < rw", prot); return (EINVAL); + } flags |= MAP_ANON; pos = 0; } if ((flags & ~(MAP_SHARED | MAP_PRIVATE | MAP_FIXED | MAP_HASSEMAPHORE | MAP_STACK | MAP_NOSYNC | MAP_ANON | MAP_EXCL | MAP_NOCORE | - MAP_PREFAULT_READ | MAP_GUARD | MAP_32BIT | MAP_ALIGNMENT_MASK)) != 0) + MAP_PREFAULT_READ | MAP_GUARD | MAP_32BIT | + MAP_ALIGNMENT_MASK)) != 0) { + SET_ERROR0(EINVAL, "reserved flag set"); return (EINVAL); - if ((flags & (MAP_EXCL | MAP_FIXED)) == MAP_EXCL) + } + if ((flags & (MAP_EXCL | MAP_FIXED)) == MAP_EXCL) { + SET_ERROR0(EINVAL, "EXCL without FIXED"); return (EINVAL); - if ((flags & (MAP_SHARED | MAP_PRIVATE)) == (MAP_SHARED | MAP_PRIVATE)) + } + if ((flags & (MAP_SHARED | MAP_PRIVATE)) == (MAP_SHARED | + MAP_PRIVATE)) { + SET_ERROR0(EINVAL, "both SHARED and PRIVATE set"); return (EINVAL); + } if (prot != PROT_NONE && - (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC)) != 0) + (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC)) != 0) { + SET_ERROR1(EINVAL, "invalid prot", prot); return (EINVAL); + } if ((flags & MAP_GUARD) != 0 && (prot != PROT_NONE || fd != -1 || pos != 0 || (flags & ~(MAP_FIXED | MAP_GUARD | MAP_EXCL | - MAP_32BIT | MAP_ALIGNMENT_MASK)) != 0)) + MAP_32BIT | MAP_ALIGNMENT_MASK)) != 0)) { + SET_ERROR0(EINVAL, "GUARD with wrong parameters"); return (EINVAL); + } /* * Align the file position to a page boundary, @@ -279,8 +297,10 @@ kern_mmap(struct thread *td, const struct mmap_req *mrp) align = flags & MAP_ALIGNMENT_MASK; if (align != 0 && align != MAP_ALIGNED_SUPER && (align >> MAP_ALIGNMENT_SHIFT >= sizeof(void *) * NBBY || - align >> MAP_ALIGNMENT_SHIFT < PAGE_SHIFT)) + align >> MAP_ALIGNMENT_SHIFT < PAGE_SHIFT)) { + SET_ERROR1(EINVAL, "bad alignment", align); return (EINVAL); + } /* * Check for illegal addresses. Watch out for address wrap... Note @@ -293,14 +313,21 @@ kern_mmap(struct thread *td, const struct mmap_req *mrp) * should be aligned after adjustment by pageoff. */ addr -= pageoff; - if (addr & PAGE_MASK) + if ((addr & PAGE_MASK) != 0) { + SET_ERROR1(EINVAL, "fixed mapping not aligned", addr); return (EINVAL); + } /* Address range must be all in user VM space. */ - if (!vm_map_range_valid(&vms->vm_map, addr, addr + size)) + if (!vm_map_range_valid(&vms->vm_map, addr, addr + size)) { + SET_ERROR0(EINVAL, "mapping outside vm_map"); return (EINVAL); - if (flags & MAP_32BIT && addr + size > MAP_32BIT_MAX_ADDR) + } + if (flags & MAP_32BIT && addr + size > MAP_32BIT_MAX_ADDR) { + SET_ERROR0(EINVAL, + "fixed 32bit mapping does not fit into 4G"); return (EINVAL); + } } else if (flags & MAP_32BIT) { /* * For MAP_32BIT, override the hint if it is too high and @@ -367,6 +394,7 @@ kern_mmap(struct thread *td, const struct mmap_req *mrp) goto done; if ((flags & (MAP_SHARED | MAP_PRIVATE)) == 0 && p->p_osrel >= P_OSREL_MAP_FSTRICT) { + SET_ERROR0(EINVAL, "neither SHARED nor PRIVATE req"); error = EINVAL; goto done; } @@ -1296,6 +1324,7 @@ vm_mmap_vnode(struct thread *td, vm_size_t objsize, vm_pager_update_writecount(obj, 0, objsize); } } else { + SET_ERROR0(EINVAL, "non-reg file"); error = EINVAL; goto done; } @@ -1379,14 +1408,18 @@ vm_mmap_cdev(struct thread *td, vm_size_t objsize, vm_prot_t prot, *flagsp |= MAP_ANON; return (0); } + /* * cdevs do not provide private mappings of any kind. */ if ((*maxprotp & VM_PROT_WRITE) == 0 && (prot & VM_PROT_WRITE) != 0) return (EACCES); - if (flags & (MAP_PRIVATE|MAP_COPY)) + if ((flags & (MAP_PRIVATE | MAP_COPY)) != 0) { + SET_ERROR0(EINVAL, "cdev mapping must be shared"); return (EINVAL); + } + /* * Force device mappings to be shared. */ @@ -1410,8 +1443,10 @@ vm_mmap_cdev(struct thread *td, vm_size_t objsize, vm_prot_t prot, return (error); obj = vm_pager_allocate(OBJT_DEVICE, cdev, objsize, prot, *foff, td->td_ucred); - if (obj == NULL) + if (obj == NULL) { + SET_ERROR0(EINVAL, "cdev driver does not support mmap"); return (EINVAL); + } *objp = obj; *flagsp = flags; return (0); @@ -1428,8 +1463,10 @@ vm_mmap(vm_map_t map, vm_offset_t *addr, vm_size_t size, vm_prot_t prot, int error; boolean_t writecounted; - if (size == 0) + if (size == 0) { + SET_ERROR0(EINVAL, "zero-sized req"); return (EINVAL); + } size = round_page(size); object = NULL; @@ -1455,6 +1492,7 @@ vm_mmap(vm_map_t map, vm_offset_t *addr, vm_size_t size, vm_prot_t prot, handle, &foff, &object, &writecounted); break; default: + SET_ERROR1(EINVAL, "unsupported backing obj type", handle_type); error = EINVAL; break; } @@ -1536,21 +1574,32 @@ vm_mmap_object(vm_map_t map, vm_offset_t *addr, vm_size_t size, vm_prot_t prot, * callbacks) and other internal mapping requests (such as in * exec). */ - if (foff & PAGE_MASK) + if ((foff & PAGE_MASK) != 0) { + SET_ERROR1(EINVAL, "offset not page-aligned", foff); return (EINVAL); + } if ((flags & MAP_FIXED) == 0) { fitit = true; *addr = round_page(*addr); } else { - if (*addr != trunc_page(*addr)) + if (*addr != trunc_page(*addr)) { + SET_ERROR1(EINVAL, + "non-fixed mapping address not aligned", *addr); return (EINVAL); + } fitit = false; } if (flags & MAP_ANON) { - if (object != NULL || foff != 0) + if (object != NULL) { + SET_ERROR0(EINVAL, "anon mapping backed by an object"); + return (EINVAL); + } + if (foff != 0) { + SET_ERROR0(EINVAL, "anon mapping with non-zero offset"); return (EINVAL); + } docow = 0; } else if (flags & MAP_PREFAULT_READ) docow = MAP_PREFAULT; @@ -1569,8 +1618,10 @@ vm_mmap_object(vm_map_t map, vm_offset_t *addr, vm_size_t size, vm_prot_t prot, if (writecounted) docow |= MAP_WRITECOUNT; if (flags & MAP_STACK) { - if (object != NULL) + if (object != NULL) { + SET_ERROR0(EINVAL, "stack mapping backed by an object"); return (EINVAL); + } docow |= MAP_STACK_AREA; } if ((flags & MAP_EXCL) != 0) @@ -1632,16 +1683,24 @@ vm_mmap_object(vm_map_t map, vm_offset_t *addr, vm_size_t size, vm_prot_t prot, int vm_mmap_to_errno(int rv) { + int error; switch (rv) { case KERN_SUCCESS: return (0); case KERN_INVALID_ADDRESS: case KERN_NO_SPACE: - return (ENOMEM); + error = ENOMEM; + break; case KERN_PROTECTION_FAILURE: - return (EACCES); + error = EACCES; + break; default: - return (EINVAL); + error = EINVAL; + break; } + if ((curthread->td_pflags2 & (TDP2_UEXTERR | TDP2_EXTERR)) == + TDP2_UEXTERR) + SET_ERROR1(error, "mach error", rv); + return (error); }