Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 15 Sep 2020 20:22:50 +0000 (UTC)
From:      Konstantin Belousov <kib@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r365766 - head/sys/amd64/vmm/amd
Message-ID:  <202009152022.08FKMoV2096689@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kib
Date: Tue Sep 15 20:22:50 2020
New Revision: 365766
URL: https://svnweb.freebsd.org/changeset/base/365766

Log:
  bhyve: intercept AMD SVM instructions.
  
  Intercept and report #UD to VM on SVM/AMD in case VM tried to execute an
  SVM instruction.  Otherwise, SVM allows execution of them, and instructions
  operate on host physical addresses despite being executed in guest mode.
  
  Reported by:	Maxime Villard <max@m00nbsd.net>
  admbug:	972
  CVE:	CVE-2020-7467
  Reviewed by:	grehan, markj
  Differential revision:	https://reviews.freebsd.org/D26313

Modified:
  head/sys/amd64/vmm/amd/svm.c
  head/sys/amd64/vmm/amd/vmcb.h

Modified: head/sys/amd64/vmm/amd/svm.c
==============================================================================
--- head/sys/amd64/vmm/amd/svm.c	Tue Sep 15 19:23:42 2020	(r365765)
+++ head/sys/amd64/vmm/amd/svm.c	Tue Sep 15 20:22:50 2020	(r365766)
@@ -488,11 +488,24 @@ vmcb_init(struct svm_softc *sc, int vcpu, uint64_t iop
 	svm_enable_intercept(sc, vcpu, VMCB_CTRL1_INTCPT, VMCB_INTCPT_SHUTDOWN);
 	svm_enable_intercept(sc, vcpu, VMCB_CTRL1_INTCPT,
 	    VMCB_INTCPT_FERR_FREEZE);
+	svm_enable_intercept(sc, vcpu, VMCB_CTRL1_INTCPT, VMCB_INTCPT_INVD);
+	svm_enable_intercept(sc, vcpu, VMCB_CTRL1_INTCPT, VMCB_INTCPT_INVLPGA);
 
 	svm_enable_intercept(sc, vcpu, VMCB_CTRL2_INTCPT, VMCB_INTCPT_MONITOR);
 	svm_enable_intercept(sc, vcpu, VMCB_CTRL2_INTCPT, VMCB_INTCPT_MWAIT);
 
 	/*
+	 * Intercept SVM instructions since AMD enables them in guests otherwise.
+	 * Non-intercepted VMMCALL causes #UD, skip it.
+	 */
+	svm_enable_intercept(sc, vcpu, VMCB_CTRL2_INTCPT, VMCB_INTCPT_VMLOAD);
+	svm_enable_intercept(sc, vcpu, VMCB_CTRL2_INTCPT, VMCB_INTCPT_VMSAVE);
+	svm_enable_intercept(sc, vcpu, VMCB_CTRL2_INTCPT, VMCB_INTCPT_STGI);
+	svm_enable_intercept(sc, vcpu, VMCB_CTRL2_INTCPT, VMCB_INTCPT_CLGI);
+	svm_enable_intercept(sc, vcpu, VMCB_CTRL2_INTCPT, VMCB_INTCPT_SKINIT);
+	svm_enable_intercept(sc, vcpu, VMCB_CTRL2_INTCPT, VMCB_INTCPT_ICEBP);
+
+	/*
 	 * From section "Canonicalization and Consistency Checks" in APMv2
 	 * the VMRUN intercept bit must be set to pass the consistency check.
 	 */
@@ -1236,43 +1249,45 @@ emulate_rdmsr(struct svm_softc *sc, int vcpu, u_int nu
 static const char *
 exit_reason_to_str(uint64_t reason)
 {
+	int i;
 	static char reasonbuf[32];
+	static const struct {
+		int reason;
+		const char *str;
+	} reasons[] = {
+		{ .reason = VMCB_EXIT_INVALID,	.str = "invalvmcb" },
+		{ .reason = VMCB_EXIT_SHUTDOWN,	.str = "shutdown" },
+		{ .reason = VMCB_EXIT_NPF, 	.str = "nptfault" },
+		{ .reason = VMCB_EXIT_PAUSE,	.str = "pause" },
+		{ .reason = VMCB_EXIT_HLT,	.str = "hlt" },
+		{ .reason = VMCB_EXIT_CPUID,	.str = "cpuid" },
+		{ .reason = VMCB_EXIT_IO,	.str = "inout" },
+		{ .reason = VMCB_EXIT_MC,	.str = "mchk" },
+		{ .reason = VMCB_EXIT_INTR,	.str = "extintr" },
+		{ .reason = VMCB_EXIT_NMI,	.str = "nmi" },
+		{ .reason = VMCB_EXIT_VINTR,	.str = "vintr" },
+		{ .reason = VMCB_EXIT_MSR,	.str = "msr" },
+		{ .reason = VMCB_EXIT_IRET,	.str = "iret" },
+		{ .reason = VMCB_EXIT_MONITOR,	.str = "monitor" },
+		{ .reason = VMCB_EXIT_MWAIT,	.str = "mwait" },
+		{ .reason = VMCB_EXIT_VMRUN,	.str = "vmrun" },
+		{ .reason = VMCB_EXIT_VMMCALL,	.str = "vmmcall" },
+		{ .reason = VMCB_EXIT_VMLOAD,	.str = "vmload" },
+		{ .reason = VMCB_EXIT_VMSAVE,	.str = "vmsave" },
+		{ .reason = VMCB_EXIT_STGI,	.str = "stgi" },
+		{ .reason = VMCB_EXIT_CLGI,	.str = "clgi" },
+		{ .reason = VMCB_EXIT_SKINIT,	.str = "skinit" },
+		{ .reason = VMCB_EXIT_ICEBP,	.str = "icebp" },
+		{ .reason = VMCB_EXIT_INVD,	.str = "invd" },
+		{ .reason = VMCB_EXIT_INVLPGA,	.str = "invlpga" },
+	};
 
-	switch (reason) {
-	case VMCB_EXIT_INVALID:
-		return ("invalvmcb");
-	case VMCB_EXIT_SHUTDOWN:
-		return ("shutdown");
-	case VMCB_EXIT_NPF:
-		return ("nptfault");
-	case VMCB_EXIT_PAUSE:
-		return ("pause");
-	case VMCB_EXIT_HLT:
-		return ("hlt");
-	case VMCB_EXIT_CPUID:
-		return ("cpuid");
-	case VMCB_EXIT_IO:
-		return ("inout");
-	case VMCB_EXIT_MC:
-		return ("mchk");
-	case VMCB_EXIT_INTR:
-		return ("extintr");
-	case VMCB_EXIT_NMI:
-		return ("nmi");
-	case VMCB_EXIT_VINTR:
-		return ("vintr");
-	case VMCB_EXIT_MSR:
-		return ("msr");
-	case VMCB_EXIT_IRET:
-		return ("iret");
-	case VMCB_EXIT_MONITOR:
-		return ("monitor");
-	case VMCB_EXIT_MWAIT:
-		return ("mwait");
-	default:
-		snprintf(reasonbuf, sizeof(reasonbuf), "%#lx", reason);
-		return (reasonbuf);
+	for (i = 0; i < nitems(reasons); i++) {
+		if (reasons[i].reason == reason)
+			return (reasons[i].str);
 	}
+	snprintf(reasonbuf, sizeof(reasonbuf), "%#lx", reason);
+	return (reasonbuf);
 }
 #endif	/* KTR */
 
@@ -1523,6 +1538,20 @@ svm_vmexit(struct svm_softc *svm_sc, int vcpu, struct 
 		break;
 	case VMCB_EXIT_MWAIT:
 		vmexit->exitcode = VM_EXITCODE_MWAIT;
+		break;
+	case VMCB_EXIT_SHUTDOWN:
+	case VMCB_EXIT_VMRUN:
+	case VMCB_EXIT_VMMCALL:
+	case VMCB_EXIT_VMLOAD:
+	case VMCB_EXIT_VMSAVE:
+	case VMCB_EXIT_STGI:
+	case VMCB_EXIT_CLGI:
+	case VMCB_EXIT_SKINIT:
+	case VMCB_EXIT_ICEBP:
+	case VMCB_EXIT_INVD:
+	case VMCB_EXIT_INVLPGA:
+		vm_inject_ud(svm_sc->vm, vcpu);
+		handled = 1;
 		break;
 	default:
 		vmm_stat_incr(svm_sc->vm, vcpu, VMEXIT_UNKNOWN, 1);

Modified: head/sys/amd64/vmm/amd/vmcb.h
==============================================================================
--- head/sys/amd64/vmm/amd/vmcb.h	Tue Sep 15 19:23:42 2020	(r365765)
+++ head/sys/amd64/vmm/amd/vmcb.h	Tue Sep 15 20:22:50 2020	(r365766)
@@ -71,8 +71,8 @@
 #define	VMCB_INTCPT_INVD		BIT(22)
 #define	VMCB_INTCPT_PAUSE		BIT(23)
 #define	VMCB_INTCPT_HLT			BIT(24)
-#define	VMCB_INTCPT_INVPG		BIT(25)
-#define	VMCB_INTCPT_INVPGA		BIT(26)
+#define	VMCB_INTCPT_INVLPG		BIT(25)
+#define	VMCB_INTCPT_INVLPGA		BIT(26)
 #define	VMCB_INTCPT_IO			BIT(27)
 #define	VMCB_INTCPT_MSR			BIT(28)
 #define	VMCB_INTCPT_TASK_SWITCH		BIT(29)
@@ -134,12 +134,21 @@
 #define	VMCB_EXIT_POPF			0x71
 #define	VMCB_EXIT_CPUID			0x72
 #define	VMCB_EXIT_IRET			0x74
+#define	VMCB_EXIT_INVD			0x76
 #define	VMCB_EXIT_PAUSE			0x77
 #define	VMCB_EXIT_HLT			0x78
+#define	VMCB_EXIT_INVLPGA		0x7A
 #define	VMCB_EXIT_IO			0x7B
 #define	VMCB_EXIT_MSR			0x7C
 #define	VMCB_EXIT_SHUTDOWN		0x7F
+#define	VMCB_EXIT_VMRUN			0x80
+#define	VMCB_EXIT_VMMCALL		0x81
+#define	VMCB_EXIT_VMLOAD		0x82
 #define	VMCB_EXIT_VMSAVE		0x83
+#define	VMCB_EXIT_STGI			0x84
+#define	VMCB_EXIT_CLGI			0x85
+#define	VMCB_EXIT_SKINIT		0x86
+#define	VMCB_EXIT_ICEBP			0x88
 #define	VMCB_EXIT_MONITOR		0x8A
 #define	VMCB_EXIT_MWAIT			0x8B
 #define	VMCB_EXIT_NPF			0x400



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202009152022.08FKMoV2096689>