kvm: check CPL to find out if the Sentry is in VM

RFLAGS cannot be used because the IF flag (interrupt flag) is cleared when
a goroutine suspended on the host side is resumed in the VM. This means it
can start switching into the vm when it is already in the VM. It only works
because the rt_sigprocmask syscall is triggered before constructing a signal
frame, returning execution back to the host side, and then it switches into
the VM again.

Fixes: 374a11a7cd ("platform/kvm: rewriting bluepill()...")
PiperOrigin-RevId: 673621750
This commit is contained in:
Andrei Vagin
2024-09-11 18:52:36 -07:00
committed by gVisor bot
parent 9a61c0b3a2
commit 2a413db730
3 changed files with 13 additions and 8 deletions
+3 -4
View File
@@ -59,10 +59,9 @@ fallback:
MOVQ ·savedSigsysHandler(SB), AX
JMP AX
TEXT ·rflags(SB), $8-8
PUSHFQ
POPQ AX
MOVQ AX, ret+0(FP)
TEXT ·getcs(SB), $0-2
MOVW CS, AX
MOVW AX, ret+0(FP)
RET
TEXT ·addrOfBluepillUserHandler(SB), $0-8
@@ -148,9 +148,8 @@ func bluepillArchHandleExit(c *vCPU, context unsafe.Pointer) {
}
func addrOfBluepillUserHandler() uintptr
func rflags() uint64
const _RFLAGS_IF = 1 << 9
func getcs() uint16
func currentCPU() *vCPU
@@ -158,8 +157,8 @@ func currentCPU() *vCPU
//
//go:nosplit
func bluepill(c *vCPU) {
// Interrupts are always disabled in the VM.
if rflags()&_RFLAGS_IF == 0 {
// The sentry is running in the VM ring 0.
if getcs()&3 == 0 {
if currentCPU() == c {
// Already in the vm.
return
@@ -29,6 +29,13 @@ import (
"gvisor.dev/gvisor/pkg/sentry/platform/kvm/testutil"
)
func TestGetCS(t *testing.T) {
cs := getcs()
if cs != 0x33 {
t.Fatalf("cs = 0x%x", cs)
}
}
func TestSegments(t *testing.T) {
applicationTest(t, true, testutil.AddrOfTwiddleSegments(), func(c *vCPU, regs *arch.Registers, pt *pagetables.PageTables) bool {
testutil.SetTestSegments(regs)