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
This commit is contained in:
parent
071c00f495
commit
50cb59e230
@ -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:
|
||||
/*
|
||||
|
@ -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));
|
||||
|
Loading…
x
Reference in New Issue
Block a user