Skip to content

Commit 962e2b6

Browse files
tlendackysean-jc
authored andcommitted
KVM: SVM: Decrypt SEV VMSA in dump_vmcb() if debugging is enabled
An SEV-ES/SEV-SNP VM save area (VMSA) can be decrypted if the guest policy allows debugging. Update the dump_vmcb() routine to output some of the SEV VMSA contents if possible. This can be useful for debug purposes. Signed-off-by: Tom Lendacky <[email protected]> Acked-by: Borislav Petkov (AMD) <[email protected]> Tested-by: Kim Phillips <[email protected]> Link: https://lore.kernel.org/r/ea3b852c295b6f4b200925ed6b6e2c90d9475e71.1742477213.git.thomas.lendacky@amd.com Signed-off-by: Sean Christopherson <[email protected]>
1 parent 309d285 commit 962e2b6

File tree

3 files changed

+122
-0
lines changed

3 files changed

+122
-0
lines changed

arch/x86/kvm/svm/sev.c

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,8 @@ static int sev_launch_start(struct kvm *kvm, struct kvm_sev_cmd *argp)
560560
if (copy_from_user(&params, u64_to_user_ptr(argp->data), sizeof(params)))
561561
return -EFAULT;
562562

563+
sev->policy = params.policy;
564+
563565
memset(&start, 0, sizeof(start));
564566

565567
dh_blob = NULL;
@@ -2199,6 +2201,8 @@ static int snp_launch_start(struct kvm *kvm, struct kvm_sev_cmd *argp)
21992201
if (params.policy & SNP_POLICY_MASK_SINGLE_SOCKET)
22002202
return -EINVAL;
22012203

2204+
sev->policy = params.policy;
2205+
22022206
sev->snp_context = snp_context_create(kvm, argp);
22032207
if (!sev->snp_context)
22042208
return -ENOTTY;
@@ -4922,3 +4926,97 @@ int sev_private_max_mapping_level(struct kvm *kvm, kvm_pfn_t pfn)
49224926

49234927
return level;
49244928
}
4929+
4930+
struct vmcb_save_area *sev_decrypt_vmsa(struct kvm_vcpu *vcpu)
4931+
{
4932+
struct vcpu_svm *svm = to_svm(vcpu);
4933+
struct vmcb_save_area *vmsa;
4934+
struct kvm_sev_info *sev;
4935+
int error = 0;
4936+
int ret;
4937+
4938+
if (!sev_es_guest(vcpu->kvm))
4939+
return NULL;
4940+
4941+
/*
4942+
* If the VMSA has not yet been encrypted, return a pointer to the
4943+
* current un-encrypted VMSA.
4944+
*/
4945+
if (!vcpu->arch.guest_state_protected)
4946+
return (struct vmcb_save_area *)svm->sev_es.vmsa;
4947+
4948+
sev = to_kvm_sev_info(vcpu->kvm);
4949+
4950+
/* Check if the SEV policy allows debugging */
4951+
if (sev_snp_guest(vcpu->kvm)) {
4952+
if (!(sev->policy & SNP_POLICY_DEBUG))
4953+
return NULL;
4954+
} else {
4955+
if (sev->policy & SEV_POLICY_NODBG)
4956+
return NULL;
4957+
}
4958+
4959+
if (sev_snp_guest(vcpu->kvm)) {
4960+
struct sev_data_snp_dbg dbg = {0};
4961+
4962+
vmsa = snp_alloc_firmware_page(__GFP_ZERO);
4963+
if (!vmsa)
4964+
return NULL;
4965+
4966+
dbg.gctx_paddr = __psp_pa(sev->snp_context);
4967+
dbg.src_addr = svm->vmcb->control.vmsa_pa;
4968+
dbg.dst_addr = __psp_pa(vmsa);
4969+
4970+
ret = sev_do_cmd(SEV_CMD_SNP_DBG_DECRYPT, &dbg, &error);
4971+
4972+
/*
4973+
* Return the target page to a hypervisor page no matter what.
4974+
* If this fails, the page can't be used, so leak it and don't
4975+
* try to use it.
4976+
*/
4977+
if (snp_page_reclaim(vcpu->kvm, PHYS_PFN(__pa(vmsa))))
4978+
return NULL;
4979+
4980+
if (ret) {
4981+
pr_err("SEV: SNP_DBG_DECRYPT failed ret=%d, fw_error=%d (%#x)\n",
4982+
ret, error, error);
4983+
free_page((unsigned long)vmsa);
4984+
4985+
return NULL;
4986+
}
4987+
} else {
4988+
struct sev_data_dbg dbg = {0};
4989+
struct page *vmsa_page;
4990+
4991+
vmsa_page = alloc_page(GFP_KERNEL);
4992+
if (!vmsa_page)
4993+
return NULL;
4994+
4995+
vmsa = page_address(vmsa_page);
4996+
4997+
dbg.handle = sev->handle;
4998+
dbg.src_addr = svm->vmcb->control.vmsa_pa;
4999+
dbg.dst_addr = __psp_pa(vmsa);
5000+
dbg.len = PAGE_SIZE;
5001+
5002+
ret = sev_do_cmd(SEV_CMD_DBG_DECRYPT, &dbg, &error);
5003+
if (ret) {
5004+
pr_err("SEV: SEV_CMD_DBG_DECRYPT failed ret=%d, fw_error=%d (0x%x)\n",
5005+
ret, error, error);
5006+
__free_page(vmsa_page);
5007+
5008+
return NULL;
5009+
}
5010+
}
5011+
5012+
return vmsa;
5013+
}
5014+
5015+
void sev_free_decrypted_vmsa(struct kvm_vcpu *vcpu, struct vmcb_save_area *vmsa)
5016+
{
5017+
/* If the VMSA has not yet been encrypted, nothing was allocated */
5018+
if (!vcpu->arch.guest_state_protected || !vmsa)
5019+
return;
5020+
5021+
free_page((unsigned long)vmsa);
5022+
}

