Il 14/01/2014 07:24, Li Zefan ha scritto:
> From: Andy Honig <[email protected]>
> 
> commit fda4e2e85589191b123d31cdc21fd33ee70f50fd upstream.
> 
> In kvm_lapic_sync_from_vapic and kvm_lapic_sync_to_vapic there is the
> potential to corrupt kernel memory if userspace provides an address that
> is at the end of a page.  This patches concerts those functions to use
> kvm_write_guest_cached and kvm_read_guest_cached.  It also checks the
> vapic_address specified by userspace during ioctl processing and returns
> an error to userspace if the address is not a valid GPA.
> 
> This is generally not guest triggerable, because the required write is
> done by firmware that runs before the guest.  Also, it only affects AMD
> processors and oldish Intel that do not have the FlexPriority feature
> (unless you disable FlexPriority, of course; then newer processors are
> also affected).
> 
> Fixes: b93463aa59d6 ('KVM: Accelerated apic support')
> 
> Reported-by: Andrew Honig <[email protected]>
> Signed-off-by: Andrew Honig <[email protected]>
> Signed-off-by: Paolo Bonzini <[email protected]>
> [ lizf: backported to 3.4: based on Paolo's backport hints for <3.10 ]
> Signed-off-by: Li Zefan <[email protected]>

Reviewed-by: Paolo Bonzini <[email protected]>

Thanks Li---just gotten back from vacation.

Paolo

> ---
> 
> Paolo's backport hints is here:
> 
> http://lkml.org/lkml/2013/12/16/176
> 
> ---
>  arch/x86/kvm/lapic.c | 24 ++++++++++++++----------
>  arch/x86/kvm/lapic.h |  4 ++--
>  arch/x86/kvm/x86.c   | 33 +--------------------------------
>  3 files changed, 17 insertions(+), 44 deletions(-)
> 
> diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
> index 8584322..2bf03a9 100644
> --- a/arch/x86/kvm/lapic.c
> +++ b/arch/x86/kvm/lapic.c
> @@ -1278,14 +1278,12 @@ void __kvm_migrate_apic_timer(struct kvm_vcpu *vcpu)
>  void kvm_lapic_sync_from_vapic(struct kvm_vcpu *vcpu)
>  {
>       u32 data;
> -     void *vapic;
>  
>       if (!irqchip_in_kernel(vcpu->kvm) || !vcpu->arch.apic->vapic_addr)
>               return;
>  
> -     vapic = kmap_atomic(vcpu->arch.apic->vapic_page);
> -     data = *(u32 *)(vapic + offset_in_page(vcpu->arch.apic->vapic_addr));
> -     kunmap_atomic(vapic);
> +     kvm_read_guest_cached(vcpu->kvm, &vcpu->arch.apic->vapic_cache, &data,
> +                           sizeof(u32));
>  
>       apic_set_tpr(vcpu->arch.apic, data & 0xff);
>  }
> @@ -1295,7 +1293,6 @@ void kvm_lapic_sync_to_vapic(struct kvm_vcpu *vcpu)
>       u32 data, tpr;
>       int max_irr, max_isr;
>       struct kvm_lapic *apic;
> -     void *vapic;
>  
>       if (!irqchip_in_kernel(vcpu->kvm) || !vcpu->arch.apic->vapic_addr)
>               return;
> @@ -1310,17 +1307,24 @@ void kvm_lapic_sync_to_vapic(struct kvm_vcpu *vcpu)
>               max_isr = 0;
>       data = (tpr & 0xff) | ((max_isr & 0xf0) << 8) | (max_irr << 24);
>  
> -     vapic = kmap_atomic(vcpu->arch.apic->vapic_page);
> -     *(u32 *)(vapic + offset_in_page(vcpu->arch.apic->vapic_addr)) = data;
> -     kunmap_atomic(vapic);
> +     kvm_write_guest_cached(vcpu->kvm, &vcpu->arch.apic->vapic_cache, &data,
> +                            sizeof(u32));
>  }
>  
> -void kvm_lapic_set_vapic_addr(struct kvm_vcpu *vcpu, gpa_t vapic_addr)
> +int kvm_lapic_set_vapic_addr(struct kvm_vcpu *vcpu, gpa_t vapic_addr)
>  {
>       if (!irqchip_in_kernel(vcpu->kvm))
> -             return;
> +             return -EINVAL;
> +
> +     if (vapic_addr) {
> +             if (kvm_gfn_to_hva_cache_init(vcpu->kvm,
> +                                     &vcpu->arch.apic->vapic_cache,
> +                                     vapic_addr, sizeof(u32)))
> +                     return -EINVAL;
> +       }
>  
>       vcpu->arch.apic->vapic_addr = vapic_addr;
> +     return 0;
>  }
>  
>  int kvm_x2apic_msr_write(struct kvm_vcpu *vcpu, u32 msr, u64 data)
> diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h
> index 6f4ce25..6aec071 100644
> --- a/arch/x86/kvm/lapic.h
> +++ b/arch/x86/kvm/lapic.h
> @@ -15,7 +15,7 @@ struct kvm_lapic {
>       bool irr_pending;
>       void *regs;
>       gpa_t vapic_addr;
> -     struct page *vapic_page;
> +     struct gfn_to_hva_cache vapic_cache;
>  };
>  int kvm_create_lapic(struct kvm_vcpu *vcpu);
>  void kvm_free_lapic(struct kvm_vcpu *vcpu);
> @@ -46,7 +46,7 @@ int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu);
>  u64 kvm_get_lapic_tscdeadline_msr(struct kvm_vcpu *vcpu);
>  void kvm_set_lapic_tscdeadline_msr(struct kvm_vcpu *vcpu, u64 data);
>  
> -void kvm_lapic_set_vapic_addr(struct kvm_vcpu *vcpu, gpa_t vapic_addr);
> +int kvm_lapic_set_vapic_addr(struct kvm_vcpu *vcpu, gpa_t vapic_addr);
>  void kvm_lapic_sync_from_vapic(struct kvm_vcpu *vcpu);
>  void kvm_lapic_sync_to_vapic(struct kvm_vcpu *vcpu);
>  
> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> index 3663e0b..4b1be29 100644
> --- a/arch/x86/kvm/x86.c
> +++ b/arch/x86/kvm/x86.c
> @@ -2728,8 +2728,7 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
>               r = -EFAULT;
>               if (copy_from_user(&va, argp, sizeof va))
>                       goto out;
> -             r = 0;
> -             kvm_lapic_set_vapic_addr(vcpu, va.vapic_addr);
> +             r = kvm_lapic_set_vapic_addr(vcpu, va.vapic_addr);
>               break;
>       }
>       case KVM_X86_SETUP_MCE: {
> @@ -5075,33 +5074,6 @@ static void post_kvm_run_save(struct kvm_vcpu *vcpu)
>                       !kvm_event_needs_reinjection(vcpu);
>  }
>  
> -static void vapic_enter(struct kvm_vcpu *vcpu)
> -{
> -     struct kvm_lapic *apic = vcpu->arch.apic;
> -     struct page *page;
> -
> -     if (!apic || !apic->vapic_addr)
> -             return;
> -
> -     page = gfn_to_page(vcpu->kvm, apic->vapic_addr >> PAGE_SHIFT);
> -
> -     vcpu->arch.apic->vapic_page = page;
> -}
> -
> -static void vapic_exit(struct kvm_vcpu *vcpu)
> -{
> -     struct kvm_lapic *apic = vcpu->arch.apic;
> -     int idx;
> -
> -     if (!apic || !apic->vapic_addr)
> -             return;
> -
> -     idx = srcu_read_lock(&vcpu->kvm->srcu);
> -     kvm_release_page_dirty(apic->vapic_page);
> -     mark_page_dirty(vcpu->kvm, apic->vapic_addr >> PAGE_SHIFT);
> -     srcu_read_unlock(&vcpu->kvm->srcu, idx);
> -}
> -
>  static void update_cr8_intercept(struct kvm_vcpu *vcpu)
>  {
>       int max_irr, tpr;
> @@ -5385,7 +5357,6 @@ static int __vcpu_run(struct kvm_vcpu *vcpu)
>       }
>  
>       vcpu->srcu_idx = srcu_read_lock(&kvm->srcu);
> -     vapic_enter(vcpu);
>  
>       r = 1;
>       while (r > 0) {
> @@ -5442,8 +5413,6 @@ static int __vcpu_run(struct kvm_vcpu *vcpu)
>  
>       srcu_read_unlock(&kvm->srcu, vcpu->srcu_idx);
>  
> -     vapic_exit(vcpu);
> -
>       return r;
>  }
>  
> 

--
To unsubscribe from this list: send the line "unsubscribe stable" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to