diff options
author | kib <kib@FreeBSD.org> | 2008-09-02 17:52:11 +0000 |
---|---|---|
committer | kib <kib@FreeBSD.org> | 2008-09-02 17:52:11 +0000 |
commit | 59a00054acff9e2ada7d2366d4aeaec829dcd3a4 (patch) | |
tree | 6ebcf1585c96d0e1d8f54111b10eb1820d727ffe /sys/amd64/amd64/cpu_switch.S | |
parent | 84967086499f3a1a3480390747da9dcc1ae26abd (diff) | |
download | FreeBSD-src-59a00054acff9e2ada7d2366d4aeaec829dcd3a4.zip FreeBSD-src-59a00054acff9e2ada7d2366d4aeaec829dcd3a4.tar.gz |
- 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
Diffstat (limited to 'sys/amd64/amd64/cpu_switch.S')
-rw-r--r-- | sys/amd64/amd64/cpu_switch.S | 20 |
1 files changed, 18 insertions, 2 deletions
diff --git a/sys/amd64/amd64/cpu_switch.S b/sys/amd64/amd64/cpu_switch.S index f34b0cc..a0b11f8 100644 --- a/sys/amd64/amd64/cpu_switch.S +++ b/sys/amd64/amd64/cpu_switch.S @@ -109,8 +109,24 @@ ENTRY(cpu_switch) movq %rsp,PCB_RSP(%r8) movq %rbx,PCB_RBX(%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) jnz store_seg |