Skip to content

Commit 5932ca4

Browse files
committed
KVM: x86: disallow pre-fault for SNP VMs before initialization
KVM_PRE_FAULT_MEMORY for an SNP guest can race with sev_gmem_post_populate() in bad ways. The following sequence for instance can potentially trigger an RMP fault: thread A, sev_gmem_post_populate: called thread B, sev_gmem_prepare: places below 'pfn' in a private state in RMP thread A, sev_gmem_post_populate: *vaddr = kmap_local_pfn(pfn + i); thread A, sev_gmem_post_populate: copy_from_user(vaddr, src + i * PAGE_SIZE, PAGE_SIZE); RMP #PF Fix this by only allowing KVM_PRE_FAULT_MEMORY to run after a guest's initial private memory contents have been finalized via KVM_SEV_SNP_LAUNCH_FINISH. Beyond fixing this issue, it just sort of makes sense to enforce this, since the KVM_PRE_FAULT_MEMORY documentation states: "KVM maps memory as if the vCPU generated a stage-2 read page fault" which sort of implies we should be acting on the same guest state that a vCPU would see post-launch after the initial guest memory is all set up. Co-developed-by: Michael Roth <[email protected]> Signed-off-by: Michael Roth <[email protected]> Signed-off-by: Paolo Bonzini <[email protected]>
1 parent c2adcf0 commit 5932ca4

File tree

6 files changed

+22
-0
lines changed

6 files changed

+22
-0
lines changed

Documentation/virt/kvm/api.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6402,6 +6402,12 @@ for the current vCPU state. KVM maps memory as if the vCPU generated a
64026402
stage-2 read page fault, e.g. faults in memory as needed, but doesn't break
64036403
CoW. However, KVM does not mark any newly created stage-2 PTE as Accessed.
64046404

6405+
In the case of confidential VM types where there is an initial set up of
6406+
private guest memory before the guest is 'finalized'/measured, this ioctl
6407+
should only be issued after completing all the necessary setup to put the
6408+
guest into a 'finalized' state so that the above semantics can be reliably
6409+
ensured.
6410+
64056411
In some cases, multiple vCPUs might share the page tables. In this
64066412
case, the ioctl can be called in parallel.
64076413

arch/x86/include/asm/kvm_host.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1305,6 +1305,7 @@ struct kvm_arch {
13051305
u8 vm_type;
13061306
bool has_private_mem;
13071307
bool has_protected_state;
1308+
bool pre_fault_allowed;
13081309
struct hlist_head mmu_page_hash[KVM_NUM_MMU_PAGES];
13091310
struct list_head active_mmu_pages;
13101311
struct list_head zapped_obsolete_pages;

arch/x86/kvm/mmu/mmu.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4743,6 +4743,9 @@ long kvm_arch_vcpu_pre_fault_memory(struct kvm_vcpu *vcpu,
47434743
u64 end;
47444744
int r;
47454745

4746+
if (!vcpu->kvm->arch.pre_fault_allowed)
4747+
return -EOPNOTSUPP;
4748+
47464749
/*
47474750
* reload is efficient when called repeatedly, so we can do it on
47484751
* every iteration.

arch/x86/kvm/svm/sev.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2549,6 +2549,14 @@ static int snp_launch_finish(struct kvm *kvm, struct kvm_sev_cmd *argp)
25492549
data->gctx_paddr = __psp_pa(sev->snp_context);
25502550
ret = sev_issue_cmd(kvm, SEV_CMD_SNP_LAUNCH_FINISH, data, &argp->error);
25512551

2552+
/*
2553+
* Now that there will be no more SNP_LAUNCH_UPDATE ioctls, private pages
2554+
* can be given to the guest simply by marking the RMP entry as private.
2555+
* This can happen on first access and also with KVM_PRE_FAULT_MEMORY.
2556+
*/
2557+
if (!ret)
2558+
kvm->arch.pre_fault_allowed = true;
2559+
25522560
kfree(id_auth);
25532561

25542562
e_free_id_block:

arch/x86/kvm/svm/svm.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4949,6 +4949,7 @@ static int svm_vm_init(struct kvm *kvm)
49494949
to_kvm_sev_info(kvm)->need_init = true;
49504950

49514951
kvm->arch.has_private_mem = (type == KVM_X86_SNP_VM);
4952+
kvm->arch.pre_fault_allowed = !kvm->arch.has_private_mem;
49524953
}
49534954

49544955
if (!pause_filter_count || !pause_filter_thresh)

arch/x86/kvm/x86.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12646,6 +12646,9 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
1264612646
kvm->arch.vm_type = type;
1264712647
kvm->arch.has_private_mem =
1264812648
(type == KVM_X86_SW_PROTECTED_VM);
12649+
/* Decided by the vendor code for other VM types. */
12650+
kvm->arch.pre_fault_allowed =
12651+
type == KVM_X86_DEFAULT_VM || type == KVM_X86_SW_PROTECTED_VM;
1264912652

1265012653
ret = kvm_page_track_init(kvm);
1265112654
if (ret)

0 commit comments

Comments
 (0)