Validate if the value written into {FS,GS}.base is a canonical
address, writting non-canonical address can cause kernel a panic, by restricting base values to 0..VM_MAXUSER_ADDRESS, ensuring only canonical values get written to the registers. Reviewed by: peter, Josepha Koshy < joseph.koshy at gmail dot com > Approved by: re (scottl)
This commit is contained in:
parent
5305063bdf
commit
740fd64d65
@ -360,7 +360,7 @@ cpu_set_upcall_kse(struct thread *td, void (*entry)(void *), void *arg,
|
||||
tf->tf_regs[FRAME_FLAGS] = 0; /* full restore */
|
||||
}
|
||||
|
||||
void
|
||||
int
|
||||
cpu_set_user_tls(struct thread *td, void *tls_base)
|
||||
{
|
||||
|
||||
@ -368,6 +368,7 @@ cpu_set_user_tls(struct thread *td, void *tls_base)
|
||||
td->td_pcb->pcb_hw.apcb_unique = (unsigned long)tls_base;
|
||||
else
|
||||
alpha_pal_wrunique((uintptr_t)tls_base);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -42,6 +42,10 @@ __FBSDID("$FreeBSD$");
|
||||
#include <machine/sysarch.h>
|
||||
#include <machine/pcb.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/pmap.h>
|
||||
#include <machine/vmparam.h>
|
||||
|
||||
#ifndef _SYS_SYSPROTO_H_
|
||||
struct sysarch_args {
|
||||
int op;
|
||||
@ -57,6 +61,7 @@ sysarch(td, uap)
|
||||
int error = 0;
|
||||
struct pcb *pcb = curthread->td_pcb;
|
||||
uint32_t i386base;
|
||||
uint64_t a64base;
|
||||
|
||||
switch(uap->op) {
|
||||
case I386_GET_FSBASE:
|
||||
@ -65,9 +70,12 @@ sysarch(td, uap)
|
||||
break;
|
||||
case I386_SET_FSBASE:
|
||||
error = copyin(uap->parms, &i386base, sizeof(i386base));
|
||||
pcb->pcb_fsbase = i386base;
|
||||
if (!error)
|
||||
wrmsr(MSR_FSBASE, pcb->pcb_fsbase);
|
||||
if (!error) {
|
||||
critical_enter();
|
||||
wrmsr(MSR_FSBASE, i386base);
|
||||
pcb->pcb_fsbase = i386base;
|
||||
critical_exit();
|
||||
}
|
||||
break;
|
||||
case I386_GET_GSBASE:
|
||||
i386base = pcb->pcb_gsbase;
|
||||
@ -75,18 +83,29 @@ sysarch(td, uap)
|
||||
break;
|
||||
case I386_SET_GSBASE:
|
||||
error = copyin(uap->parms, &i386base, sizeof(i386base));
|
||||
pcb->pcb_gsbase = i386base;
|
||||
if (!error)
|
||||
wrmsr(MSR_KGSBASE, pcb->pcb_gsbase);
|
||||
if (!error) {
|
||||
critical_enter();
|
||||
wrmsr(MSR_KGSBASE, i386base);
|
||||
pcb->pcb_gsbase = i386base;
|
||||
critical_exit();
|
||||
}
|
||||
break;
|
||||
case AMD64_GET_FSBASE:
|
||||
error = copyout(&pcb->pcb_fsbase, uap->parms, sizeof(pcb->pcb_fsbase));
|
||||
break;
|
||||
|
||||
case AMD64_SET_FSBASE:
|
||||
error = copyin(uap->parms, &pcb->pcb_fsbase, sizeof(pcb->pcb_fsbase));
|
||||
if (!error)
|
||||
wrmsr(MSR_FSBASE, pcb->pcb_fsbase);
|
||||
error = copyin(uap->parms, &a64base, sizeof(a64base));
|
||||
if (!error) {
|
||||
if (a64base < VM_MAXUSER_ADDRESS) {
|
||||
critical_enter();
|
||||
wrmsr(MSR_FSBASE, a64base);
|
||||
pcb->pcb_fsbase = a64base;
|
||||
critical_exit();
|
||||
} else {
|
||||
error = EINVAL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case AMD64_GET_GSBASE:
|
||||
@ -94,9 +113,17 @@ sysarch(td, uap)
|
||||
break;
|
||||
|
||||
case AMD64_SET_GSBASE:
|
||||
error = copyin(uap->parms, &pcb->pcb_gsbase, sizeof(pcb->pcb_gsbase));
|
||||
if (!error)
|
||||
wrmsr(MSR_KGSBASE, pcb->pcb_gsbase);
|
||||
error = copyin(uap->parms, &a64base, sizeof(a64base));
|
||||
if (!error) {
|
||||
if (a64base < VM_MAXUSER_ADDRESS) {
|
||||
critical_enter();
|
||||
wrmsr(MSR_KGSBASE, a64base);
|
||||
pcb->pcb_gsbase = a64base;
|
||||
critical_exit();
|
||||
} else {
|
||||
error = EINVAL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -341,10 +341,13 @@ cpu_set_upcall_kse(struct thread *td, void (*entry)(void *), void *arg,
|
||||
td->td_frame->tf_rdi = (register_t)arg;
|
||||
}
|
||||
|
||||
void
|
||||
int
|
||||
cpu_set_user_tls(struct thread *td, void *tls_base)
|
||||
{
|
||||
|
||||
if ((u_int64_t)tls_base >= VM_MAXUSER_ADDRESS)
|
||||
return (EINVAL);
|
||||
|
||||
if (td == curthread) {
|
||||
critical_enter();
|
||||
td->td_pcb->pcb_fsbase = (register_t)tls_base;
|
||||
@ -353,6 +356,7 @@ cpu_set_user_tls(struct thread *td, void *tls_base)
|
||||
} else {
|
||||
td->td_pcb->pcb_fsbase = (register_t)tls_base;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
#ifdef SMP
|
||||
|
@ -297,7 +297,7 @@ cpu_set_upcall_kse(struct thread *td, void (*entry)(void *), void *arg,
|
||||
tf->tf_spsr = PSR_USR32_MODE;
|
||||
}
|
||||
|
||||
void
|
||||
int
|
||||
cpu_set_user_tls(struct thread *td, void *tls_base)
|
||||
{
|
||||
|
||||
@ -308,6 +308,7 @@ cpu_set_user_tls(struct thread *td, void *tls_base)
|
||||
*(void **)ARM_TP_ADDRESS = tls_base;
|
||||
critical_exit();
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -472,7 +472,7 @@ cpu_set_upcall_kse(struct thread *td, void (*entry)(void *), void *arg,
|
||||
(int)arg);
|
||||
}
|
||||
|
||||
void
|
||||
int
|
||||
cpu_set_user_tls(struct thread *td, void *tls_base)
|
||||
{
|
||||
struct segment_descriptor sd;
|
||||
@ -503,6 +503,7 @@ cpu_set_user_tls(struct thread *td, void *tls_base)
|
||||
load_gs(GSEL(GUGS_SEL, SEL_UPL));
|
||||
}
|
||||
critical_exit();
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -209,10 +209,11 @@ cpu_set_upcall_kse(struct thread *td, void (*entry)(void *), void *arg,
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
int
|
||||
cpu_set_user_tls(struct thread *td, void *tls_base)
|
||||
{
|
||||
td->td_frame->tf_special.tp = (unsigned long)tls_base;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -176,7 +176,12 @@ create_thread(struct thread *td, mcontext_t *ctx,
|
||||
/* Set upcall address to user thread entry function. */
|
||||
cpu_set_upcall_kse(newtd, start_func, arg, &stack);
|
||||
/* Setup user TLS address and TLS pointer register. */
|
||||
cpu_set_user_tls(newtd, tls_base);
|
||||
error = cpu_set_user_tls(newtd, tls_base);
|
||||
if (error != 0) {
|
||||
thread_free(newtd);
|
||||
crfree(td->td_ucred);
|
||||
return (error);
|
||||
}
|
||||
}
|
||||
|
||||
if ((td->td_proc->p_flag & P_HADTHREADS) == 0) {
|
||||
|
@ -355,9 +355,10 @@ cpu_set_upcall_kse(struct thread *td, void (*entry)(void *), void *arg,
|
||||
td->td_retval[1] = 0;
|
||||
}
|
||||
|
||||
void
|
||||
int
|
||||
cpu_set_user_tls(struct thread *td, void *tls_base)
|
||||
{
|
||||
|
||||
td->td_frame->fixreg[2] = (register_t)tls_base;
|
||||
return (0);
|
||||
}
|
||||
|
@ -355,9 +355,10 @@ cpu_set_upcall_kse(struct thread *td, void (*entry)(void *), void *arg,
|
||||
td->td_retval[1] = 0;
|
||||
}
|
||||
|
||||
void
|
||||
int
|
||||
cpu_set_user_tls(struct thread *td, void *tls_base)
|
||||
{
|
||||
|
||||
td->td_frame->fixreg[2] = (register_t)tls_base;
|
||||
return (0);
|
||||
}
|
||||
|
@ -196,13 +196,14 @@ cpu_set_upcall_kse(struct thread *td, void (*entry)(void *), void *arg,
|
||||
td->td_retval[1] = tf->tf_out[1];
|
||||
}
|
||||
|
||||
void
|
||||
int
|
||||
cpu_set_user_tls(struct thread *td, void *tls_base)
|
||||
{
|
||||
|
||||
if (td == curthread)
|
||||
flushw();
|
||||
td->td_frame->tf_global[7] = (uint64_t) tls_base;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -897,7 +897,7 @@ void kse_GC(void);
|
||||
void kseinit(void);
|
||||
void cpu_set_upcall(struct thread *td, struct thread *td0);
|
||||
void cpu_set_upcall_kse(struct thread *, void (*)(void *), void *, stack_t *);
|
||||
void cpu_set_user_tls(struct thread *, void *tls_base);
|
||||
int cpu_set_user_tls(struct thread *, void *tls_base);
|
||||
void cpu_thread_clean(struct thread *);
|
||||
void cpu_thread_exit(struct thread *);
|
||||
void cpu_thread_setup(struct thread *td);
|
||||
|
Loading…
Reference in New Issue
Block a user