summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordavidxu <davidxu@FreeBSD.org>2005-07-10 23:31:11 +0000
committerdavidxu <davidxu@FreeBSD.org>2005-07-10 23:31:11 +0000
commitbc8b519d0f5bbf92cb40d8b35ea92bb2285463c5 (patch)
treee1deb69e9ef98abe6e3de57b17a8192575186ef3
parent6d86e52425b9f58cf008209ca788b1475811f5f3 (diff)
downloadFreeBSD-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.c3
-rw-r--r--sys/amd64/amd64/sys_machdep.c51
-rw-r--r--sys/amd64/amd64/vm_machdep.c6
-rw-r--r--sys/arm/arm/vm_machdep.c3
-rw-r--r--sys/i386/i386/vm_machdep.c3
-rw-r--r--sys/ia64/ia64/vm_machdep.c3
-rw-r--r--sys/kern/kern_thr.c7
-rw-r--r--sys/powerpc/aim/vm_machdep.c3
-rw-r--r--sys/powerpc/powerpc/vm_machdep.c3
-rw-r--r--sys/sparc64/sparc64/vm_machdep.c3
-rw-r--r--sys/sys/proc.h2
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);
OpenPOWER on IntegriCloud