x86/sev: Improve handling of writes to intercepted TSC MSRs
authorNikunj A Dadhania <nikunj@amd.com>
Tue, 22 Jul 2025 07:48:53 +0000 (13:18 +0530)
committerBorislav Petkov (AMD) <bp@alien8.de>
Tue, 12 Aug 2025 10:33:58 +0000 (12:33 +0200)
Currently, when a Secure TSC enabled SNP guest attempts to write to the
intercepted GUEST_TSC_FREQ MSR (a read-only MSR), the guest kernel response
incorrectly implies a VMM configuration error, when in fact it is the usual
VMM configuration to intercept writes to read-only MSRs, unless explicitly
documented.

Modify the intercepted TSC MSR #VC handling:
* Write to GUEST_TSC_FREQ will generate a #GP instead of terminating the
  guest
* Write to MSR_IA32_TSC will generate a #GP instead of silently ignoring it

However, continue to terminate the guest when reading from intercepted
GUEST_TSC_FREQ MSR with Secure TSC enabled, as intercepted reads indicate an
improper VMM configuration for Secure TSC enabled SNP guests.

  [ bp: simplify comment. ]

Fixes: 38cc6495cdec ("x86/sev: Prevent GUEST_TSC_FREQ MSR interception for Secure TSC enabled guests")
Suggested-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Nikunj A Dadhania <nikunj@amd.com>
Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
Reviewed-by: Tom Lendacky <thomas.lendacky@amd.com>
Link: https://lore.kernel.org/20250722074853.22253-1-nikunj@amd.com
arch/x86/coco/sev/vc-handle.c

index faf1fce89ed478753bbc62cf6a1da1c8c6b65f42..c3b4acbde0d8c6a8b7b254346c980baaf39f20bd 100644 (file)
@@ -371,29 +371,30 @@ static enum es_result __vc_handle_msr_caa(struct pt_regs *regs, bool write)
  * executing with Secure TSC enabled, so special handling is required for
  * accesses of MSR_IA32_TSC and MSR_AMD64_GUEST_TSC_FREQ.
  */
-static enum es_result __vc_handle_secure_tsc_msrs(struct pt_regs *regs, bool write)
+static enum es_result __vc_handle_secure_tsc_msrs(struct es_em_ctxt *ctxt, bool write)
 {
+       struct pt_regs *regs = ctxt->regs;
        u64 tsc;
 
        /*
-        * GUEST_TSC_FREQ should not be intercepted when Secure TSC is enabled.
-        * Terminate the SNP guest when the interception is enabled.
+        * Writing to MSR_IA32_TSC can cause subsequent reads of the TSC to
+        * return undefined values, and GUEST_TSC_FREQ is read-only. Generate
+        * a #GP on all writes.
         */
-       if (regs->cx == MSR_AMD64_GUEST_TSC_FREQ)
-               return ES_VMM_ERROR;
+       if (write) {
+               ctxt->fi.vector = X86_TRAP_GP;
+               ctxt->fi.error_code = 0;
+               return ES_EXCEPTION;
+       }
 
        /*
-        * Writes: Writing to MSR_IA32_TSC can cause subsequent reads of the TSC
-        *         to return undefined values, so ignore all writes.
-        *
-        * Reads: Reads of MSR_IA32_TSC should return the current TSC value, use
-        *        the value returned by rdtsc_ordered().
+        * GUEST_TSC_FREQ read should not be intercepted when Secure TSC is
+        * enabled. Terminate the guest if a read is attempted.
         */
-       if (write) {
-               WARN_ONCE(1, "TSC MSR writes are verboten!\n");
-               return ES_OK;
-       }
+       if (regs->cx == MSR_AMD64_GUEST_TSC_FREQ)
+               return ES_VMM_ERROR;
 
+       /* Reads of MSR_IA32_TSC should return the current TSC value. */
        tsc = rdtsc_ordered();
        regs->ax = lower_32_bits(tsc);
        regs->dx = upper_32_bits(tsc);
@@ -416,7 +417,7 @@ static enum es_result vc_handle_msr(struct ghcb *ghcb, struct es_em_ctxt *ctxt)
        case MSR_IA32_TSC:
        case MSR_AMD64_GUEST_TSC_FREQ:
                if (sev_status & MSR_AMD64_SNP_SECURE_TSC)
-                       return __vc_handle_secure_tsc_msrs(regs, write);
+                       return __vc_handle_secure_tsc_msrs(ctxt, write);
                break;
        default:
                break;