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 <m...@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
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to