summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorguenther <guenther@openbsd.org>2017-10-04 02:10:33 +0000
committerguenther <guenther@openbsd.org>2017-10-04 02:10:33 +0000
commit198d2c0b5f3bd7bc8fe753be0dc3ca31bc97c53d (patch)
tree7e67370022c32f6e3eda9110a9074184507c3c26
parentNested xrstor handled leaks a kernel address into sigval, but potential (diff)
downloadwireguard-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.c16
-rw-r--r--sys/arch/amd64/amd64/locore.S6
-rw-r--r--sys/arch/amd64/amd64/trap.c11
-rw-r--r--sys/arch/amd64/amd64/vector.S3
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)