diff options
author | davidxu <davidxu@FreeBSD.org> | 2005-07-10 23:31:11 +0000 |
---|---|---|
committer | davidxu <davidxu@FreeBSD.org> | 2005-07-10 23:31:11 +0000 |
commit | bc8b519d0f5bbf92cb40d8b35ea92bb2285463c5 (patch) | |
tree | e1deb69e9ef98abe6e3de57b17a8192575186ef3 | |
parent | 6d86e52425b9f58cf008209ca788b1475811f5f3 (diff) | |
download | FreeBSD-src-bc8b519d0f5bbf92cb40d8b35ea92bb2285463c5.zip FreeBSD-src-bc8b519d0f5bbf92cb40d8b35ea92bb2285463c5.tar.gz |
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)
-rw-r--r-- | sys/alpha/alpha/vm_machdep.c | 3 | ||||
-rw-r--r-- | sys/amd64/amd64/sys_machdep.c | 51 | ||||
-rw-r--r-- | sys/amd64/amd64/vm_machdep.c | 6 | ||||
-rw-r--r-- | sys/arm/arm/vm_machdep.c | 3 | ||||
-rw-r--r-- | sys/i386/i386/vm_machdep.c | 3 | ||||
-rw-r--r-- | sys/ia64/ia64/vm_machdep.c | 3 | ||||
-rw-r--r-- | sys/kern/kern_thr.c | 7 | ||||
-rw-r--r-- | sys/powerpc/aim/vm_machdep.c | 3 | ||||
-rw-r--r-- | sys/powerpc/powerpc/vm_machdep.c | 3 | ||||
-rw-r--r-- | sys/sparc64/sparc64/vm_machdep.c | 3 | ||||
-rw-r--r-- | sys/sys/proc.h | 2 |
11 files changed, 65 insertions, 22 deletions
diff --git a/sys/alpha/alpha/vm_machdep.c b/sys/alpha/alpha/vm_machdep.c index f8e9028..cfbdf2c 100644 --- a/sys/alpha/alpha/vm_machdep.c +++ b/sys/alpha/alpha/vm_machdep.c @@ -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); } /* diff --git a/sys/amd64/amd64/sys_machdep.c b/sys/amd64/amd64/sys_machdep.c index 25fbb6f..7f022d0 100644 --- a/sys/amd64/amd64/sys_machdep.c +++ b/sys/amd64/amd64/sys_machdep.c @@ -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: diff --git a/sys/amd64/amd64/vm_machdep.c b/sys/amd64/amd64/vm_machdep.c index 5acc1c0..424adaf 100644 --- a/sys/amd64/amd64/vm_machdep.c +++ b/sys/amd64/amd64/vm_machdep.c @@ -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 diff --git a/sys/arm/arm/vm_machdep.c b/sys/arm/arm/vm_machdep.c index 6c0760e..154958d 100644 --- a/sys/arm/arm/vm_machdep.c +++ b/sys/arm/arm/vm_machdep.c @@ -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 diff --git a/sys/i386/i386/vm_machdep.c b/sys/i386/i386/vm_machdep.c index 7a9837d..9ad7891 100644 --- a/sys/i386/i386/vm_machdep.c +++ b/sys/i386/i386/vm_machdep.c @@ -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); } /* diff --git a/sys/ia64/ia64/vm_machdep.c b/sys/ia64/ia64/vm_machdep.c index f7d6301..685aece 100644 --- a/sys/ia64/ia64/vm_machdep.c +++ b/sys/ia64/ia64/vm_machdep.c @@ -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); } /* diff --git a/sys/kern/kern_thr.c b/sys/kern/kern_thr.c index 4a552a2..0e8b3e8 100644 --- a/sys/kern/kern_thr.c +++ b/sys/kern/kern_thr.c @@ -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) { diff --git a/sys/powerpc/aim/vm_machdep.c b/sys/powerpc/aim/vm_machdep.c index 60274f3..4b896ea 100644 --- a/sys/powerpc/aim/vm_machdep.c +++ b/sys/powerpc/aim/vm_machdep.c @@ -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); } diff --git a/sys/powerpc/powerpc/vm_machdep.c b/sys/powerpc/powerpc/vm_machdep.c index 60274f3..4b896ea 100644 --- a/sys/powerpc/powerpc/vm_machdep.c +++ b/sys/powerpc/powerpc/vm_machdep.c @@ -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); } diff --git a/sys/sparc64/sparc64/vm_machdep.c b/sys/sparc64/sparc64/vm_machdep.c index 20bf46b..9dd80fd 100644 --- a/sys/sparc64/sparc64/vm_machdep.c +++ b/sys/sparc64/sparc64/vm_machdep.c @@ -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); } /* diff --git a/sys/sys/proc.h b/sys/sys/proc.h index b165c07..a408ecc 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -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); |