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>