From: guenther Date: Mon, 18 May 2015 19:59:27 +0000 (+0000) Subject: Do lazy update/reset of the FS.base and %[def]s segment registers: reseting X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=b13138f26d8f4e65100b2377aab2ba4570a8d014;p=openbsd Do lazy update/reset of the FS.base and %[def]s segment registers: reseting segment registers in cpu_switchto if the old thread had made it to userspace and restoring FS.base only on first return to userspace since context switch. ok mlarkin@ --- diff --git a/sys/arch/amd64/amd64/db_interface.c b/sys/arch/amd64/amd64/db_interface.c index a822f22515c..2f182fa4aa0 100644 --- a/sys/arch/amd64/amd64/db_interface.c +++ b/sys/arch/amd64/amd64/db_interface.c @@ -1,4 +1,4 @@ -/* $OpenBSD: db_interface.c,v 1.22 2015/03/14 03:38:46 jsg Exp $ */ +/* $OpenBSD: db_interface.c,v 1.23 2015/05/18 19:59:27 guenther Exp $ */ /* $NetBSD: db_interface.c,v 1.1 2003/04/26 18:39:27 fvdl Exp $ */ /* @@ -142,10 +142,6 @@ kdb_trap(int type, int code, db_regs_t *regs) ddb_regs = *regs; ddb_regs.tf_cs &= 0xffff; - ddb_regs.tf_ds &= 0xffff; - ddb_regs.tf_es &= 0xffff; - ddb_regs.tf_fs &= 0xffff; - ddb_regs.tf_gs &= 0xffff; ddb_regs.tf_ss &= 0xffff; s = splhigh(); diff --git a/sys/arch/amd64/amd64/db_trace.c b/sys/arch/amd64/amd64/db_trace.c index 03f1f8cb17a..58f96e4cfb3 100644 --- a/sys/arch/amd64/amd64/db_trace.c +++ b/sys/arch/amd64/amd64/db_trace.c @@ -1,4 +1,4 @@ -/* $OpenBSD: db_trace.c,v 1.11 2015/03/31 04:40:47 guenther Exp $ */ +/* $OpenBSD: db_trace.c,v 1.12 2015/05/18 19:59:27 guenther Exp $ */ /* $NetBSD: db_trace.c,v 1.1 2003/04/26 18:39:27 fvdl Exp $ */ /* @@ -53,10 +53,6 @@ static int db_x86_64_regop(struct db_variable *, db_expr_t *, int); * Machine register set. */ struct db_variable db_regs[] = { - { "ds", dbreg(ds), db_x86_64_regop }, - { "es", dbreg(es), db_x86_64_regop }, - { "fs", dbreg(fs), db_x86_64_regop }, - { "gs", dbreg(gs), db_x86_64_regop }, { "rdi", dbreg(rdi), db_x86_64_regop }, { "rsi", dbreg(rsi), db_x86_64_regop }, { "rbp", dbreg(rbp), db_x86_64_regop }, diff --git a/sys/arch/amd64/amd64/genassym.cf b/sys/arch/amd64/amd64/genassym.cf index e13a477a767..80bc03c006d 100644 --- a/sys/arch/amd64/amd64/genassym.cf +++ b/sys/arch/amd64/amd64/genassym.cf @@ -1,4 +1,4 @@ -# $OpenBSD: genassym.cf,v 1.30 2014/04/01 09:05:03 mpi Exp $ +# $OpenBSD: genassym.cf,v 1.31 2015/05/18 19:59:27 guenther Exp $ # Written by Artur Grabowski art@openbsd.org, Public Domain include @@ -114,6 +114,9 @@ member CPU_INFO_MUTEX_LEVEL ci_mutex_level endif member CPU_INFO_GDT ci_gdt member CPU_INFO_TSS ci_tss +member CPU_INFO_FLAGS ci_flags + +export CPUF_USERSEGS_BIT struct intrsource member is_recurse diff --git a/sys/arch/amd64/amd64/locore.S b/sys/arch/amd64/amd64/locore.S index d3f9cffcfb0..c264f9a2de1 100644 --- a/sys/arch/amd64/amd64/locore.S +++ b/sys/arch/amd64/amd64/locore.S @@ -1,4 +1,4 @@ -/* $OpenBSD: locore.S,v 1.64 2015/04/18 05:14:05 guenther Exp $ */ +/* $OpenBSD: locore.S,v 1.65 2015/05/18 19:59:27 guenther Exp $ */ /* $NetBSD: locore.S,v 1.13 2004/03/25 18:33:17 drochner Exp $ */ /* @@ -867,6 +867,17 @@ ENTRY(cpu_switchto) movq %rbp,PCB_RBP(%r13) switch_exited: + /* did old proc run in userspace? then reset the segment regs */ + btrl $CPUF_USERSEGS_BIT, CPUVAR(FLAGS) + jnc restore_saved + + /* set %ds, %es, and %fs to expected value to prevent info leak */ + movw $(GSEL(GUDATA_SEL, SEL_UPL)),%ax + movw %ax,%ds + movw %ax,%es + movw %ax,%fs + +restore_saved: /* * Restore saved context. * @@ -1017,10 +1028,6 @@ IDTVEC(syscall) movq CPUVAR(SCRATCH),%r15 subq $32,%rsp INTR_SAVE_GPRS - movw %fs,TF_FS(%rsp) - movw %gs,TF_GS(%rsp) - movw %es,TF_ES(%rsp) - movw $(GSEL(GUDATA_SEL, SEL_UPL)),TF_DS(%rsp) movq %r11, TF_RFLAGS(%rsp) /* old rflags from syscall insn */ movq $(GSEL(GUCODE_SEL, SEL_UPL)), TF_CS(%rsp) movq %rcx,TF_RIP(%rsp) diff --git a/sys/arch/amd64/amd64/machdep.c b/sys/arch/amd64/amd64/machdep.c index 5062679137f..a5f17ebc1ab 100644 --- a/sys/arch/amd64/amd64/machdep.c +++ b/sys/arch/amd64/amd64/machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: machdep.c,v 1.210 2015/04/25 21:21:02 guenther Exp $ */ +/* $OpenBSD: machdep.c,v 1.211 2015/05/18 19:59:27 guenther Exp $ */ /* $NetBSD: machdep.c,v 1.3 2003/05/07 22:58:18 fvdl Exp $ */ /*- @@ -576,11 +576,6 @@ sendsig(sig_t catcher, int sig, int mask, u_long code, int type, /* * Build context to run handler in. */ - tf->tf_ds = GSEL(GUDATA_SEL, SEL_UPL); - tf->tf_es = GSEL(GUDATA_SEL, SEL_UPL); - tf->tf_fs = GSEL(GUDATA_SEL, SEL_UPL); - tf->tf_gs = GSEL(GUDATA_SEL, SEL_UPL); - tf->tf_rax = (u_int64_t)catcher; tf->tf_rdi = sig; tf->tf_rsi = sip; @@ -1012,6 +1007,29 @@ dumpsys(void) delay(5000000); /* 5 seconds */ } +/* + * Set FS.base for userspace and reset %ds, %es, and %fs segment registers + */ +void +reset_segs(struct pcb *pcb, u_int64_t fsbase) +{ + /* + * Segment registers (%ds, %es, %fs, %gs) aren't in the trapframe. + * %gs is reset on return to userspace to avoid having to deal with + * swapgs; others are reset on context switch and here. This + * operates like the cpu_switchto() sequence: if we haven't reset + * %[def]s already, do so now. + */ + if (curcpu()->ci_flags & CPUF_USERSEGS) { + curcpu()->ci_flags &= ~CPUF_USERSEGS; + __asm volatile( + "movw %%ax,%%ds\n\t" + "movw %%ax,%%es\n\t" + "movw %%ax,%%fs" : : "a"(GSEL(GUDATA_SEL, SEL_UPL))); + } + pcb->pcb_fsbase = fsbase; +} + /* * Clear registers on exec */ @@ -1025,13 +1043,10 @@ setregs(struct proc *p, struct exec_package *pack, u_long stack, if (p->p_addr->u_pcb.pcb_fpcpu != NULL) fpusave_proc(p, 0); p->p_md.md_flags &= ~MDP_USEDFPU; - p->p_addr->u_pcb.pcb_fsbase = 0; + + reset_segs(&p->p_addr->u_pcb, 0); tf = p->p_md.md_regs; - tf->tf_ds = GSEL(GUDATA_SEL, SEL_UPL); - tf->tf_es = GSEL(GUDATA_SEL, SEL_UPL); - tf->tf_fs = GSEL(GUDATA_SEL, SEL_UPL); - tf->tf_gs = GSEL(GUDATA_SEL, SEL_UPL); tf->tf_rdi = 0; tf->tf_rsi = 0; tf->tf_rbp = 0; @@ -1905,22 +1920,6 @@ check_context(const struct reg *regs, struct trapframe *tf) if (((regs->r_rflags ^ tf->tf_rflags) & PSL_USERSTATIC) != 0) return EINVAL; - sel = regs->r_es & 0xffff; - if (sel != 0 && !VALID_USER_DSEL(sel)) - return EINVAL; - - sel = regs->r_fs & 0xffff; - if (sel != 0 && !VALID_USER_DSEL(sel)) - return EINVAL; - - sel = regs->r_gs & 0xffff; - if (sel != 0 && !VALID_USER_DSEL(sel)) - return EINVAL; - - sel = regs->r_ds & 0xffff; - if (!VALID_USER_DSEL(sel)) - return EINVAL; - sel = regs->r_ss & 0xffff; if (!VALID_USER_DSEL(sel)) return EINVAL; diff --git a/sys/arch/amd64/amd64/process_machdep.c b/sys/arch/amd64/amd64/process_machdep.c index 9b3f0f2198c..823a93e111a 100644 --- a/sys/arch/amd64/amd64/process_machdep.c +++ b/sys/arch/amd64/amd64/process_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: process_machdep.c,v 1.12 2015/03/14 03:38:46 jsg Exp $ */ +/* $OpenBSD: process_machdep.c,v 1.13 2015/05/18 19:59:27 guenther Exp $ */ /* $NetBSD: process_machdep.c,v 1.1 2003/04/26 18:39:31 fvdl Exp $ */ /*- @@ -114,10 +114,10 @@ process_read_regs(struct proc *p, struct reg *regs) regs->r_rflags = tf->tf_rflags; regs->r_cs = tf->tf_cs; regs->r_ss = tf->tf_ss; - regs->r_ds = tf->tf_ds; - regs->r_es = tf->tf_es; - regs->r_fs = tf->tf_fs; - regs->r_gs = tf->tf_gs; + regs->r_ds = GSEL(GUDATA_SEL, SEL_UPL); + regs->r_es = GSEL(GUDATA_SEL, SEL_UPL); + regs->r_fs = GSEL(GUDATA_SEL, SEL_UPL); + regs->r_gs = GSEL(GUDATA_SEL, SEL_UPL); return (0); } @@ -177,10 +177,6 @@ process_write_regs(struct proc *p, struct reg *regs) tf->tf_rflags = regs->r_rflags; tf->tf_cs = regs->r_cs; tf->tf_ss = regs->r_ss; - tf->tf_ds = regs->r_ds; - tf->tf_es = regs->r_es; - tf->tf_fs = regs->r_fs; - tf->tf_gs = regs->r_gs; return (0); } diff --git a/sys/arch/amd64/amd64/sys_machdep.c b/sys/arch/amd64/amd64/sys_machdep.c index 97af7d80a5f..6bde501bbee 100644 --- a/sys/arch/amd64/amd64/sys_machdep.c +++ b/sys/arch/amd64/amd64/sys_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sys_machdep.c,v 1.15 2015/03/14 03:38:46 jsg Exp $ */ +/* $OpenBSD: sys_machdep.c,v 1.16 2015/05/18 19:59:27 guenther Exp $ */ /* $NetBSD: sys_machdep.c,v 1.1 2003/04/26 18:39:32 fvdl Exp $ */ /*- @@ -51,6 +51,7 @@ #include #include #include +#include #if defined(PERFCTRS) && 0 #include @@ -96,23 +97,21 @@ amd64_iopl(struct proc *p, void *args, register_t *retval) int amd64_get_fsbase(struct proc *p, void *args) { - return copyout(&p->p_addr->u_pcb.pcb_fsbase, args, - sizeof(p->p_addr->u_pcb.pcb_fsbase)); + void *base = tcb_get(p); + + return (copyout(&base, args, sizeof(base))); } int amd64_set_fsbase(struct proc *p, void *args) { int error; - uint64_t base; + void *base; if ((error = copyin(args, &base, sizeof(base))) != 0) return (error); - if (base >= VM_MAXUSER_ADDRESS) - return (EINVAL); - - p->p_addr->u_pcb.pcb_fsbase = base; + tcb_set(p, base); return 0; } diff --git a/sys/arch/amd64/amd64/vector.S b/sys/arch/amd64/amd64/vector.S index aa2f10f940e..9e1d24408b6 100644 --- a/sys/arch/amd64/amd64/vector.S +++ b/sys/arch/amd64/amd64/vector.S @@ -1,4 +1,4 @@ -/* $OpenBSD: vector.S,v 1.37 2015/04/19 19:45:21 sf Exp $ */ +/* $OpenBSD: vector.S,v 1.38 2015/05/18 19:59:27 guenther Exp $ */ /* $NetBSD: vector.S,v 1.5 2004/06/28 09:13:11 fvdl Exp $ */ /* @@ -156,11 +156,7 @@ IDTVEC(trap0d) testq $SEL_UPL,TF_CS(%rsp) jz 2f 1: swapgs -2: movw %gs,TF_GS(%rsp) - movw %fs,TF_FS(%rsp) - movw %es,TF_ES(%rsp) - movw %ds,TF_DS(%rsp) - movq %r15,TF_R15(%rsp) +2: movq %r15,TF_R15(%rsp) movq %r14,TF_R14(%rsp) movq %r13,TF_R13(%rsp) movq %r12,TF_R12(%rsp) diff --git a/sys/arch/amd64/amd64/vm_machdep.c b/sys/arch/amd64/amd64/vm_machdep.c index 52d0c5037f1..da9ce9fe4fd 100644 --- a/sys/arch/amd64/amd64/vm_machdep.c +++ b/sys/arch/amd64/amd64/vm_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vm_machdep.c,v 1.31 2015/05/05 02:13:46 guenther Exp $ */ +/* $OpenBSD: vm_machdep.c,v 1.32 2015/05/18 19:59:27 guenther Exp $ */ /* $NetBSD: vm_machdep.c,v 1.1 2003/04/26 18:39:33 fvdl Exp $ */ /*- @@ -58,6 +58,7 @@ #include #include #include +#include void setredzone(struct proc *); @@ -223,3 +224,16 @@ vunmapbuf(struct buf *bp, vsize_t len) bp->b_data = bp->b_saveaddr; bp->b_saveaddr = 0; } + +void * +tcb_get(struct proc *p) +{ + return ((void *)p->p_addr->u_pcb.pcb_fsbase); +} + +void +tcb_set(struct proc *p, void *tcb) +{ + KASSERT(p == curproc); + reset_segs(&p->p_addr->u_pcb, (u_int64_t)tcb); +} diff --git a/sys/arch/amd64/include/cpu.h b/sys/arch/amd64/include/cpu.h index 7caefde92ff..fb010dc87f4 100644 --- a/sys/arch/amd64/include/cpu.h +++ b/sys/arch/amd64/include/cpu.h @@ -1,4 +1,4 @@ -/* $OpenBSD: cpu.h,v 1.91 2015/04/18 22:16:21 kettenis Exp $ */ +/* $OpenBSD: cpu.h,v 1.92 2015/05/18 19:59:27 guenther Exp $ */ /* $NetBSD: cpu.h,v 1.1 2003/04/26 18:39:39 fvdl Exp $ */ /*- @@ -144,6 +144,8 @@ struct cpu_info { #define CPUF_IDENTIFIED 0x0020 /* CPU has been identified */ #define CPUF_CONST_TSC 0x0040 /* CPU has constant TSC */ +#define CPUF_USERSEGS_BIT 7 /* CPU has curproc's segments */ +#define CPUF_USERSEGS (1< @@ -21,12 +21,11 @@ #ifdef _KERNEL -#include +void *tcb_get(struct proc *_p); +void tcb_set(struct proc *_p, void *_newtcb); -#define TCB_GET(p) \ - ((void *)((struct pcb *)(p)->p_addr)->pcb_fsbase) -#define TCB_SET(p, addr) \ - (((struct pcb *)(p)->p_addr)->pcb_fsbase = (u_int64_t)(addr)) +#define TCB_GET(p) tcb_get(p) +#define TCB_SET(p, addr) tcb_set(p, addr) #else /* _KERNEL */