[PATCH v3 50/75] x86/sev-es: Do not crash on #VC exceptions from user-space

Joerg Roedel
2020-04-28T15:17:00Z

From: Joerg Roedel <jroedel@suse.de>

Send SIGBUS to the user-space process that caused the #VC exception
instead of killing the machine. Also ratelimit the error messages so
that user-space can't flood the kernel log and add a prefix the the
messages printed for SEV-ES.

Signed-off-by: Joerg Roedel <jroedel@suse.de>
---
arch/x86/kernel/sev-es.c | 40 +++++++++++++++++++++++++++++-----------
1 file changed, 29 insertions(+), 11 deletions(-)

diff --git a/arch/x86/kernel/sev-es.c b/arch/x86/kernel/sev-es.c
index c2223c2a28c2..f4ce3b475464 100644
--- a/arch/x86/kernel/sev-es.c
+++ b/arch/x86/kernel/sev-es.c
@@ -7,6 +7,8 @@
* Author: Joerg Roedel <jroedel@suse.de>
*/

+#define pr_fmt(fmt) "SEV-ES: " fmt
+
#include <linux/sched/debug.h> /* For show_regs() */
#include <linux/percpu-defs.h>
#include <linux/mem_encrypt.h>
@@ -468,7 +470,7 @@ static void vc_forward_exception(struct es_em_ctxt *ctxt)
do_invalid_op(ctxt->regs, 0);
break;
default:
- pr_emerg("ERROR: Unsupported exception in #VC instruction emulation - can't continue\n");
+ pr_emerg("Unsupported exception in #VC instruction emulation - can't continue\n");
BUG();
}
}
@@ -516,16 +518,16 @@ dotraplinkage void do_vmm_communication(struct pt_regs *regs,
vc_finish_insn(&ctxt);
break;
case ES_UNSUPPORTED:
- pr_emerg("PANIC: Unsupported exit-code 0x%02lx in early #VC exception (IP: 0x%lx)\n",
- exit_code, regs->ip);
+ pr_err_ratelimited("Unsupported exit-code 0x%02lx in early #VC exception (IP: 0x%lx)\n",
+ exit_code, regs->ip);
goto fail;
case ES_VMM_ERROR:
- pr_emerg("PANIC: Failure in communication with VMM (exit-code 0x%02lx IP: 0x%lx)\n",
- exit_code, regs->ip);
+ pr_err_ratelimited("Failure in communication with VMM (exit-code 0x%02lx IP: 0x%lx)\n",
+ exit_code, regs->ip);
goto fail;
case ES_DECODE_FAILED:
- pr_emerg("PANIC: Failed to decode instruction (exit-code 0x%02lx IP: 0x%lx)\n",
- exit_code, regs->ip);
+ pr_err_ratelimited("Failed to decode instruction (exit-code 0x%02lx IP: 0x%lx)\n",
+ exit_code, regs->ip);
goto fail;
case ES_EXCEPTION:
vc_forward_exception(&ctxt);
@@ -534,7 +536,7 @@ dotraplinkage void do_vmm_communication(struct pt_regs *regs,
/* Nothing to do */
break;
default:
- pr_emerg("PANIC: Unknown result in %s():%d\n", __func__, result);
+ pr_emerg("Unknown result in %s():%d\n", __func__, result);
/*
* Emulating the instruction which caused the #VC exception
* failed - can't continue so print debug information
@@ -545,10 +547,26 @@ dotraplinkage void do_vmm_communication(struct pt_regs *regs,
return;

fail:
- show_regs(regs);
+ if (user_mode(regs)) {
+ /*
+ * Do not kill the machine if user-space triggered the
+ * exception. Send SIGBUS instead and let user-space deal with
+ * it.
+ */
+ force_sig_fault(SIGBUS, BUS_OBJERR, (void __user *)0);
+ } else {
+ pr_emerg("PANIC: Unhandled #VC exception in kernel space (result=%d)\n",
+ result);

- while (true)
- halt();
+ /* Show some debug info */
+ show_regs(regs);
+
+ /* Ask hypervisor to sev_es_terminate */
+ sev_es_terminate(GHCB_SEV_ES_REASON_GENERAL_REQUEST);
+
+ /* If that fails and we get here - just panic */
+ panic("Returned from Terminate-Request to Hypervisor\n");
+ }
}

bool __init vc_boot_ghcb(struct pt_regs *regs)
--
2.17.1