Changeset View
Changeset View
Standalone View
Standalone View
head/sys/vm/vm_mmap.c
Show First 20 Lines • Show All 97 Lines • ▼ Show 20 Lines | |||||
#endif | #endif | ||||
int old_mlock = 0; | int old_mlock = 0; | ||||
SYSCTL_INT(_vm, OID_AUTO, old_mlock, CTLFLAG_RWTUN, &old_mlock, 0, | SYSCTL_INT(_vm, OID_AUTO, old_mlock, CTLFLAG_RWTUN, &old_mlock, 0, | ||||
"Do not apply RLIMIT_MEMLOCK on mlockall"); | "Do not apply RLIMIT_MEMLOCK on mlockall"); | ||||
static int mincore_mapped = 1; | static int mincore_mapped = 1; | ||||
SYSCTL_INT(_vm, OID_AUTO, mincore_mapped, CTLFLAG_RWTUN, &mincore_mapped, 0, | SYSCTL_INT(_vm, OID_AUTO, mincore_mapped, CTLFLAG_RWTUN, &mincore_mapped, 0, | ||||
"mincore reports mappings, not residency"); | "mincore reports mappings, not residency"); | ||||
static int imply_prot_max = 0; | |||||
SYSCTL_INT(_vm, OID_AUTO, imply_prot_max, CTLFLAG_RWTUN, &imply_prot_max, 0, | |||||
"Imply maximum page permissions in mmap() when none are specified"); | |||||
#ifdef MAP_32BIT | #ifdef MAP_32BIT | ||||
#define MAP_32BIT_MAX_ADDR ((vm_offset_t)1 << 31) | #define MAP_32BIT_MAX_ADDR ((vm_offset_t)1 << 31) | ||||
#endif | #endif | ||||
#ifndef _SYS_SYSPROTO_H_ | #ifndef _SYS_SYSPROTO_H_ | ||||
struct sbrk_args { | struct sbrk_args { | ||||
int incr; | int incr; | ||||
▲ Show 20 Lines • Show All 68 Lines • ▼ Show 20 Lines | |||||
kern_mmap(struct thread *td, uintptr_t addr0, size_t len, int prot, int flags, | kern_mmap(struct thread *td, uintptr_t addr0, size_t len, int prot, int flags, | ||||
int fd, off_t pos) | int fd, off_t pos) | ||||
{ | { | ||||
struct vmspace *vms; | struct vmspace *vms; | ||||
struct file *fp; | struct file *fp; | ||||
vm_offset_t addr; | vm_offset_t addr; | ||||
vm_size_t pageoff, size; | vm_size_t pageoff, size; | ||||
vm_prot_t cap_maxprot; | vm_prot_t cap_maxprot; | ||||
int align, error; | int align, error, max_prot; | ||||
cap_rights_t rights; | cap_rights_t rights; | ||||
if ((prot & ~(_PROT_ALL | PROT_MAX(_PROT_ALL))) != 0) | |||||
return (EINVAL); | |||||
max_prot = PROT_MAX_EXTRACT(prot); | |||||
prot = PROT_EXTRACT(prot); | |||||
if (max_prot != 0 && (max_prot & prot) != prot) | |||||
return (EINVAL); | |||||
/* | |||||
* Always honor PROT_MAX if set. If not, default to all | |||||
* permissions unless we're implying maximum permissions. | |||||
* | |||||
* XXX: should be tunable per process and ABI. | |||||
*/ | |||||
if (max_prot == 0) | |||||
max_prot = (imply_prot_max && prot != PROT_NONE) ? | |||||
prot : _PROT_ALL; | |||||
vms = td->td_proc->p_vmspace; | vms = td->td_proc->p_vmspace; | ||||
fp = NULL; | fp = NULL; | ||||
AUDIT_ARG_FD(fd); | AUDIT_ARG_FD(fd); | ||||
addr = addr0; | addr = addr0; | ||||
/* | /* | ||||
* Ignore old flags that used to be defined but did not do anything. | * Ignore old flags that used to be defined but did not do anything. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 129 Lines • ▼ Show 20 Lines | error = vm_mmap_object(&vms->vm_map, &addr, size, VM_PROT_NONE, | ||||
VM_PROT_NONE, flags, NULL, pos, FALSE, td); | VM_PROT_NONE, flags, NULL, pos, FALSE, td); | ||||
} else if ((flags & MAP_ANON) != 0) { | } else if ((flags & MAP_ANON) != 0) { | ||||
/* | /* | ||||
* Mapping blank space is trivial. | * Mapping blank space is trivial. | ||||
* | * | ||||
* This relies on VM_PROT_* matching PROT_*. | * This relies on VM_PROT_* matching PROT_*. | ||||
*/ | */ | ||||
error = vm_mmap_object(&vms->vm_map, &addr, size, prot, | error = vm_mmap_object(&vms->vm_map, &addr, size, prot, | ||||
VM_PROT_ALL, flags, NULL, pos, FALSE, td); | max_prot, flags, NULL, pos, FALSE, td); | ||||
} else { | } else { | ||||
/* | /* | ||||
* Mapping file, get fp for validation and don't let the | * Mapping file, get fp for validation and don't let the | ||||
* descriptor disappear on us if we block. Check capability | * descriptor disappear on us if we block. Check capability | ||||
* rights, but also return the maximum rights to be combined | * rights, but also return the maximum rights to be combined | ||||
* with maxprot later. | * with maxprot later. | ||||
*/ | */ | ||||
cap_rights_init(&rights, CAP_MMAP); | cap_rights_init(&rights, CAP_MMAP); | ||||
Show All 11 Lines | if (len == 0) { | ||||
if ((flags & (MAP_SHARED | MAP_PRIVATE)) == 0 && | if ((flags & (MAP_SHARED | MAP_PRIVATE)) == 0 && | ||||
td->td_proc->p_osrel >= P_OSREL_MAP_FSTRICT) { | td->td_proc->p_osrel >= P_OSREL_MAP_FSTRICT) { | ||||
error = EINVAL; | error = EINVAL; | ||||
goto done; | goto done; | ||||
} | } | ||||
/* This relies on VM_PROT_* matching PROT_*. */ | /* This relies on VM_PROT_* matching PROT_*. */ | ||||
error = fo_mmap(fp, &vms->vm_map, &addr, size, prot, | error = fo_mmap(fp, &vms->vm_map, &addr, size, prot, | ||||
cap_maxprot, flags, pos, td); | max_prot & cap_maxprot, flags, pos, td); | ||||
} | } | ||||
if (error == 0) | if (error == 0) | ||||
td->td_retval[0] = (register_t) (addr + pageoff); | td->td_retval[0] = (register_t) (addr + pageoff); | ||||
done: | done: | ||||
if (fp) | if (fp) | ||||
fdrop(fp, td); | fdrop(fp, td); | ||||
▲ Show 20 Lines • Show All 214 Lines • ▼ Show 20 Lines | sys_mprotect(struct thread *td, struct mprotect_args *uap) | ||||
return (kern_mprotect(td, (uintptr_t)uap->addr, uap->len, uap->prot)); | return (kern_mprotect(td, (uintptr_t)uap->addr, uap->len, uap->prot)); | ||||
} | } | ||||
int | int | ||||
kern_mprotect(struct thread *td, uintptr_t addr0, size_t size, int prot) | kern_mprotect(struct thread *td, uintptr_t addr0, size_t size, int prot) | ||||
{ | { | ||||
vm_offset_t addr; | vm_offset_t addr; | ||||
vm_size_t pageoff; | vm_size_t pageoff; | ||||
int vm_error, max_prot; | |||||
addr = addr0; | addr = addr0; | ||||
prot = (prot & VM_PROT_ALL); | if ((prot & ~(_PROT_ALL | PROT_MAX(_PROT_ALL))) != 0) | ||||
return (EINVAL); | |||||
max_prot = PROT_MAX_EXTRACT(prot); | |||||
prot = PROT_EXTRACT(prot); | |||||
pageoff = (addr & PAGE_MASK); | pageoff = (addr & PAGE_MASK); | ||||
addr -= pageoff; | addr -= pageoff; | ||||
size += pageoff; | size += pageoff; | ||||
size = (vm_size_t) round_page(size); | size = (vm_size_t) round_page(size); | ||||
#ifdef COMPAT_FREEBSD32 | #ifdef COMPAT_FREEBSD32 | ||||
if (SV_PROC_FLAG(td->td_proc, SV_ILP32)) { | if (SV_PROC_FLAG(td->td_proc, SV_ILP32)) { | ||||
if (((addr + size) & 0xffffffff) < addr) | if (((addr + size) & 0xffffffff) < addr) | ||||
return (EINVAL); | return (EINVAL); | ||||
} else | } else | ||||
#endif | #endif | ||||
if (addr + size < addr) | if (addr + size < addr) | ||||
return (EINVAL); | return (EINVAL); | ||||
switch (vm_map_protect(&td->td_proc->p_vmspace->vm_map, addr, | vm_error = KERN_SUCCESS; | ||||
addr + size, prot, FALSE)) { | if (max_prot != 0) { | ||||
if ((max_prot & prot) != prot) | |||||
return (EINVAL); | |||||
vm_error = vm_map_protect(&td->td_proc->p_vmspace->vm_map, | |||||
addr, addr + size, max_prot, TRUE); | |||||
} | |||||
if (vm_error == KERN_SUCCESS) | |||||
vm_error = vm_map_protect(&td->td_proc->p_vmspace->vm_map, | |||||
addr, addr + size, prot, FALSE); | |||||
switch (vm_error) { | |||||
case KERN_SUCCESS: | case KERN_SUCCESS: | ||||
return (0); | return (0); | ||||
case KERN_PROTECTION_FAILURE: | case KERN_PROTECTION_FAILURE: | ||||
return (EACCES); | return (EACCES); | ||||
case KERN_RESOURCE_SHORTAGE: | case KERN_RESOURCE_SHORTAGE: | ||||
return (ENOMEM); | return (ENOMEM); | ||||
} | } | ||||
return (EINVAL); | return (EINVAL); | ||||
▲ Show 20 Lines • Show All 977 Lines • Show Last 20 Lines |