-/* $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 $ */
/*
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();
-/* $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 $ */
/*
* 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 },
-# $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>
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
-/* $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 $ */
/*
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.
*
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)
-/* $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 $ */
/*-
/*
* 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;
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
*/
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;
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;
-/* $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 $ */
/*-
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);
}
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);
}
-/* $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 $ */
/*-
#include <machine/psl.h>
#include <machine/reg.h>
#include <machine/sysarch.h>
+#include <machine/tcb.h>
#if defined(PERFCTRS) && 0
#include <machine/pmc.h>
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;
}
-/* $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 $ */
/*
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)
-/* $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 $ */
/*-
#include <machine/cpu.h>
#include <machine/reg.h>
#include <machine/fpu.h>
+#include <machine/tcb.h>
void setredzone(struct proc *);
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);
+}
-/* $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 $ */
/*-
#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 */
-/* $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 ; \
-/* $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 $ */
/*-
int pcb_cr0; /* saved image of CR0 */
};
+#ifdef _KERNEL
+void reset_segs(struct pcb *_pcb, u_int64_t _fsbase);
+#endif
+
#endif /* _MACHINE_PCB_H_ */
-/* $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 */