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);
 }

Reply via email to