Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/kern_exec.c
Show First 20 Lines • Show All 113 Lines • ▼ Show 20 Lines | |||||
int coredump_pack_vmmapinfo = 1; | int coredump_pack_vmmapinfo = 1; | ||||
SYSCTL_INT(_kern, OID_AUTO, coredump_pack_vmmapinfo, CTLFLAG_RWTUN, | SYSCTL_INT(_kern, OID_AUTO, coredump_pack_vmmapinfo, CTLFLAG_RWTUN, | ||||
&coredump_pack_vmmapinfo, 0, | &coredump_pack_vmmapinfo, 0, | ||||
"Enable file path packing in 'procstat -v' coredump notes"); | "Enable file path packing in 'procstat -v' coredump notes"); | ||||
static int sysctl_kern_ps_strings(SYSCTL_HANDLER_ARGS); | static int sysctl_kern_ps_strings(SYSCTL_HANDLER_ARGS); | ||||
static int sysctl_kern_usrstack(SYSCTL_HANDLER_ARGS); | static int sysctl_kern_usrstack(SYSCTL_HANDLER_ARGS); | ||||
static int sysctl_kern_stacktop(SYSCTL_HANDLER_ARGS); | |||||
static int sysctl_kern_stackprot(SYSCTL_HANDLER_ARGS); | static int sysctl_kern_stackprot(SYSCTL_HANDLER_ARGS); | ||||
static int do_execve(struct thread *td, struct image_args *args, | static int do_execve(struct thread *td, struct image_args *args, | ||||
struct mac *mac_p, struct vmspace *oldvmspace); | struct mac *mac_p, struct vmspace *oldvmspace); | ||||
/* XXX This should be vm_size_t. */ | /* XXX This should be vm_size_t. */ | ||||
SYSCTL_PROC(_kern, KERN_PS_STRINGS, ps_strings, CTLTYPE_ULONG|CTLFLAG_RD| | SYSCTL_PROC(_kern, KERN_PS_STRINGS, ps_strings, CTLTYPE_ULONG|CTLFLAG_RD| | ||||
CTLFLAG_CAPRD|CTLFLAG_MPSAFE, NULL, 0, sysctl_kern_ps_strings, "LU", | CTLFLAG_CAPRD|CTLFLAG_MPSAFE, NULL, 0, sysctl_kern_ps_strings, "LU", | ||||
"Location of process' ps_strings structure"); | "Location of process' ps_strings structure"); | ||||
/* XXX This should be vm_size_t. */ | /* XXX This should be vm_size_t. */ | ||||
SYSCTL_PROC(_kern, KERN_USRSTACK, usrstack, CTLTYPE_ULONG|CTLFLAG_RD| | SYSCTL_PROC(_kern, KERN_USRSTACK, usrstack, CTLTYPE_ULONG|CTLFLAG_RD| | ||||
CTLFLAG_CAPRD|CTLFLAG_MPSAFE, NULL, 0, sysctl_kern_usrstack, "LU", | CTLFLAG_CAPRD|CTLFLAG_MPSAFE, NULL, 0, sysctl_kern_usrstack, "LU", | ||||
"Top of process stack"); | "Top of process stack"); | ||||
SYSCTL_PROC(_kern, KERN_STACKTOP, stacktop, CTLTYPE_ULONG | CTLFLAG_RD | | |||||
CTLFLAG_CAPRD | CTLFLAG_MPSAFE, NULL, 0, sysctl_kern_stacktop, "LU", | |||||
"Top of process stack with stack gap."); | |||||
SYSCTL_PROC(_kern, OID_AUTO, stackprot, CTLTYPE_INT|CTLFLAG_RD|CTLFLAG_MPSAFE, | SYSCTL_PROC(_kern, OID_AUTO, stackprot, CTLTYPE_INT|CTLFLAG_RD|CTLFLAG_MPSAFE, | ||||
NULL, 0, sysctl_kern_stackprot, "I", | NULL, 0, sysctl_kern_stackprot, "I", | ||||
"Stack memory permissions"); | "Stack memory permissions"); | ||||
u_long ps_arg_cache_limit = PAGE_SIZE / 16; | u_long ps_arg_cache_limit = PAGE_SIZE / 16; | ||||
SYSCTL_ULONG(_kern, OID_AUTO, ps_arg_cache_limit, CTLFLAG_RW, | SYSCTL_ULONG(_kern, OID_AUTO, ps_arg_cache_limit, CTLFLAG_RW, | ||||
&ps_arg_cache_limit, 0, | &ps_arg_cache_limit, 0, | ||||
"Process' command line characters cache limit"); | "Process' command line characters cache limit"); | ||||
Show All 11 Lines | |||||
SYSCTL_INT(_kern, OID_AUTO, core_dump_can_intr, CTLFLAG_RWTUN, | SYSCTL_INT(_kern, OID_AUTO, core_dump_can_intr, CTLFLAG_RWTUN, | ||||
&core_dump_can_intr, 0, | &core_dump_can_intr, 0, | ||||
"Core dumping interruptible with SIGKILL"); | "Core dumping interruptible with SIGKILL"); | ||||
static int | static int | ||||
sysctl_kern_ps_strings(SYSCTL_HANDLER_ARGS) | sysctl_kern_ps_strings(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
struct proc *p; | struct proc *p; | ||||
int error; | vm_offset_t ps_strings; | ||||
p = curproc; | p = curproc; | ||||
#ifdef SCTL_MASK32 | #ifdef SCTL_MASK32 | ||||
if (req->flags & SCTL_MASK32) { | if (req->flags & SCTL_MASK32) { | ||||
unsigned int val; | unsigned int val; | ||||
val = (unsigned int)p->p_sysent->sv_psstrings; | val = (unsigned int)PROC_PS_STRINGS(p); | ||||
error = SYSCTL_OUT(req, &val, sizeof(val)); | return (SYSCTL_OUT(req, &val, sizeof(val))); | ||||
} else | } | ||||
#endif | #endif | ||||
error = SYSCTL_OUT(req, &p->p_sysent->sv_psstrings, | ps_strings = PROC_PS_STRINGS(p); | ||||
sizeof(p->p_sysent->sv_psstrings)); | return (SYSCTL_OUT(req, &ps_strings, sizeof(ps_strings))); | ||||
return error; | |||||
} | } | ||||
static int | static int | ||||
sysctl_kern_usrstack(SYSCTL_HANDLER_ARGS) | sysctl_kern_usrstack(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
struct proc *p; | struct proc *p; | ||||
int error; | vm_offset_t val; | ||||
p = curproc; | p = curproc; | ||||
#ifdef SCTL_MASK32 | #ifdef SCTL_MASK32 | ||||
if (req->flags & SCTL_MASK32) { | if (req->flags & SCTL_MASK32) { | ||||
unsigned int val; | unsigned int val32; | ||||
val = (unsigned int)p->p_sysent->sv_usrstack; | |||||
error = SYSCTL_OUT(req, &val, sizeof(val)); | |||||
} else | |||||
#endif | |||||
error = SYSCTL_OUT(req, &p->p_sysent->sv_usrstack, | |||||
sizeof(p->p_sysent->sv_usrstack)); | |||||
return (error); | |||||
} | |||||
static int | val32 = round_page((unsigned int)p->p_vmspace->vm_stacktop); | ||||
sysctl_kern_stacktop(SYSCTL_HANDLER_ARGS) | return (SYSCTL_OUT(req, &val32, sizeof(val32))); | ||||
{ | } | ||||
vm_offset_t stacktop; | |||||
struct proc *p; | |||||
int error; | |||||
p = curproc; | |||||
#ifdef SCTL_MASK32 | |||||
if (req->flags & SCTL_MASK32) { | |||||
unsigned int val; | |||||
val = (unsigned int)(p->p_sysent->sv_usrstack - | |||||
p->p_vmspace->vm_stkgap); | |||||
error = SYSCTL_OUT(req, &val, sizeof(val)); | |||||
} else | |||||
#endif | #endif | ||||
{ | val = round_page(p->p_vmspace->vm_stacktop); | ||||
stacktop = p->p_sysent->sv_usrstack - p->p_vmspace->vm_stkgap; | return (SYSCTL_OUT(req, &val, sizeof(val))); | ||||
error = SYSCTL_OUT(req, &stacktop, sizeof(stacktop)); | |||||
} | } | ||||
return (error); | |||||
} | |||||
static int | static int | ||||
sysctl_kern_stackprot(SYSCTL_HANDLER_ARGS) | sysctl_kern_stackprot(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
struct proc *p; | struct proc *p; | ||||
p = curproc; | p = curproc; | ||||
return (SYSCTL_OUT(req, &p->p_sysent->sv_stackprot, | return (SYSCTL_OUT(req, &p->p_sysent->sv_stackprot, | ||||
▲ Show 20 Lines • Show All 898 Lines • ▼ Show 20 Lines | exec_free_abi_mappings(struct proc *p) | ||||
if (sv->sv_shared_page_obj == NULL) | if (sv->sv_shared_page_obj == NULL) | ||||
return; | return; | ||||
pmap_remove(vmspace_pmap(vmspace), sv->sv_shared_page_base, | pmap_remove(vmspace_pmap(vmspace), sv->sv_shared_page_base, | ||||
sv->sv_shared_page_base + sv->sv_shared_page_len); | sv->sv_shared_page_base + sv->sv_shared_page_len); | ||||
} | } | ||||
/* | /* | ||||
* Destroy old address space, and allocate a new stack. | * Run down the current address space and install a new one. Map the shared | ||||
* The new stack is only sgrowsiz large because it is grown | * page and compute the new image's stack size. | ||||
* automatically on a page fault. | |||||
*/ | */ | ||||
int | int | ||||
exec_new_vmspace(struct image_params *imgp, struct sysentvec *sv) | exec_new_vmspace(struct image_params *imgp, struct sysentvec *sv) | ||||
{ | { | ||||
int error; | int error; | ||||
struct proc *p = imgp->proc; | struct proc *p = imgp->proc; | ||||
struct vmspace *vmspace = p->p_vmspace; | struct vmspace *vmspace = p->p_vmspace; | ||||
struct thread *td = curthread; | struct thread *td = curthread; | ||||
vm_object_t obj; | vm_object_t obj; | ||||
struct rlimit rlim_stack; | vm_offset_t sv_minuser; | ||||
vm_offset_t sv_minuser, stack_addr; | |||||
vm_map_t map; | vm_map_t map; | ||||
vm_prot_t stack_prot; | |||||
u_long ssiz; | |||||
imgp->vmspace_destroyed = true; | imgp->vmspace_destroyed = true; | ||||
imgp->sysent = sv; | imgp->sysent = sv; | ||||
if (p->p_sysent->sv_onexec_old != NULL) | if (p->p_sysent->sv_onexec_old != NULL) | ||||
p->p_sysent->sv_onexec_old(td); | p->p_sysent->sv_onexec_old(td); | ||||
itimers_exec(p); | itimers_exec(p); | ||||
Show All 18 Lines | if (refcount_load(&vmspace->vm_refcnt) == 1 && | ||||
pmap_remove_pages(vmspace_pmap(vmspace)); | pmap_remove_pages(vmspace_pmap(vmspace)); | ||||
vm_map_remove(map, vm_map_min(map), vm_map_max(map)); | vm_map_remove(map, vm_map_min(map), vm_map_max(map)); | ||||
/* | /* | ||||
* An exec terminates mlockall(MCL_FUTURE). | * An exec terminates mlockall(MCL_FUTURE). | ||||
* ASLR and W^X states must be re-evaluated. | * ASLR and W^X states must be re-evaluated. | ||||
*/ | */ | ||||
vm_map_lock(map); | vm_map_lock(map); | ||||
vm_map_modflags(map, 0, MAP_WIREFUTURE | MAP_ASLR | | vm_map_modflags(map, 0, MAP_WIREFUTURE | MAP_ASLR | | ||||
MAP_ASLR_IGNSTART | MAP_WXORX); | MAP_ASLR_IGNSTART | MAP_ASLR_STACK | MAP_WXORX); | ||||
vm_map_unlock(map); | vm_map_unlock(map); | ||||
} else { | } else { | ||||
error = vmspace_exec(p, sv_minuser, sv->sv_maxuser); | error = vmspace_exec(p, sv_minuser, sv->sv_maxuser); | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
vmspace = p->p_vmspace; | vmspace = p->p_vmspace; | ||||
map = &vmspace->vm_map; | map = &vmspace->vm_map; | ||||
} | } | ||||
Show All 9 Lines | error = vm_map_fixed(map, obj, 0, | ||||
VM_PROT_READ | VM_PROT_EXECUTE, | VM_PROT_READ | VM_PROT_EXECUTE, | ||||
MAP_INHERIT_SHARE | MAP_ACC_NO_CHARGE); | MAP_INHERIT_SHARE | MAP_ACC_NO_CHARGE); | ||||
if (error != KERN_SUCCESS) { | if (error != KERN_SUCCESS) { | ||||
vm_object_deallocate(obj); | vm_object_deallocate(obj); | ||||
return (vm_mmap_to_errno(error)); | return (vm_mmap_to_errno(error)); | ||||
} | } | ||||
} | } | ||||
/* Allocate a new stack */ | return (sv->sv_onexec != NULL ? sv->sv_onexec(p, imgp) : 0); | ||||
} | |||||
/* | |||||
* Compute the stack size limit and map the main process stack. | |||||
*/ | |||||
int | |||||
exec_map_stack(struct image_params *imgp) | |||||
{ | |||||
struct rlimit rlim_stack; | |||||
struct sysentvec *sv; | |||||
struct proc *p; | |||||
vm_map_t map; | |||||
struct vmspace *vmspace; | |||||
vm_offset_t stack_addr, stack_top; | |||||
kib: stack_off can be int | |||||
u_long ssiz; | |||||
int error, find_space, stack_off; | |||||
vm_prot_t stack_prot; | |||||
p = imgp->proc; | |||||
sv = p->p_sysent; | |||||
if (imgp->stack_sz != 0) { | if (imgp->stack_sz != 0) { | ||||
ssiz = trunc_page(imgp->stack_sz); | ssiz = trunc_page(imgp->stack_sz); | ||||
PROC_LOCK(p); | PROC_LOCK(p); | ||||
lim_rlimit_proc(p, RLIMIT_STACK, &rlim_stack); | lim_rlimit_proc(p, RLIMIT_STACK, &rlim_stack); | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
if (ssiz > rlim_stack.rlim_max) | if (ssiz > rlim_stack.rlim_max) | ||||
ssiz = rlim_stack.rlim_max; | ssiz = rlim_stack.rlim_max; | ||||
if (ssiz > rlim_stack.rlim_cur) { | if (ssiz > rlim_stack.rlim_cur) { | ||||
rlim_stack.rlim_cur = ssiz; | rlim_stack.rlim_cur = ssiz; | ||||
kern_setrlimit(curthread, RLIMIT_STACK, &rlim_stack); | kern_setrlimit(curthread, RLIMIT_STACK, &rlim_stack); | ||||
} | } | ||||
} else if (sv->sv_maxssiz != NULL) { | } else if (sv->sv_maxssiz != NULL) { | ||||
ssiz = *sv->sv_maxssiz; | ssiz = *sv->sv_maxssiz; | ||||
} else { | } else { | ||||
ssiz = maxssiz; | ssiz = maxssiz; | ||||
} | } | ||||
imgp->eff_stack_sz = lim_cur(curthread, RLIMIT_STACK); | |||||
if (ssiz < imgp->eff_stack_sz) | vmspace = p->p_vmspace; | ||||
imgp->eff_stack_sz = ssiz; | map = &vmspace->vm_map; | ||||
stack_addr = sv->sv_usrstack - ssiz; | |||||
stack_prot = obj != NULL && imgp->stack_prot != 0 ? | stack_prot = sv->sv_shared_page_obj != NULL && imgp->stack_prot != 0 ? | ||||
imgp->stack_prot : sv->sv_stackprot; | imgp->stack_prot : sv->sv_stackprot; | ||||
error = vm_map_stack(map, stack_addr, (vm_size_t)ssiz, stack_prot, | if ((map->flags & MAP_ASLR_STACK) != 0) { | ||||
VM_PROT_ALL, MAP_STACK_GROWS_DOWN); | stack_addr = round_page((vm_offset_t)p->p_vmspace->vm_daddr + | ||||
lim_max(curthread, RLIMIT_DATA)); | |||||
find_space = VMFS_ANY_SPACE; | |||||
} else { | |||||
stack_addr = sv->sv_usrstack - ssiz; | |||||
find_space = VMFS_NO_SPACE; | |||||
} | |||||
error = vm_map_find(map, NULL, 0, &stack_addr, (vm_size_t)ssiz, | |||||
sv->sv_usrstack, find_space, stack_prot, VM_PROT_ALL, | |||||
MAP_STACK_GROWS_DOWN); | |||||
if (error != KERN_SUCCESS) { | if (error != KERN_SUCCESS) { | ||||
uprintf("exec_new_vmspace: mapping stack size %#jx prot %#x " | uprintf("exec_new_vmspace: mapping stack size %#jx prot %#x " | ||||
"failed mach error %d errno %d\n", (uintmax_t)ssiz, | "failed, mach error %d errno %d\n", (uintmax_t)ssiz, | ||||
stack_prot, error, vm_mmap_to_errno(error)); | stack_prot, error, vm_mmap_to_errno(error)); | ||||
return (vm_mmap_to_errno(error)); | return (vm_mmap_to_errno(error)); | ||||
} | } | ||||
vmspace->vm_stkgap = 0; | |||||
stack_top = stack_addr + ssiz; | |||||
if ((map->flags & MAP_ASLR_STACK) != 0) { | |||||
Done Inline ActionsIt is somewhat cryptic to use VMFS_ANY_SPACE. Why not check for MAP_ASLR_STACK? kib: It is somewhat cryptic to use VMFS_ANY_SPACE. Why not check for MAP_ASLR_STACK? | |||||
/* Randomize within the first page of the stack. */ | |||||
arc4rand(&stack_off, sizeof(stack_off), 0); | |||||
stack_top -= rounddown2(stack_off & PAGE_MASK, sizeof(void *)); | |||||
} | |||||
/* | /* | ||||
* vm_ssize and vm_maxsaddr are somewhat antiquated concepts, but they | * vm_ssize and vm_maxsaddr are somewhat antiquated concepts, but they | ||||
* are still used to enforce the stack rlimit on the process stack. | * are still used to enforce the stack rlimit on the process stack. | ||||
*/ | */ | ||||
vmspace->vm_ssize = sgrowsiz >> PAGE_SHIFT; | |||||
vmspace->vm_maxsaddr = (char *)stack_addr; | vmspace->vm_maxsaddr = (char *)stack_addr; | ||||
vmspace->vm_stacktop = stack_top; | |||||
vmspace->vm_ssize = sgrowsiz >> PAGE_SHIFT; | |||||
return (sv->sv_onexec != NULL ? sv->sv_onexec(p, imgp) : 0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* Copy out argument and environment strings from the old process address | * Copy out argument and environment strings from the old process address | ||||
* space into the temporary string buffer. | * space into the temporary string buffer. | ||||
*/ | */ | ||||
int | int | ||||
exec_copyin_args(struct image_args *args, const char *fname, | exec_copyin_args(struct image_args *args, const char *fname, | ||||
▲ Show 20 Lines • Show All 317 Lines • ▼ Show 20 Lines | exec_args_get_begin_envv(struct image_args *args) | ||||
KASSERT(args->endp != NULL, ("endp not initialized")); | KASSERT(args->endp != NULL, ("endp not initialized")); | ||||
if (args->envc > 0) | if (args->envc > 0) | ||||
return (args->begin_envv); | return (args->begin_envv); | ||||
return (args->endp); | return (args->endp); | ||||
} | } | ||||
void | |||||
exec_stackgap(struct image_params *imgp, uintptr_t *dp) | |||||
{ | |||||
struct proc *p = imgp->proc; | |||||
if (imgp->sysent->sv_stackgap == NULL || | |||||
(p->p_fctl0 & (NT_FREEBSD_FCTL_ASLR_DISABLE | | |||||
NT_FREEBSD_FCTL_ASG_DISABLE)) != 0 || | |||||
(imgp->map_flags & MAP_ASLR) == 0) { | |||||
p->p_vmspace->vm_stkgap = 0; | |||||
return; | |||||
} | |||||
p->p_vmspace->vm_stkgap = imgp->sysent->sv_stackgap(imgp, dp); | |||||
} | |||||
/* | /* | ||||
* Copy strings out to the new process address space, constructing new arg | * Copy strings out to the new process address space, constructing new arg | ||||
* and env vector tables. Return a pointer to the base so that it can be used | * and env vector tables. Return a pointer to the base so that it can be used | ||||
* as the initial stack pointer. | * as the initial stack pointer. | ||||
*/ | */ | ||||
int | int | ||||
exec_copyout_strings(struct image_params *imgp, uintptr_t *stack_base) | exec_copyout_strings(struct image_params *imgp, uintptr_t *stack_base) | ||||
{ | { | ||||
int argc, envc; | int argc, envc; | ||||
char **vectp; | char **vectp; | ||||
char *stringp; | char *stringp; | ||||
uintptr_t destp, ustringp; | uintptr_t destp, ustringp; | ||||
struct ps_strings *arginfo; | struct ps_strings *arginfo; | ||||
struct proc *p; | struct proc *p; | ||||
struct sysentvec *sysent; | struct sysentvec *sysent; | ||||
size_t execpath_len; | size_t execpath_len; | ||||
int error, szsigcode; | int error, szsigcode; | ||||
char canary[sizeof(long) * 8]; | char canary[sizeof(long) * 8]; | ||||
p = imgp->proc; | p = imgp->proc; | ||||
sysent = p->p_sysent; | sysent = p->p_sysent; | ||||
arginfo = (struct ps_strings *)sysent->sv_psstrings; | destp = PROC_PS_STRINGS(p); | ||||
destp = (uintptr_t)arginfo; | arginfo = imgp->ps_strings = (void *)destp; | ||||
imgp->ps_strings = arginfo; | |||||
/* | /* | ||||
* Install sigcode. | * Install sigcode. | ||||
*/ | */ | ||||
if (sysent->sv_sigcode_base == 0 && sysent->sv_szsigcode != NULL) { | if (sysent->sv_sigcode_base == 0 && sysent->sv_szsigcode != NULL) { | ||||
szsigcode = *(sysent->sv_szsigcode); | szsigcode = *(sysent->sv_szsigcode); | ||||
destp -= szsigcode; | destp -= szsigcode; | ||||
destp = rounddown2(destp, sizeof(void *)); | destp = rounddown2(destp, sizeof(void *)); | ||||
Show All 38 Lines | if (error != 0) | ||||
return (error); | return (error); | ||||
/* | /* | ||||
* Allocate room for the argument and environment strings. | * Allocate room for the argument and environment strings. | ||||
*/ | */ | ||||
destp -= ARG_MAX - imgp->args->stringspace; | destp -= ARG_MAX - imgp->args->stringspace; | ||||
destp = rounddown2(destp, sizeof(void *)); | destp = rounddown2(destp, sizeof(void *)); | ||||
ustringp = destp; | ustringp = destp; | ||||
exec_stackgap(imgp, &destp); | |||||
if (imgp->auxargs) { | if (imgp->auxargs) { | ||||
/* | /* | ||||
* Allocate room on the stack for the ELF auxargs | * Allocate room on the stack for the ELF auxargs | ||||
* array. It has up to AT_COUNT entries. | * array. It has up to AT_COUNT entries. | ||||
*/ | */ | ||||
destp -= AT_COUNT * sizeof(Elf_Auxinfo); | destp -= AT_COUNT * sizeof(Elf_Auxinfo); | ||||
destp = rounddown2(destp, sizeof(void *)); | destp = rounddown2(destp, sizeof(void *)); | ||||
▲ Show 20 Lines • Show All 362 Lines • Show Last 20 Lines |
stack_off can be int