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

Joerg Roedel
Tue, 28 Apr 2020 15:17:00 -0000

From: Joerg Roedel <jroedel at 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 at 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 at 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