x86/sev: Allow #VC exceptions on the VC2 stack
authorJoerg Roedel <jroedel@suse.de>
Thu, 21 Oct 2021 08:08:33 +0000 (10:08 +0200)
committerBorislav Petkov <bp@suse.de>
Thu, 21 Oct 2021 16:29:36 +0000 (18:29 +0200)
When code running on the VC2 stack causes a nested VC exception, the
handler will not handle it as expected but goes again into the error
path.

The result is that the panic() call happening when the VC exception
was raised in an invalid context is called recursively. Fix this by
checking the interrupted stack too and only call panic if it is not
the VC2 stack.

 [ bp: Fixup comment. ]

Fixes: 0786138c78e79 ("x86/sev-es: Add a Runtime #VC Exception Handler")
Reported-by: Xinyang Ge <xing@microsoft.com>
Signed-off-by: Joerg Roedel <jroedel@suse.de>
Signed-off-by: Borislav Petkov <bp@suse.de>
Link: https://lkml.kernel.org/r/20211021080833.30875-3-joro@8bytes.org
arch/x86/kernel/sev.c

index a6895e4..2de1f36 100644 (file)
@@ -1319,13 +1319,26 @@ static __always_inline void vc_forward_exception(struct es_em_ctxt *ctxt)
        }
 }
 
-static __always_inline bool on_vc_fallback_stack(struct pt_regs *regs)
+static __always_inline bool is_vc2_stack(unsigned long sp)
 {
-       unsigned long sp = (unsigned long)regs;
-
        return (sp >= __this_cpu_ist_bottom_va(VC2) && sp < __this_cpu_ist_top_va(VC2));
 }
 
+static __always_inline bool vc_from_invalid_context(struct pt_regs *regs)
+{
+       unsigned long sp, prev_sp;
+
+       sp      = (unsigned long)regs;
+       prev_sp = regs->sp;
+
+       /*
+        * If the code was already executing on the VC2 stack when the #VC
+        * happened, let it proceed to the normal handling routine. This way the
+        * code executing on the VC2 stack can cause #VC exceptions to get handled.
+        */
+       return is_vc2_stack(sp) && !is_vc2_stack(prev_sp);
+}
+
 static bool vc_raw_handle_exception(struct pt_regs *regs, unsigned long error_code)
 {
        struct ghcb_state state;
@@ -1406,7 +1419,7 @@ DEFINE_IDTENTRY_VC_KERNEL(exc_vmm_communication)
         * But keep this here in case the noinstr annotations are violated due
         * to bug elsewhere.
         */
-       if (unlikely(on_vc_fallback_stack(regs))) {
+       if (unlikely(vc_from_invalid_context(regs))) {
                instrumentation_begin();
                panic("Can't handle #VC exception from unsupported context\n");
                instrumentation_end();