Do lazy update/reset of the FS.base and %[def]s segment registers: reseting
authorguenther <guenther@openbsd.org>
Mon, 18 May 2015 19:59:27 +0000 (19:59 +0000)
committerguenther <guenther@openbsd.org>
Mon, 18 May 2015 19:59:27 +0000 (19:59 +0000)
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@

13 files changed:
sys/arch/amd64/amd64/db_interface.c
sys/arch/amd64/amd64/db_trace.c
sys/arch/amd64/amd64/genassym.cf
sys/arch/amd64/amd64/locore.S
sys/arch/amd64/amd64/machdep.c
sys/arch/amd64/amd64/process_machdep.c
sys/arch/amd64/amd64/sys_machdep.c
sys/arch/amd64/amd64/vector.S
sys/arch/amd64/amd64/vm_machdep.c
sys/arch/amd64/include/cpu.h
sys/arch/amd64/include/frameasm.h
sys/arch/amd64/include/pcb.h
sys/arch/amd64/include/tcb.h

index a822f22..2f182fa 100644 (file)
@@ -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();
index 03f1f8c..58f96e4 100644 (file)
@@ -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 },
index e13a477..80bc03c 100644 (file)
@@ -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 <sys/param.h>
@@ -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
index d3f9cff..c264f9a 100644 (file)
@@ -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)
index 5062679..a5f17eb 100644 (file)
@@ -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;
index 9b3f0f2..823a93e 100644 (file)
@@ -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);
 }
index 97af7d8..6bde501 100644 (file)
@@ -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 <machine/psl.h>
 #include <machine/reg.h>
 #include <machine/sysarch.h>
+#include <machine/tcb.h>
 
 #if defined(PERFCTRS) && 0
 #include <machine/pmc.h>
@@ -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;
 }
 
index aa2f10f..9e1d244 100644 (file)
@@ -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)
index 52d0c50..da9ce9f 100644 (file)
@@ -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 <machine/cpu.h>
 #include <machine/reg.h>
 #include <machine/fpu.h>
+#include <machine/tcb.h>
 
 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);
+}
index 7caefde..fb010dc 100644 (file)
@@ -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<<CPUF_USERSEGS_BIT)          /* and FS.base */
 
 #define CPUF_PRESENT   0x1000          /* CPU is present */
 #define CPUF_RUNNING   0x2000          /* CPU is running */
index 95a1e0f..b06d1bf 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: frameasm.h,v 1.7 2012/04/17 16:02:33 guenther Exp $   */
+/*     $OpenBSD: frameasm.h,v 1.8 2015/05/18 19:59:27 guenther Exp $   */
 /*     $NetBSD: frameasm.h,v 1.1 2003/04/26 18:39:40 fvdl Exp $        */
 
 #ifndef _AMD64_MACHINE_FRAMEASM_H
        testq   $SEL_UPL,56(%rsp)       ; \
        je      98f                     ; \
        swapgs                          ; \
-       movw    %gs,0(%rsp)             ; \
-       movw    %fs,8(%rsp)             ; \
-       movw    %es,16(%rsp)            ; \
-       movw    %ds,24(%rsp)            ; \
 98:    INTR_SAVE_GPRS
 
 #define INTRFASTEXIT \
        pushq   %r13                    ;
 
 /*
- * Restore %ds, %es, %fs, and %gs, dealing with the FS.base MSR for
- * %fs and doing the cli/swapgs for %gs.  Uses %rax, %rcx, and %rdx
+ * Restore FS.base if it's not already in the CPU, and do the cli/swapgs.
+ * Uses %rax, %rcx, and %rdx
  */
 #define INTR_RESTORE_SELECTORS                                         \
+       btsl    $CPUF_USERSEGS_BIT, CPUVAR(FLAGS)                       ; \
+       jc      99f                                                     ; \
        movq    CPUVAR(CURPCB),%rdx     /* for below */                 ; \
-       /* %es and %ds */                                                 \
-       movw    TF_ES(%rsp),%es                                         ; \
-       movw    $(GSEL(GUDATA_SEL, SEL_UPL)),%ax                        ; \
-       movw    %ax,%ds                                                 ; \
-       /* Make sure both %fs and FS.base are the desired values */       \
-       movw    TF_FS(%rsp),%fs                                         ; \
        movq    PCB_FSBASE(%rdx),%rax                                   ; \
        cmpq    $0,%rax                                                 ; \
        je      99f             /* setting %fs has zeroed FS.base */    ; \
        shrq    $32,%rdx                                                ; \
        movl    $MSR_FSBASE,%ecx                                        ; \
        wrmsr                                                           ; \
-99:    cli             /* %fs done, so swapgs and do %gs */            ; \
+99:    movw    $(GSEL(GUDATA_SEL, SEL_UPL)),%ax                        ; \
+       cli                                                             ; \
        swapgs                                                          ; \
-       movw    TF_GS(%rsp),%gs
+       movw    %ax,%gs
 
 
 #define CHECK_ASTPENDING(reg)  movq    CPUVAR(CURPROC),reg             ; \
index 85efc56..8462444 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: pcb.h,v 1.13 2015/05/05 02:13:46 guenther Exp $       */
+/*     $OpenBSD: pcb.h,v 1.14 2015/05/18 19:59:27 guenther Exp $       */
 /*     $NetBSD: pcb.h,v 1.1 2003/04/26 18:39:45 fvdl Exp $     */
 
 /*-
@@ -89,4 +89,8 @@ struct pcb {
        int     pcb_cr0;                /* saved image of CR0 */
 };
 
+#ifdef _KERNEL
+void   reset_segs(struct pcb *_pcb, u_int64_t _fsbase);
+#endif
+
 #endif /* _MACHINE_PCB_H_ */
index 6bbfff6..3f7c209 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: tcb.h,v 1.2 2011/10/19 06:48:56 guenther Exp $        */
+/*     $OpenBSD: tcb.h,v 1.3 2015/05/18 19:59:27 guenther Exp $        */
 
 /*
  * Copyright (c) 2011 Philip Guenther <guenther@openbsd.org>
 
 #ifdef _KERNEL
 
-#include <machine/pcb.h>
+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 */