KVM: arm64: Detect and handle hypervisor stack overflows
authorKalesh Singh <kaleshsingh@google.com>
Wed, 20 Apr 2022 21:42:56 +0000 (14:42 -0700)
committerMarc Zyngier <maz@kernel.org>
Thu, 28 Apr 2022 19:53:13 +0000 (20:53 +0100)
The hypervisor stacks (for both nVHE Hyp mode and nVHE protected mode)
are aligned such  that any valid stack address has PAGE_SHIFT bit as 1.
This allows us to conveniently check for overflow in the exception entry
without corrupting any GPRs. We won't recover from a stack overflow so
panic the hypervisor.

Signed-off-by: Kalesh Singh <kaleshsingh@google.com>
Tested-by: Fuad Tabba <tabba@google.com>
Reviewed-by: Fuad Tabba <tabba@google.com>
Signed-off-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20220420214317.3303360-6-kaleshsingh@google.com
arch/arm64/kvm/hyp/nvhe/host.S
arch/arm64/kvm/hyp/nvhe/switch.c

index 3d613e7..09b5254 100644 (file)
@@ -153,6 +153,18 @@ SYM_FUNC_END(__host_hvc)
 
 .macro invalid_host_el2_vect
        .align 7
+
+       /*
+        * Test whether the SP has overflowed, without corrupting a GPR.
+        * nVHE hypervisor stacks are aligned so that the PAGE_SHIFT bit
+        * of SP should always be 1.
+        */
+       add     sp, sp, x0                      // sp' = sp + x0
+       sub     x0, sp, x0                      // x0' = sp' - x0 = (sp + x0) - x0 = sp
+       tbz     x0, #PAGE_SHIFT, .L__hyp_sp_overflow\@
+       sub     x0, sp, x0                      // x0'' = sp' - x0' = (sp + x0) - sp = x0
+       sub     sp, sp, x0                      // sp'' = sp' - x0 = (sp + x0) - x0 = sp
+
        /* If a guest is loaded, panic out of it. */
        stp     x0, x1, [sp, #-16]!
        get_loaded_vcpu x0, x1
@@ -165,6 +177,18 @@ SYM_FUNC_END(__host_hvc)
         * been partially clobbered by __host_enter.
         */
        b       hyp_panic
+
+.L__hyp_sp_overflow\@:
+       /*
+        * Reset SP to the top of the stack, to allow handling the hyp_panic.
+        * This corrupts the stack but is ok, since we won't be attempting
+        * any unwinding here.
+        */
+       ldr_this_cpu    x0, kvm_init_params + NVHE_INIT_STACK_HYP_VA, x1
+       mov     sp, x0
+
+       b       hyp_panic_bad_stack
+       ASM_BUG()
 .endm
 
 .macro invalid_host_el1_vect
index 6410d21..703a5d3 100644 (file)
@@ -347,7 +347,7 @@ int __kvm_vcpu_run(struct kvm_vcpu *vcpu)
        return exit_code;
 }
 
-void __noreturn hyp_panic(void)
+asmlinkage void __noreturn hyp_panic(void)
 {
        u64 spsr = read_sysreg_el2(SYS_SPSR);
        u64 elr = read_sysreg_el2(SYS_ELR);
@@ -369,6 +369,11 @@ void __noreturn hyp_panic(void)
        unreachable();
 }
 
+asmlinkage void __noreturn hyp_panic_bad_stack(void)
+{
+       hyp_panic();
+}
+
 asmlinkage void kvm_unexpected_el2_exception(void)
 {
        return __kvm_unexpected_el2_exception();