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:
David Xu 2005-07-10 23:31:11 +00:00
parent 5305063bdf
commit 740fd64d65
11 changed files with 65 additions and 22 deletions

View File

@ -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);
}
/*

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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);
}
/*

View File

@ -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);
}
/*

View File

@ -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) {

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}
/*

View File

@ -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);