diff options
author | 2017-10-04 02:10:33 +0000 | |
---|---|---|
committer | 2017-10-04 02:10:33 +0000 | |
commit | 198d2c0b5f3bd7bc8fe753be0dc3ca31bc97c53d (patch) | |
tree | 7e67370022c32f6e3eda9110a9074184507c3c26 | |
parent | Nested xrstor handled leaks a kernel address into sigval, but potential (diff) | |
download | wireguard-openbsd-198d2c0b5f3bd7bc8fe753be0dc3ca31bc97c53d.tar.xz wireguard-openbsd-198d2c0b5f3bd7bc8fe753be0dc3ca31bc97c53d.zip |
Follow the pattern set by copy*/pcb_onfault: when xrstor faults, return
from the trap to a 'resume' address to effectively make xrstor_user()
return an error indication, then do the FPU cleanup and trap generation
from there where we can get access to the original, userspace trapframe.
The original fix tried to handle the trap while on the wrong trapframe,
leaking kernel addresses and possibly leading to double faults.
Problem pointed out by abluhm@
ok deraadt@ mikeb@
-rw-r--r-- | sys/arch/amd64/amd64/fpu.c | 16 | ||||
-rw-r--r-- | sys/arch/amd64/amd64/locore.S | 6 | ||||
-rw-r--r-- | sys/arch/amd64/amd64/trap.c | 11 | ||||
-rw-r--r-- | sys/arch/amd64/amd64/vector.S | 3 |
4 files changed, 23 insertions, 13 deletions
diff --git a/sys/arch/amd64/amd64/fpu.c b/sys/arch/amd64/amd64/fpu.c index 74cd263c015..f9b55c648cf 100644 --- a/sys/arch/amd64/amd64/fpu.c +++ b/sys/arch/amd64/amd64/fpu.c @@ -1,4 +1,4 @@ -/* $OpenBSD: fpu.c,v 1.36 2017/10/03 17:36:40 guenther Exp $ */ +/* $OpenBSD: fpu.c,v 1.37 2017/10/04 02:10:33 guenther Exp $ */ /* $NetBSD: fpu.c,v 1.1 2003/04/26 18:39:28 fvdl Exp $ */ /*- @@ -55,7 +55,8 @@ #include <dev/isa/isavar.h> -void xrstor_user(struct savefpu *_addr, uint64_t _mask); +int xrstor_user(struct savefpu *_addr, uint64_t _mask); +void trap(struct trapframe *); /* * We do lazy initialization and switching using the TS bit in cr0 and the @@ -80,7 +81,7 @@ void xrstor_user(struct savefpu *_addr, uint64_t _mask); */ uint64_t xsave_mask; -void fpudna(struct cpu_info *); +void fpudna(struct cpu_info *, struct trapframe *); static int x86fpflags_to_siginfo(u_int32_t); /* @@ -194,7 +195,7 @@ x86fpflags_to_siginfo(u_int32_t flags) * saved state. */ void -fpudna(struct cpu_info *ci) +fpudna(struct cpu_info *ci, struct trapframe *frame) { struct savefpu *sfp; struct proc *p; @@ -255,7 +256,12 @@ fpudna(struct cpu_info *ci) p->p_md.md_flags |= MDP_USEDFPU; } else { if (xsave_mask) { - xrstor_user(sfp, xsave_mask); + if (xrstor_user(sfp, xsave_mask)) { + fpusave_proc(p, 0); /* faulted */ + frame->tf_trapno = T_PROTFLT; + trap(frame); + return; + } } else { static double zero = 0.0; diff --git a/sys/arch/amd64/amd64/locore.S b/sys/arch/amd64/amd64/locore.S index e0fa7144b62..179504c9aca 100644 --- a/sys/arch/amd64/amd64/locore.S +++ b/sys/arch/amd64/amd64/locore.S @@ -1,4 +1,4 @@ -/* $OpenBSD: locore.S,v 1.88 2017/10/03 17:36:40 guenther Exp $ */ +/* $OpenBSD: locore.S,v 1.89 2017/10/04 02:10:33 guenther Exp $ */ /* $NetBSD: locore.S,v 1.13 2004/03/25 18:33:17 drochner Exp $ */ /* @@ -698,6 +698,10 @@ ENTRY(xrstor_user) .globl xrstor_fault xrstor_fault: xrstor (%rdi) + xorl %eax, %eax + ret +ENTRY(xrstor_resume) + movl $1, %eax ret ENTRY(pagezero) diff --git a/sys/arch/amd64/amd64/trap.c b/sys/arch/amd64/amd64/trap.c index 5b720d10a30..6bb389aad62 100644 --- a/sys/arch/amd64/amd64/trap.c +++ b/sys/arch/amd64/amd64/trap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: trap.c,v 1.60 2017/10/03 22:06:19 deraadt Exp $ */ +/* $OpenBSD: trap.c,v 1.61 2017/10/04 02:10:33 guenther Exp $ */ /* $NetBSD: trap.c,v 1.2 2003/05/04 23:51:56 fvdl Exp $ */ /*- @@ -144,7 +144,8 @@ trap(struct trapframe *frame) struct proc *p = curproc; int type = (int)frame->tf_trapno; struct pcb *pcb; - extern char doreti_iret[], resume_iret[], xrstor_fault[]; + extern char doreti_iret[], resume_iret[]; + extern char xrstor_fault[], xrstor_resume[]; caddr_t onfault; int error; uint64_t cr2; @@ -210,9 +211,8 @@ trap(struct trapframe *frame) * instruction that faulted. */ if (frame->tf_rip == (u_int64_t)xrstor_fault && p != NULL) { - fpusave_proc(p, 0); - frame->tf_rip = 0; /* Hide kernel address */ - goto user_trap; + frame->tf_rip = (u_int64_t)xrstor_resume; + return; } case T_SEGNPFLT: case T_ALIGNFLT: @@ -241,7 +241,6 @@ copyfault: case T_TSSFLT|T_USER: case T_SEGNPFLT|T_USER: case T_STKFLT|T_USER: -user_trap: #ifdef TRAP_SIGDEBUG printf("pid %d (%s): %s at rip %llx addr %llx\n", p->p_p->ps_pid, p->p_p->ps_comm, "BUS", diff --git a/sys/arch/amd64/amd64/vector.S b/sys/arch/amd64/amd64/vector.S index d88edeb315c..730220af132 100644 --- a/sys/arch/amd64/amd64/vector.S +++ b/sys/arch/amd64/amd64/vector.S @@ -1,4 +1,4 @@ -/* $OpenBSD: vector.S,v 1.50 2017/08/25 19:28:48 guenther Exp $ */ +/* $OpenBSD: vector.S,v 1.51 2017/10/04 02:10:33 guenther Exp $ */ /* $NetBSD: vector.S,v 1.5 2004/06/28 09:13:11 fvdl Exp $ */ /* @@ -127,6 +127,7 @@ IDTVEC(trap07) cld SMAP_CLAC movq CPUVAR(SELF),%rdi + movq %rsp, %rsi call _C_LABEL(fpudna) INTRFASTEXIT IDTVEC(trap08) |