Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 28 Sep 2017 09:01:28 +0000 (UTC)
From:      Konstantin Belousov <kib@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r324080 - head/sys/i386/i386
Message-ID:  <201709280901.v8S91SYk051539@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
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@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));



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201709280901.v8S91SYk051539>