Il 14/01/2014 07:24, Li Zefan ha scritto: > From: Andy Honig <ahonig@xxxxxxxxxx> > > 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 <ahonig@xxxxxxxxxx> > Signed-off-by: Andrew Honig <ahonig@xxxxxxxxxx> > Signed-off-by: Paolo Bonzini <pbonzini@xxxxxxxxxx> > [ lizf: backported to 3.4: based on Paolo's backport hints for <3.10 ] > Signed-off-by: Li Zefan <lizefan@xxxxxxxxxx> Reviewed-by: Paolo Bonzini <pbonzini@xxxxxxxxxx> 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 majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html