svn commit: r324080 - head/sys/i386/i386
Konstantin Belousov
kib at FreeBSD.org
Thu Sep 28 09:01:30 UTC 2017
Author: kib
Date: Thu Sep 28 09:01:28 2017
New Revision: 324080
URL: https://svnweb.freebsd.org/changeset/base/324080
Log:
A different fix for the issue from r323722.
Split the handlers for pop of invalid selectors from the trap frame
into usermode and kernel variants. Usermode handler is kept as is, it
restores the already loaded parts of the trap frame and jumps to set
up a signal delivery to the user process.
New kernel part of the handler emulates IRET treatment of the segments
which would violate access right. It loads NUL selector in the
segment register which load causes the fault, and then continues the
return to interrupted kernel code. Since invalid selectors in the
segment registers in the kernel mode can only exist while kernel still
enters or exits from userspace, we only zero invalid userspace
selectors. If userspace tries to use the segment register, it gets a
signal, as if the processor segment descriptor cache was reloaded.
Reported by: Maxime Villard <max at m00nbsd.net>
Suggested and reviewed by: bde
Sponsored by: The FreeBSD Foundation
MFC after: 1 week
Modified:
head/sys/i386/i386/exception.s
head/sys/i386/i386/genassym.c
Modified: head/sys/i386/i386/exception.s
==============================================================================
--- head/sys/i386/i386/exception.s Thu Sep 28 08:46:15 2017 (r324079)
+++ head/sys/i386/i386/exception.s Thu Sep 28 09:01:28 2017 (r324080)
@@ -425,8 +425,16 @@ doreti_iret:
* doreti_iret_fault and friends. Alternative return code for
* the case where we get a fault in the doreti_exit code
* above. trap() (i386/i386/trap.c) catches this specific
- * case, sends the process a signal and continues in the
- * corresponding place in the code below.
+ * case, and continues in the corresponding place in the code
+ * below.
+ *
+ * If the fault occured during return to usermode, we recreate
+ * the trap frame and call trap() to send a signal. Otherwise
+ * the kernel was tricked into fault by attempt to restore invalid
+ * usermode segment selectors on return from nested fault or
+ * interrupt, where interrupted kernel entry code not yet loaded
+ * kernel selectors. In the latter case, emulate iret and zero
+ * the invalid selector.
*/
ALIGN_TEXT
.globl doreti_iret_fault
@@ -437,18 +445,35 @@ doreti_iret_fault:
movw %ds,(%esp)
.globl doreti_popl_ds_fault
doreti_popl_ds_fault:
+ testb $SEL_RPL_MASK,TF_CS-TF_DS(%esp)
+ jz doreti_popl_ds_kfault
pushl $0
movw %es,(%esp)
.globl doreti_popl_es_fault
doreti_popl_es_fault:
+ testb $SEL_RPL_MASK,TF_CS-TF_ES(%esp)
+ jz doreti_popl_es_kfault
pushl $0
movw %fs,(%esp)
.globl doreti_popl_fs_fault
doreti_popl_fs_fault:
+ testb $SEL_RPL_MASK,TF_CS-TF_FS(%esp)
+ jz doreti_popl_fs_kfault
sti
movl $0,TF_ERR(%esp) /* XXX should be the error code */
movl $T_PROTFLT,TF_TRAPNO(%esp)
jmp alltraps_with_regs_pushed
+
+doreti_popl_ds_kfault:
+ movl $0,(%esp)
+ jmp doreti_popl_ds
+doreti_popl_es_kfault:
+ movl $0,(%esp)
+ jmp doreti_popl_es
+doreti_popl_fs_kfault:
+ movl $0,(%esp)
+ jmp doreti_popl_fs
+
#ifdef HWPMC_HOOKS
doreti_nmi:
/*
Modified: head/sys/i386/i386/genassym.c
==============================================================================
--- head/sys/i386/i386/genassym.c Thu Sep 28 08:46:15 2017 (r324079)
+++ head/sys/i386/i386/genassym.c Thu Sep 28 09:01:28 2017 (r324080)
@@ -156,11 +156,15 @@ ASSYM(PCB_IDT, offsetof(struct pcb, pcb_idt));
ASSYM(PCB_LDT, offsetof(struct pcb, pcb_ldt));
ASSYM(PCB_TR, offsetof(struct pcb, pcb_tr));
+ASSYM(TF_FS, offsetof(struct trapframe, tf_fs));
+ASSYM(TF_ES, offsetof(struct trapframe, tf_es));
+ASSYM(TF_DS, offsetof(struct trapframe, tf_ds));
ASSYM(TF_TRAPNO, offsetof(struct trapframe, tf_trapno));
ASSYM(TF_ERR, offsetof(struct trapframe, tf_err));
ASSYM(TF_EIP, offsetof(struct trapframe, tf_eip));
ASSYM(TF_CS, offsetof(struct trapframe, tf_cs));
ASSYM(TF_EFLAGS, offsetof(struct trapframe, tf_eflags));
+
ASSYM(SIGF_HANDLER, offsetof(struct sigframe, sf_ahu.sf_handler));
#ifdef COMPAT_43
ASSYM(SIGF_SC, offsetof(struct osigframe, sf_siginfo.si_sc));
More information about the svn-src-all
mailing list