On 7/22/19 12:12 PM, Cfir Cohen wrote: > In addition, it seems that svm_page_enc_status_hc() accepts 'gpa', > 'npages', 'enc' directly from the guest, and so these can take > arbitrary values. A very large 'npages' could lead to an int overflow > in 'gfn_end = gfn_start + npages', making gfn_end < gfn_start. This > could an OOB access in the bitmap. Concrete example: gfn_start = 2, > npages = -1, gfn_end = 2+(-1) = 1, sev_resize_page_enc_bitmap > allocates a bitmap for a single page (new_size=1), __bitmap_set access > offset gfn_end - gfn_start = -1. > Good point. I will add a check for it, something like if (gfn_end <= gfn_start) return -EINVAL; > > On Sun, Jul 21, 2019 at 1:57 PM David Rientjes <rientjes@xxxxxxxxxx> wrote: >> >> On Wed, 10 Jul 2019, Singh, Brijesh wrote: >> >>> diff --git a/Documentation/virtual/kvm/hypercalls.txt b/Documentation/virtual/kvm/hypercalls.txt >>> index da24c138c8d1..94f0611f4d88 100644 >>> --- a/Documentation/virtual/kvm/hypercalls.txt >>> +++ b/Documentation/virtual/kvm/hypercalls.txt >>> @@ -141,3 +141,17 @@ a0 corresponds to the APIC ID in the third argument (a2), bit 1 >>> corresponds to the APIC ID a2+1, and so on. >>> >>> Returns the number of CPUs to which the IPIs were delivered successfully. >>> + >>> +7. KVM_HC_PAGE_ENC_STATUS >>> +------------------------- >>> +Architecture: x86 >>> +Status: active >>> +Purpose: Notify the encryption status changes in guest page table (SEV guest) >>> + >>> +a0: the guest physical address of the start page >>> +a1: the number of pages >>> +a2: encryption attribute >>> + >>> + Where: >>> + * 1: Encryption attribute is set >>> + * 0: Encryption attribute is cleared >>> diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h >>> index 26d1eb83f72a..b463a81dc176 100644 >>> --- a/arch/x86/include/asm/kvm_host.h >>> +++ b/arch/x86/include/asm/kvm_host.h >>> @@ -1199,6 +1199,8 @@ struct kvm_x86_ops { >>> uint16_t (*nested_get_evmcs_version)(struct kvm_vcpu *vcpu); >>> >>> bool (*need_emulation_on_page_fault)(struct kvm_vcpu *vcpu); >>> + int (*page_enc_status_hc)(struct kvm *kvm, unsigned long gpa, >>> + unsigned long sz, unsigned long mode); >>> }; >>> >>> struct kvm_arch_async_pf { >>> diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c >>> index 3089942f6630..431718309359 100644 >>> --- a/arch/x86/kvm/svm.c >>> +++ b/arch/x86/kvm/svm.c >>> @@ -135,6 +135,8 @@ struct kvm_sev_info { >>> int fd; /* SEV device fd */ >>> unsigned long pages_locked; /* Number of pages locked */ >>> struct list_head regions_list; /* List of registered regions */ >>> + unsigned long *page_enc_bmap; >>> + unsigned long page_enc_bmap_size; >>> }; >>> >>> struct kvm_svm { >>> @@ -1910,6 +1912,8 @@ static void sev_vm_destroy(struct kvm *kvm) >>> >>> sev_unbind_asid(kvm, sev->handle); >>> sev_asid_free(kvm); >>> + >>> + kvfree(sev->page_enc_bmap); >>> } >>> >>> static void avic_vm_destroy(struct kvm *kvm) >> >> Adding Cfir who flagged this kvfree(). >> >> Other freeing of sev->page_enc_bmap in this patch also set >> sev->page_enc_bmap_size to 0 and neither set sev->page_enc_bmap to NULL >> after freeing it. >> >> For extra safety, is it possible to sev->page_enc_bmap = NULL anytime the >> bitmap is kvfreed? >> >>> @@ -2084,6 +2088,7 @@ static void avic_set_running(struct kvm_vcpu *vcpu, bool is_run) >>> >>> static void svm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event) >>> { >>> + struct kvm_sev_info *sev = &to_kvm_svm(vcpu->kvm)->sev_info; >>> struct vcpu_svm *svm = to_svm(vcpu); >>> u32 dummy; >>> u32 eax = 1; >>> @@ -2105,6 +2110,12 @@ static void svm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event) >>> >>> if (kvm_vcpu_apicv_active(vcpu) && !init_event) >>> avic_update_vapic_bar(svm, APIC_DEFAULT_PHYS_BASE); >>> + >>> + /* reset the page encryption bitmap */ >>> + if (sev_guest(vcpu->kvm)) { >>> + kvfree(sev->page_enc_bmap); >>> + sev->page_enc_bmap_size = 0; >>> + } >>> } >>> >>> static int avic_init_vcpu(struct vcpu_svm *svm) >> >> What is protecting sev->page_enc_bmap and sev->page_enc_bmap_size in calls >> to svm_vcpu_reset()?