Changeset View
Changeset View
Standalone View
Standalone View
sys/vm/vm_map.c
Show First 20 Lines • Show All 337 Lines • ▼ Show 20 Lines | vmspace_alloc(vm_offset_t min, vm_offset_t max, pmap_pinit_t pinit) | ||||
vm->vm_shm = NULL; | vm->vm_shm = NULL; | ||||
vm->vm_swrss = 0; | vm->vm_swrss = 0; | ||||
vm->vm_tsize = 0; | vm->vm_tsize = 0; | ||||
vm->vm_dsize = 0; | vm->vm_dsize = 0; | ||||
vm->vm_ssize = 0; | vm->vm_ssize = 0; | ||||
vm->vm_taddr = 0; | vm->vm_taddr = 0; | ||||
vm->vm_daddr = 0; | vm->vm_daddr = 0; | ||||
vm->vm_maxsaddr = 0; | vm->vm_maxsaddr = 0; | ||||
vm->vm_stkgap = 0; | |||||
return (vm); | return (vm); | ||||
} | } | ||||
#ifdef RACCT | #ifdef RACCT | ||||
static void | static void | ||||
vmspace_container_reset(struct proc *p) | vmspace_container_reset(struct proc *p) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 3,904 Lines • ▼ Show 20 Lines | vmspace_fork(struct vmspace *vm1, vm_ooffset_t *fork_charge) | ||||
vm2 = vmspace_alloc(vm_map_min(old_map), vm_map_max(old_map), | vm2 = vmspace_alloc(vm_map_min(old_map), vm_map_max(old_map), | ||||
pmap_pinit); | pmap_pinit); | ||||
if (vm2 == NULL) | if (vm2 == NULL) | ||||
return (NULL); | return (NULL); | ||||
vm2->vm_taddr = vm1->vm_taddr; | vm2->vm_taddr = vm1->vm_taddr; | ||||
vm2->vm_daddr = vm1->vm_daddr; | vm2->vm_daddr = vm1->vm_daddr; | ||||
vm2->vm_maxsaddr = vm1->vm_maxsaddr; | vm2->vm_maxsaddr = vm1->vm_maxsaddr; | ||||
vm2->vm_stkgap = vm1->vm_stkgap; | |||||
vm_map_lock(old_map); | vm_map_lock(old_map); | ||||
if (old_map->busy) | if (old_map->busy) | ||||
vm_map_wait_busy(old_map); | vm_map_wait_busy(old_map); | ||||
new_map = &vm2->vm_map; | new_map = &vm2->vm_map; | ||||
locked = vm_map_trylock(new_map); /* trylock to silence WITNESS */ | locked = vm_map_trylock(new_map); /* trylock to silence WITNESS */ | ||||
KASSERT(locked, ("vmspace_fork: lock failed")); | KASSERT(locked, ("vmspace_fork: lock failed")); | ||||
error = pmap_vmspace_copy(new_map->pmap, old_map->pmap); | error = pmap_vmspace_copy(new_map->pmap, old_map->pmap); | ||||
if (error != 0) { | if (error != 0) { | ||||
sx_xunlock(&old_map->lock); | sx_xunlock(&old_map->lock); | ||||
sx_xunlock(&new_map->lock); | sx_xunlock(&new_map->lock); | ||||
vm_map_process_deferred(); | vm_map_process_deferred(); | ||||
vmspace_free(vm2); | vmspace_free(vm2); | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
new_map->anon_loc = old_map->anon_loc; | new_map->anon_loc = old_map->anon_loc; | ||||
new_map->flags |= old_map->flags & (MAP_ASLR | MAP_ASLR_IGNSTART | | new_map->flags |= old_map->flags & (MAP_ASLR | MAP_ASLR_IGNSTART | | ||||
MAP_WXORX); | MAP_ASLR_STACK | MAP_WXORX); | ||||
VM_MAP_ENTRY_FOREACH(old_entry, old_map) { | VM_MAP_ENTRY_FOREACH(old_entry, old_map) { | ||||
if ((old_entry->eflags & MAP_ENTRY_IS_SUB_MAP) != 0) | if ((old_entry->eflags & MAP_ENTRY_IS_SUB_MAP) != 0) | ||||
panic("vm_map_fork: encountered a submap"); | panic("vm_map_fork: encountered a submap"); | ||||
inh = old_entry->inheritance; | inh = old_entry->inheritance; | ||||
if ((old_entry->eflags & MAP_ENTRY_GUARD) != 0 && | if ((old_entry->eflags & MAP_ENTRY_GUARD) != 0 && | ||||
inh != VM_INHERIT_NONE) | inh != VM_INHERIT_NONE) | ||||
▲ Show 20 Lines • Show All 196 Lines • ▼ Show 20 Lines | SYSCTL_INT(_security_bsd, OID_AUTO, stack_guard_page, CTLFLAG_RWTUN, | ||||
"Specifies the number of guard pages for a stack that grows"); | "Specifies the number of guard pages for a stack that grows"); | ||||
static int | static int | ||||
vm_map_stack_locked(vm_map_t map, vm_offset_t addrbos, vm_size_t max_ssize, | vm_map_stack_locked(vm_map_t map, vm_offset_t addrbos, vm_size_t max_ssize, | ||||
vm_size_t growsize, vm_prot_t prot, vm_prot_t max, int cow) | vm_size_t growsize, vm_prot_t prot, vm_prot_t max, int cow) | ||||
{ | { | ||||
vm_map_entry_t new_entry, prev_entry; | vm_map_entry_t new_entry, prev_entry; | ||||
vm_offset_t bot, gap_bot, gap_top, top; | vm_offset_t bot, gap_bot, gap_top, top; | ||||
vm_size_t init_ssize, sgp; | vm_size_t init_ssize; | ||||
int orient, rv; | int orient, rv; | ||||
/* | /* | ||||
* The stack orientation is piggybacked with the cow argument. | * The stack orientation is piggybacked with the cow argument. | ||||
* Extract it into orient and mask the cow argument so that we | * Extract it into orient and mask the cow argument so that we | ||||
* don't pass it around further. | * don't pass it around further. | ||||
*/ | */ | ||||
orient = cow & (MAP_STACK_GROWS_DOWN | MAP_STACK_GROWS_UP); | orient = cow & (MAP_STACK_GROWS_DOWN | MAP_STACK_GROWS_UP); | ||||
KASSERT(orient != 0, ("No stack grow direction")); | KASSERT(orient != 0, ("No stack grow direction")); | ||||
KASSERT(orient != (MAP_STACK_GROWS_DOWN | MAP_STACK_GROWS_UP), | KASSERT(orient != (MAP_STACK_GROWS_DOWN | MAP_STACK_GROWS_UP), | ||||
("bi-dir stack")); | ("bi-dir stack")); | ||||
if (max_ssize == 0 || | if (max_ssize == 0 || | ||||
!vm_map_range_valid(map, addrbos, addrbos + max_ssize)) | !vm_map_range_valid(map, addrbos, addrbos + max_ssize)) | ||||
return (KERN_INVALID_ADDRESS); | return (KERN_INVALID_ADDRESS); | ||||
sgp = ((curproc->p_flag2 & P2_STKGAP_DISABLE) != 0 || | |||||
(curproc->p_fctl0 & NT_FREEBSD_FCTL_STKGAP_DISABLE) != 0) ? 0 : | |||||
(vm_size_t)stack_guard_page * PAGE_SIZE; | |||||
if (sgp >= max_ssize) | |||||
return (KERN_INVALID_ARGUMENT); | |||||
init_ssize = growsize; | init_ssize = growsize; | ||||
if (max_ssize < init_ssize + sgp) | if (max_ssize < init_ssize) | ||||
init_ssize = max_ssize - sgp; | init_ssize = max_ssize; | ||||
/* If addr is already mapped, no go */ | /* If addr is already mapped, no go */ | ||||
if (vm_map_lookup_entry(map, addrbos, &prev_entry)) | if (vm_map_lookup_entry(map, addrbos, &prev_entry)) | ||||
return (KERN_NO_SPACE); | return (KERN_NO_SPACE); | ||||
/* | /* | ||||
* If we can't accommodate max_ssize in the current mapping, no go. | * If we can't accommodate max_ssize in the current mapping, no go. | ||||
*/ | */ | ||||
Show All 33 Lines | vm_map_stack_locked(vm_map_t map, vm_offset_t addrbos, vm_size_t max_ssize, | ||||
KASSERT((orient & MAP_STACK_GROWS_UP) == 0 || | KASSERT((orient & MAP_STACK_GROWS_UP) == 0 || | ||||
(new_entry->eflags & MAP_ENTRY_GROWS_UP) != 0, | (new_entry->eflags & MAP_ENTRY_GROWS_UP) != 0, | ||||
("new entry lacks MAP_ENTRY_GROWS_UP")); | ("new entry lacks MAP_ENTRY_GROWS_UP")); | ||||
if (gap_bot == gap_top) | if (gap_bot == gap_top) | ||||
return (KERN_SUCCESS); | return (KERN_SUCCESS); | ||||
rv = vm_map_insert(map, NULL, 0, gap_bot, gap_top, VM_PROT_NONE, | rv = vm_map_insert(map, NULL, 0, gap_bot, gap_top, VM_PROT_NONE, | ||||
VM_PROT_NONE, MAP_CREATE_GUARD | (orient == MAP_STACK_GROWS_DOWN ? | VM_PROT_NONE, MAP_CREATE_GUARD | (orient == MAP_STACK_GROWS_DOWN ? | ||||
MAP_CREATE_STACK_GAP_DN : MAP_CREATE_STACK_GAP_UP)); | MAP_CREATE_STACK_GAP_DN : MAP_CREATE_STACK_GAP_UP)); | ||||
if (rv == KERN_SUCCESS) { | if (rv != KERN_SUCCESS) | ||||
/* | |||||
* Gap can never successfully handle a fault, so | |||||
* read-ahead logic is never used for it. Re-use | |||||
* next_read of the gap entry to store | |||||
* stack_guard_page for vm_map_growstack(). | |||||
*/ | |||||
if (orient == MAP_STACK_GROWS_DOWN) | |||||
vm_map_entry_pred(new_entry)->next_read = sgp; | |||||
else | |||||
vm_map_entry_succ(new_entry)->next_read = sgp; | |||||
} else { | |||||
(void)vm_map_delete(map, bot, top); | (void)vm_map_delete(map, bot, top); | ||||
} | |||||
return (rv); | return (rv); | ||||
} | } | ||||
/* | /* | ||||
* Attempts to grow a vm stack entry. Returns KERN_SUCCESS if we | * Attempts to grow a vm stack entry. Returns KERN_SUCCESS if we | ||||
* successfully grow the stack. | * successfully grow the stack. | ||||
*/ | */ | ||||
static int | static int | ||||
vm_map_growstack(vm_map_t map, vm_offset_t addr, vm_map_entry_t gap_entry) | vm_map_growstack(vm_map_t map, vm_offset_t addr, vm_map_entry_t gap_entry) | ||||
{ | { | ||||
vm_map_entry_t stack_entry; | vm_map_entry_t stack_entry; | ||||
struct proc *p; | struct proc *p; | ||||
struct vmspace *vm; | struct vmspace *vm; | ||||
struct ucred *cred; | struct ucred *cred; | ||||
vm_offset_t gap_end, gap_start, grow_start; | vm_offset_t gap_end, gap_start, grow_start; | ||||
vm_size_t grow_amount, guard, max_grow; | vm_size_t grow_amount, max_grow; | ||||
rlim_t lmemlim, stacklim, vmemlim; | rlim_t lmemlim, stacklim, vmemlim; | ||||
int rv, rv1; | int rv, rv1; | ||||
bool gap_deleted, grow_down, is_procstack; | bool gap_deleted, grow_down, is_procstack; | ||||
#ifdef notyet | #ifdef notyet | ||||
uint64_t limit; | uint64_t limit; | ||||
#endif | #endif | ||||
#ifdef RACCT | #ifdef RACCT | ||||
int error; | int error; | ||||
Show All 34 Lines | if ((gap_entry->eflags & MAP_ENTRY_STACK_GAP_DN) != 0) { | ||||
if ((stack_entry->eflags & MAP_ENTRY_GROWS_UP) == 0 || | if ((stack_entry->eflags & MAP_ENTRY_GROWS_UP) == 0 || | ||||
stack_entry->end != gap_entry->start) | stack_entry->end != gap_entry->start) | ||||
return (KERN_FAILURE); | return (KERN_FAILURE); | ||||
grow_amount = round_page(addr + 1 - stack_entry->end); | grow_amount = round_page(addr + 1 - stack_entry->end); | ||||
grow_down = false; | grow_down = false; | ||||
} else { | } else { | ||||
return (KERN_FAILURE); | return (KERN_FAILURE); | ||||
} | } | ||||
guard = ((curproc->p_flag2 & P2_STKGAP_DISABLE) != 0 || | |||||
(curproc->p_fctl0 & NT_FREEBSD_FCTL_STKGAP_DISABLE) != 0) ? 0 : | |||||
gap_entry->next_read; | |||||
max_grow = gap_entry->end - gap_entry->start; | max_grow = gap_entry->end - gap_entry->start; | ||||
if (guard > max_grow) | |||||
return (KERN_NO_SPACE); | |||||
max_grow -= guard; | |||||
if (grow_amount > max_grow) | if (grow_amount > max_grow) | ||||
return (KERN_NO_SPACE); | return (KERN_NO_SPACE); | ||||
/* | /* | ||||
* If this is the main process stack, see if we're over the stack | * If this is the main process stack, see if we're over the stack | ||||
* limit. | * limit. | ||||
*/ | */ | ||||
is_procstack = addr >= (vm_offset_t)vm->vm_maxsaddr && | is_procstack = addr >= (vm_offset_t)vm->vm_maxsaddr && | ||||
▲ Show 20 Lines • Show All 704 Lines • Show Last 20 Lines |