arch/x86/kvm/svm/svm.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3442,6 +3442,15 @@ static void dump_vmcb(struct kvm_vcpu *vcpu)
34423442
pr_err("%-20s%016llx\n", "avic_logical_id:", control->avic_logical_id);
34433443
pr_err("%-20s%016llx\n", "avic_physical_id:", control->avic_physical_id);
34443444
pr_err("%-20s%016llx\n", "vmsa_pa:", control->vmsa_pa);
3445+
3446+
if (sev_es_guest(vcpu->kvm)) {
3447+
save = sev_decrypt_vmsa(vcpu);
3448+
if (!save)
3449+
goto no_vmsa;
3450+
3451+
save01 = save;
3452+
}
3453+
34453454
pr_err("VMCB State Save Area:\n");
34463455
pr_err("%-5s s: %04x a: %04x l: %08x b: %016llx\n",
34473456
"es:",
@@ -3512,6 +3521,10 @@ static void dump_vmcb(struct kvm_vcpu *vcpu)
35123521
pr_err("%-15s %016llx %-13s %016llx\n",
35133522
"excp_from:", save->last_excp_from,
35143523
"excp_to:", save->last_excp_to);
3524+
3525+
no_vmsa:
3526+
if (sev_es_guest(vcpu->kvm))
3527+
sev_free_decrypted_vmsa(vcpu, save);
35153528
}
35163529

35173530
static bool svm_check_exit_valid(u64 exit_code)

arch/x86/kvm/svm/svm.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ struct kvm_sev_info {
9898
unsigned int asid; /* ASID used for this guest */
9999
unsigned int handle; /* SEV firmware handle */
100100
int fd; /* SEV device fd */
101+
unsigned long policy;
101102
unsigned long pages_locked; /* Number of pages locked */
102103
struct list_head regions_list; /* List of registered regions */
103104
u64 ap_jump_table; /* SEV-ES AP Jump Table address */
@@ -114,6 +115,9 @@ struct kvm_sev_info {
114115
struct mutex guest_req_mutex; /* Must acquire before using bounce buffers */
115116
};
116117

118+
#define SEV_POLICY_NODBG BIT_ULL(0)
119+
#define SNP_POLICY_DEBUG BIT_ULL(19)
120+
117121
struct kvm_svm {
118122
struct kvm kvm;
119123

@@ -783,6 +787,8 @@ void sev_snp_init_protected_guest_state(struct kvm_vcpu *vcpu);
783787
int sev_gmem_prepare(struct kvm *kvm, kvm_pfn_t pfn, gfn_t gfn, int max_order);
784788
void sev_gmem_invalidate(kvm_pfn_t start, kvm_pfn_t end);
785789
int sev_private_max_mapping_level(struct kvm *kvm, kvm_pfn_t pfn);
790+
struct vmcb_save_area *sev_decrypt_vmsa(struct kvm_vcpu *vcpu);
791+
void sev_free_decrypted_vmsa(struct kvm_vcpu *vcpu, struct vmcb_save_area *vmsa);
786792
#else
787793
static inline struct page *snp_safe_alloc_page_node(int node, gfp_t gfp)
788794
{
@@ -814,6 +820,11 @@ static inline int sev_private_max_mapping_level(struct kvm *kvm, kvm_pfn_t pfn)
814820
return 0;
815821
}
816822

823+
static inline struct vmcb_save_area *sev_decrypt_vmsa(struct kvm_vcpu *vcpu)
824+
{
825+
return NULL;
826+
}
827+
static inline void sev_free_decrypted_vmsa(struct kvm_vcpu *vcpu, struct vmcb_save_area *vmsa) {}
817828
#endif
818829

819830
/* vmenter.S */

0 commit comments

Comments
 (0)