mirror of
https://github.com/freebsd/freebsd-src
synced 2024-09-19 08:13:57 +00:00
- When executing FreeBSD/amd64 binaries from FreeBSD/i386 or Linux/i386
processes, clear PCB_32BIT and PCB_GS32BIT bits [1]. - Reread the fs and gs bases from the msr unconditionally, not believing the values in pcb_fsbase and pcb_gsbase, since usermode may reload segment registers, invalidating the cache. [2]. Both problems resulted in the wrong fs base, causing wrong tls pointer be dereferenced in the usermode. Reported and tested by: Vyacheslav Bocharov <adeepv at gmail com> [1] Reported by: Bernd Walter <ticsoat cicely7 cicely de>, Artem Belevich <fbsdlist at src cx>[2] Reviewed by: peter MFC after: 3 days
This commit is contained in:
parent
ffffa83b60
commit
f98c3ea74e
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=182684
|
@ -109,8 +109,24 @@ ENTRY(cpu_switch)
|
||||||
movq %rsp,PCB_RSP(%r8)
|
movq %rsp,PCB_RSP(%r8)
|
||||||
movq %rbx,PCB_RBX(%r8)
|
movq %rbx,PCB_RBX(%r8)
|
||||||
movq %rax,PCB_RIP(%r8)
|
movq %rax,PCB_RIP(%r8)
|
||||||
movq PCB_FSBASE(%r8),%r9
|
|
||||||
movq PCB_GSBASE(%r8),%r10
|
/*
|
||||||
|
* Reread fs and gs bases. Explicit fs segment register load
|
||||||
|
* by the usermode code may change actual fs base without
|
||||||
|
* updating pcb_{fs,gs}base.
|
||||||
|
*
|
||||||
|
* %rdx still contains the mtx, save %rdx around rdmsr.
|
||||||
|
*/
|
||||||
|
movq %rdx,%r11
|
||||||
|
movl $MSR_FSBASE,%ecx
|
||||||
|
rdmsr
|
||||||
|
shlq $32,%rdx
|
||||||
|
leaq (%rax,%rdx),%r9
|
||||||
|
movl $MSR_KGSBASE,%ecx
|
||||||
|
rdmsr
|
||||||
|
shlq $32,%rdx
|
||||||
|
leaq (%rax,%rdx),%r10
|
||||||
|
movq %r11,%rdx
|
||||||
|
|
||||||
testl $PCB_32BIT,PCB_FLAGS(%r8)
|
testl $PCB_32BIT,PCB_FLAGS(%r8)
|
||||||
jnz store_seg
|
jnz store_seg
|
||||||
|
|
|
@ -734,6 +734,7 @@ exec_setregs(td, entry, stack, ps_strings)
|
||||||
pcb->pcb_fsbase = 0;
|
pcb->pcb_fsbase = 0;
|
||||||
pcb->pcb_gsbase = 0;
|
pcb->pcb_gsbase = 0;
|
||||||
critical_exit();
|
critical_exit();
|
||||||
|
pcb->pcb_flags &= ~(PCB_32BIT | PCB_GS32BIT);
|
||||||
load_ds(_udatasel);
|
load_ds(_udatasel);
|
||||||
load_es(_udatasel);
|
load_es(_udatasel);
|
||||||
load_fs(_udatasel);
|
load_fs(_udatasel);
|
||||||
|
|
|
@ -742,5 +742,6 @@ ia32_setregs(td, entry, stack, ps_strings)
|
||||||
|
|
||||||
/* Return via doreti so that we can change to a different %cs */
|
/* Return via doreti so that we can change to a different %cs */
|
||||||
pcb->pcb_flags |= PCB_FULLCTX | PCB_32BIT;
|
pcb->pcb_flags |= PCB_FULLCTX | PCB_32BIT;
|
||||||
|
pcb->pcb_flags &= ~PCB_GS32BIT;
|
||||||
td->td_retval[1] = 0;
|
td->td_retval[1] = 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue