Changeset View
Changeset View
Standalone View
Standalone View
sys/amd64/amd64/sys_machdep.c
Show All 38 Lines | |||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/systm.h> | #include <sys/systm.h> | ||||
#include <sys/capsicum.h> | #include <sys/capsicum.h> | ||||
#include <sys/kernel.h> | #include <sys/kernel.h> | ||||
#include <sys/lock.h> | #include <sys/lock.h> | ||||
#include <sys/malloc.h> | #include <sys/malloc.h> | ||||
#include <sys/mutex.h> | #include <sys/mutex.h> | ||||
#include <sys/pcpu.h> | |||||
#include <sys/priv.h> | #include <sys/priv.h> | ||||
#include <sys/proc.h> | #include <sys/proc.h> | ||||
#include <sys/smp.h> | #include <sys/smp.h> | ||||
#include <sys/sysproto.h> | #include <sys/sysproto.h> | ||||
#include <sys/uio.h> | #include <sys/uio.h> | ||||
#include <vm/vm.h> | #include <vm/vm.h> | ||||
#include <vm/pmap.h> | #include <vm/pmap.h> | ||||
#include <vm/vm_kern.h> /* for kernel_map */ | #include <vm/vm_kern.h> /* for kernel_map */ | ||||
#include <vm/vm_map.h> | |||||
#include <vm/vm_extern.h> | #include <vm/vm_extern.h> | ||||
#include <machine/frame.h> | #include <machine/frame.h> | ||||
#include <machine/md_var.h> | #include <machine/md_var.h> | ||||
#include <machine/pcb.h> | #include <machine/pcb.h> | ||||
#include <machine/specialreg.h> | #include <machine/specialreg.h> | ||||
#include <machine/sysarch.h> | #include <machine/sysarch.h> | ||||
#include <machine/tss.h> | #include <machine/tss.h> | ||||
▲ Show 20 Lines • Show All 101 Lines • ▼ Show 20 Lines | update_gdt_fsbase(struct thread *td, uint32_t base) | ||||
sd->sd_lobase = base & 0xffffff; | sd->sd_lobase = base & 0xffffff; | ||||
sd->sd_hibase = (base >> 24) & 0xff; | sd->sd_hibase = (base >> 24) & 0xff; | ||||
critical_exit(); | critical_exit(); | ||||
} | } | ||||
int | int | ||||
sysarch(struct thread *td, struct sysarch_args *uap) | sysarch(struct thread *td, struct sysarch_args *uap) | ||||
{ | { | ||||
int error = 0; | struct pcb *pcb; | ||||
struct pcb *pcb = curthread->td_pcb; | struct vm_map *map; | ||||
uint32_t i386base; | uint32_t i386base; | ||||
uint64_t a64base; | uint64_t a64base; | ||||
struct i386_ioperm_args iargs; | struct i386_ioperm_args iargs; | ||||
struct i386_get_xfpustate i386xfpu; | struct i386_get_xfpustate i386xfpu; | ||||
struct i386_set_pkru i386pkru; | |||||
struct amd64_get_xfpustate a64xfpu; | struct amd64_get_xfpustate a64xfpu; | ||||
struct amd64_set_pkru a64pkru; | |||||
int error; | |||||
#ifdef CAPABILITY_MODE | #ifdef CAPABILITY_MODE | ||||
/* | /* | ||||
* When adding new operations, add a new case statement here to | * When adding new operations, add a new case statement here to | ||||
* explicitly indicate whether or not the operation is safe to | * explicitly indicate whether or not the operation is safe to | ||||
* perform in capability mode. | * perform in capability mode. | ||||
*/ | */ | ||||
if (IN_CAPABILITY_MODE(td)) { | if (IN_CAPABILITY_MODE(td)) { | ||||
switch (uap->op) { | switch (uap->op) { | ||||
case I386_GET_LDT: | case I386_GET_LDT: | ||||
case I386_SET_LDT: | case I386_SET_LDT: | ||||
case I386_GET_IOPERM: | case I386_GET_IOPERM: | ||||
case I386_GET_FSBASE: | case I386_GET_FSBASE: | ||||
case I386_SET_FSBASE: | case I386_SET_FSBASE: | ||||
case I386_GET_GSBASE: | case I386_GET_GSBASE: | ||||
case I386_SET_GSBASE: | case I386_SET_GSBASE: | ||||
case I386_GET_XFPUSTATE: | case I386_GET_XFPUSTATE: | ||||
case I386_SET_PKRU: | |||||
case I386_CLEAR_PKRU: | |||||
case AMD64_GET_FSBASE: | case AMD64_GET_FSBASE: | ||||
case AMD64_SET_FSBASE: | case AMD64_SET_FSBASE: | ||||
case AMD64_GET_GSBASE: | case AMD64_GET_GSBASE: | ||||
case AMD64_SET_GSBASE: | case AMD64_SET_GSBASE: | ||||
case AMD64_GET_XFPUSTATE: | case AMD64_GET_XFPUSTATE: | ||||
case AMD64_SET_PKRU: | |||||
case AMD64_CLEAR_PKRU: | |||||
break; | break; | ||||
case I386_SET_IOPERM: | case I386_SET_IOPERM: | ||||
default: | default: | ||||
#ifdef KTRACE | #ifdef KTRACE | ||||
if (KTRPOINT(td, KTR_CAPFAIL)) | if (KTRPOINT(td, KTR_CAPFAIL)) | ||||
ktrcapfail(CAPFAIL_SYSCALL, NULL, NULL); | ktrcapfail(CAPFAIL_SYSCALL, NULL, NULL); | ||||
#endif | #endif | ||||
return (ECAPMODE); | return (ECAPMODE); | ||||
} | } | ||||
} | } | ||||
#endif | #endif | ||||
if (uap->op == I386_GET_LDT || uap->op == I386_SET_LDT) | if (uap->op == I386_GET_LDT || uap->op == I386_SET_LDT) | ||||
return (sysarch_ldt(td, uap, UIO_USERSPACE)); | return (sysarch_ldt(td, uap, UIO_USERSPACE)); | ||||
error = 0; | |||||
pcb = td->td_pcb; | |||||
/* | /* | ||||
* XXXKIB check that the BSM generation code knows to encode | * XXXKIB check that the BSM generation code knows to encode | ||||
* the op argument. | * the op argument. | ||||
*/ | */ | ||||
AUDIT_ARG_CMD(uap->op); | AUDIT_ARG_CMD(uap->op); | ||||
switch (uap->op) { | switch (uap->op) { | ||||
case I386_GET_IOPERM: | case I386_GET_IOPERM: | ||||
case I386_SET_IOPERM: | case I386_SET_IOPERM: | ||||
if ((error = copyin(uap->parms, &iargs, | if ((error = copyin(uap->parms, &iargs, | ||||
sizeof(struct i386_ioperm_args))) != 0) | sizeof(struct i386_ioperm_args))) != 0) | ||||
return (error); | return (error); | ||||
break; | break; | ||||
case I386_GET_XFPUSTATE: | case I386_GET_XFPUSTATE: | ||||
if ((error = copyin(uap->parms, &i386xfpu, | if ((error = copyin(uap->parms, &i386xfpu, | ||||
sizeof(struct i386_get_xfpustate))) != 0) | sizeof(struct i386_get_xfpustate))) != 0) | ||||
return (error); | return (error); | ||||
a64xfpu.addr = (void *)(uintptr_t)i386xfpu.addr; | a64xfpu.addr = (void *)(uintptr_t)i386xfpu.addr; | ||||
a64xfpu.len = i386xfpu.len; | a64xfpu.len = i386xfpu.len; | ||||
break; | break; | ||||
case I386_SET_PKRU: | |||||
case I386_CLEAR_PKRU: | |||||
if ((error = copyin(uap->parms, &i386pkru, | |||||
sizeof(struct i386_set_pkru))) != 0) | |||||
return (error); | |||||
a64pkru.addr = (void *)(uintptr_t)i386pkru.addr; | |||||
a64pkru.len = i386pkru.len; | |||||
a64pkru.keyidx = i386pkru.keyidx; | |||||
a64pkru.flags = i386pkru.flags; | |||||
break; | |||||
case AMD64_GET_XFPUSTATE: | case AMD64_GET_XFPUSTATE: | ||||
if ((error = copyin(uap->parms, &a64xfpu, | if ((error = copyin(uap->parms, &a64xfpu, | ||||
sizeof(struct amd64_get_xfpustate))) != 0) | sizeof(struct amd64_get_xfpustate))) != 0) | ||||
return (error); | return (error); | ||||
break; | break; | ||||
case AMD64_SET_PKRU: | |||||
case AMD64_CLEAR_PKRU: | |||||
if ((error = copyin(uap->parms, &a64pkru, | |||||
sizeof(struct amd64_set_pkru))) != 0) | |||||
return (error); | |||||
break; | |||||
default: | default: | ||||
break; | break; | ||||
} | } | ||||
switch (uap->op) { | switch (uap->op) { | ||||
case I386_GET_IOPERM: | case I386_GET_IOPERM: | ||||
error = amd64_get_ioperm(td, &iargs); | error = amd64_get_ioperm(td, &iargs); | ||||
if (error == 0) | if (error == 0) | ||||
▲ Show 20 Lines • Show All 70 Lines • ▼ Show 20 Lines | #endif | ||||
case I386_GET_XFPUSTATE: | case I386_GET_XFPUSTATE: | ||||
case AMD64_GET_XFPUSTATE: | case AMD64_GET_XFPUSTATE: | ||||
if (a64xfpu.len > cpu_max_ext_state_size - | if (a64xfpu.len > cpu_max_ext_state_size - | ||||
sizeof(struct savefpu)) | sizeof(struct savefpu)) | ||||
return (EINVAL); | return (EINVAL); | ||||
fpugetregs(td); | fpugetregs(td); | ||||
error = copyout((char *)(get_pcb_user_save_td(td) + 1), | error = copyout((char *)(get_pcb_user_save_td(td) + 1), | ||||
a64xfpu.addr, a64xfpu.len); | a64xfpu.addr, a64xfpu.len); | ||||
break; | |||||
case I386_SET_PKRU: | |||||
case AMD64_SET_PKRU: | |||||
map = &td->td_proc->p_vmspace->vm_map; | |||||
vm_map_lock_read(map); | |||||
markj: I wonder if we should use a write lock here. With the ENOMEM handling it's possible that… | |||||
kibAuthorUnsubmitted Done Inline ActionsI should have added a comment there. The consistency of single VA is handled by the pmap lock. With the additional guarantee of the rangeset_remove() to not modify the rangeset if an error is returned, the ENOMEM retry still should be fine. This lock prevents parallel vmspace_fork() from receiving inconsistent protection settings if one thread forks and another modifies pmap protection keys for some range. kib: I should have added a comment there. The consistency of single VA is handled by the pmap lock. | |||||
error = pmap_pkru_set(PCPU_GET(curpmap), | |||||
(vm_offset_t)a64pkru.addr, (vm_offset_t)a64pkru.addr + | |||||
a64pkru.len, a64pkru.keyidx, a64pkru.flags); | |||||
vm_map_unlock_read(map); | |||||
break; | |||||
case I386_CLEAR_PKRU: | |||||
case AMD64_CLEAR_PKRU: | |||||
if (a64pkru.flags != 0 || a64pkru.keyidx != 0) { | |||||
error = EINVAL; | |||||
break; | |||||
} | |||||
map = &td->td_proc->p_vmspace->vm_map; | |||||
vm_map_lock_read(map); | |||||
error = pmap_pkru_clear(PCPU_GET(curpmap), | |||||
(vm_offset_t)a64pkru.addr, | |||||
(vm_offset_t)a64pkru.addr + a64pkru.len); | |||||
vm_map_unlock(map); | |||||
break; | break; | ||||
default: | default: | ||||
error = EINVAL; | error = EINVAL; | ||||
break; | break; | ||||
} | } | ||||
return (error); | return (error); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 423 Lines • Show Last 20 Lines |
I wonder if we should use a write lock here. With the ENOMEM handling it's possible that multiple threads are racing to modify the same VA range. It might be preferable to use a dedicated sx lock instead of the vm map lock, to avoid blocking unrelated operations.