From 2a413db7300639f82d4d7fe7ccf1e0c4f7ccd2d5 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Wed, 11 Sep 2024 18:48:20 -0700 Subject: [PATCH] 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: 374a11a7cd58 ("platform/kvm: rewriting bluepill()...") PiperOrigin-RevId: 673621750 --- pkg/sentry/platform/kvm/bluepill_amd64.s | 7 +++---- pkg/sentry/platform/kvm/bluepill_amd64_unsafe.go | 7 +++---- pkg/sentry/platform/kvm/kvm_amd64_test.go | 7 +++++++ 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/pkg/sentry/platform/kvm/bluepill_amd64.s b/pkg/sentry/platform/kvm/bluepill_amd64.s index 4f9128b58..07106b182 100644 --- a/pkg/sentry/platform/kvm/bluepill_amd64.s +++ b/pkg/sentry/platform/kvm/bluepill_amd64.s @@ -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 diff --git a/pkg/sentry/platform/kvm/bluepill_amd64_unsafe.go b/pkg/sentry/platform/kvm/bluepill_amd64_unsafe.go index a961b3bba..3d6eed70a 100644 --- a/pkg/sentry/platform/kvm/bluepill_amd64_unsafe.go +++ b/pkg/sentry/platform/kvm/bluepill_amd64_unsafe.go @@ -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 diff --git a/pkg/sentry/platform/kvm/kvm_amd64_test.go b/pkg/sentry/platform/kvm/kvm_amd64_test.go index 343e9ddf1..69fdbbf5d 100644 --- a/pkg/sentry/platform/kvm/kvm_amd64_test.go +++ b/pkg/sentry/platform/kvm/kvm_amd64_test.go @@ -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)