mirror of
https://github.com/opnsense/src.git
synced 2026-06-12 10:10:24 -04:00
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
This commit is contained in:
parent
deeda8abd5
commit
f1ad4340e4
1 changed files with 81 additions and 22 deletions
103
sys/vm/vm_mmap.c
103
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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue