summaryrefslogtreecommitdiffstats
path: root/sys/i386/i386/trap.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/i386/i386/trap.c')
-rw-r--r--sys/i386/i386/trap.c30
1 files changed, 30 insertions, 0 deletions
diff --git a/sys/i386/i386/trap.c b/sys/i386/i386/trap.c
index 000ff17..7fa94f4 100644
--- a/sys/i386/i386/trap.c
+++ b/sys/i386/i386/trap.c
@@ -116,6 +116,8 @@ void dblfault_handler(void);
extern inthand_t IDTVEC(lcall_syscall);
+extern inthand_t IDTVEC(bpt), IDTVEC(dbg), IDTVEC(int0x80_syscall);
+
#define MAX_TRAP_MSG 32
static char *trap_msg[] = {
"", /* 0 unused */
@@ -668,6 +670,34 @@ kernel_trctrap:
load_dr6(rdr6() & ~0xf);
goto out;
}
+
+ /*
+ * Malicious user code can configure a debug
+ * register watchpoint to trap on data access
+ * to the top of stack and then execute 'pop
+ * %ss; int 3'. Due to exception deferral for
+ * 'pop %ss', the CPU will not interrupt 'int
+ * 3' to raise the DB# exception for the debug
+ * register but will postpone the DB# until
+ * execution of the first instruction of the
+ * BP# handler (in kernel mode). Normally the
+ * previous check would ignore DB# exceptions
+ * for watchpoints on user addresses raised in
+ * kernel mode. However, some CPU errata
+ * include cases where DB# exceptions do not
+ * properly set bits in %dr6, e.g. Haswell
+ * HSD23 and Skylake-X SKZ24.
+ *
+ * A deferred DB# can also be raised on the
+ * first instructions of system call entry
+ * points or single-step traps via similar use
+ * of 'pop %ss' or 'mov xxx, %ss'.
+ */
+ if (frame->tf_eip ==
+ (uintptr_t)IDTVEC(int0x80_syscall) ||
+ frame->tf_eip == (uintptr_t)IDTVEC(bpt) ||
+ frame->tf_eip == (uintptr_t)IDTVEC(dbg))
+ return;
/*
* FALLTHROUGH (TRCTRAP kernel mode, kernel address)
*/
OpenPOWER on IntegriCloud