Commit 54fb723c authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm

Pull kvm fixes from Paolo Bonzini:
 "Four security fixes for KVM on x86.  Thanks to Andrew Honig and Lars
  Bull from Google for reporting them"

* tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm:
  KVM: x86: fix guest-initiated crash with x2apic (CVE-2013-6376)
  KVM: x86: Convert vapic synchronization to _cached functions (CVE-2013-6368)
  KVM: x86: Fix potential divide by 0 in lapic (CVE-2013-6367)
  KVM: Improve create VCPU parameter (CVE-2013-4587)
parents ea1e61cb 17d68b76
...@@ -143,6 +143,8 @@ static inline int kvm_apic_id(struct kvm_lapic *apic) ...@@ -143,6 +143,8 @@ static inline int kvm_apic_id(struct kvm_lapic *apic)
return (kvm_apic_get_reg(apic, APIC_ID) >> 24) & 0xff; return (kvm_apic_get_reg(apic, APIC_ID) >> 24) & 0xff;
} }
#define KVM_X2APIC_CID_BITS 0
static void recalculate_apic_map(struct kvm *kvm) static void recalculate_apic_map(struct kvm *kvm)
{ {
struct kvm_apic_map *new, *old = NULL; struct kvm_apic_map *new, *old = NULL;
...@@ -180,7 +182,8 @@ static void recalculate_apic_map(struct kvm *kvm) ...@@ -180,7 +182,8 @@ static void recalculate_apic_map(struct kvm *kvm)
if (apic_x2apic_mode(apic)) { if (apic_x2apic_mode(apic)) {
new->ldr_bits = 32; new->ldr_bits = 32;
new->cid_shift = 16; new->cid_shift = 16;
new->cid_mask = new->lid_mask = 0xffff; new->cid_mask = (1 << KVM_X2APIC_CID_BITS) - 1;
new->lid_mask = 0xffff;
} else if (kvm_apic_sw_enabled(apic) && } else if (kvm_apic_sw_enabled(apic) &&
!new->cid_mask /* flat mode */ && !new->cid_mask /* flat mode */ &&
kvm_apic_get_reg(apic, APIC_DFR) == APIC_DFR_CLUSTER) { kvm_apic_get_reg(apic, APIC_DFR) == APIC_DFR_CLUSTER) {
...@@ -841,7 +844,8 @@ static u32 apic_get_tmcct(struct kvm_lapic *apic) ...@@ -841,7 +844,8 @@ static u32 apic_get_tmcct(struct kvm_lapic *apic)
ASSERT(apic != NULL); ASSERT(apic != NULL);
/* if initial count is 0, current count should also be 0 */ /* if initial count is 0, current count should also be 0 */
if (kvm_apic_get_reg(apic, APIC_TMICT) == 0) if (kvm_apic_get_reg(apic, APIC_TMICT) == 0 ||
apic->lapic_timer.period == 0)
return 0; return 0;
remaining = hrtimer_get_remaining(&apic->lapic_timer.timer); remaining = hrtimer_get_remaining(&apic->lapic_timer.timer);
...@@ -1691,7 +1695,6 @@ static void apic_sync_pv_eoi_from_guest(struct kvm_vcpu *vcpu, ...@@ -1691,7 +1695,6 @@ static void apic_sync_pv_eoi_from_guest(struct kvm_vcpu *vcpu,
void kvm_lapic_sync_from_vapic(struct kvm_vcpu *vcpu) void kvm_lapic_sync_from_vapic(struct kvm_vcpu *vcpu)
{ {
u32 data; u32 data;
void *vapic;
if (test_bit(KVM_APIC_PV_EOI_PENDING, &vcpu->arch.apic_attention)) if (test_bit(KVM_APIC_PV_EOI_PENDING, &vcpu->arch.apic_attention))
apic_sync_pv_eoi_from_guest(vcpu, vcpu->arch.apic); apic_sync_pv_eoi_from_guest(vcpu, vcpu->arch.apic);
...@@ -1699,9 +1702,8 @@ void kvm_lapic_sync_from_vapic(struct kvm_vcpu *vcpu) ...@@ -1699,9 +1702,8 @@ void kvm_lapic_sync_from_vapic(struct kvm_vcpu *vcpu)
if (!test_bit(KVM_APIC_CHECK_VAPIC, &vcpu->arch.apic_attention)) if (!test_bit(KVM_APIC_CHECK_VAPIC, &vcpu->arch.apic_attention))
return; return;
vapic = kmap_atomic(vcpu->arch.apic->vapic_page); kvm_read_guest_cached(vcpu->kvm, &vcpu->arch.apic->vapic_cache, &data,
data = *(u32 *)(vapic + offset_in_page(vcpu->arch.apic->vapic_addr)); sizeof(u32));
kunmap_atomic(vapic);
apic_set_tpr(vcpu->arch.apic, data & 0xff); apic_set_tpr(vcpu->arch.apic, data & 0xff);
} }
...@@ -1737,7 +1739,6 @@ void kvm_lapic_sync_to_vapic(struct kvm_vcpu *vcpu) ...@@ -1737,7 +1739,6 @@ void kvm_lapic_sync_to_vapic(struct kvm_vcpu *vcpu)
u32 data, tpr; u32 data, tpr;
int max_irr, max_isr; int max_irr, max_isr;
struct kvm_lapic *apic = vcpu->arch.apic; struct kvm_lapic *apic = vcpu->arch.apic;
void *vapic;
apic_sync_pv_eoi_to_guest(vcpu, apic); apic_sync_pv_eoi_to_guest(vcpu, apic);
...@@ -1753,18 +1754,24 @@ void kvm_lapic_sync_to_vapic(struct kvm_vcpu *vcpu) ...@@ -1753,18 +1754,24 @@ void kvm_lapic_sync_to_vapic(struct kvm_vcpu *vcpu)
max_isr = 0; max_isr = 0;
data = (tpr & 0xff) | ((max_isr & 0xf0) << 8) | (max_irr << 24); data = (tpr & 0xff) | ((max_isr & 0xf0) << 8) | (max_irr << 24);
vapic = kmap_atomic(vcpu->arch.apic->vapic_page); kvm_write_guest_cached(vcpu->kvm, &vcpu->arch.apic->vapic_cache, &data,
*(u32 *)(vapic + offset_in_page(vcpu->arch.apic->vapic_addr)) = data; sizeof(u32));
kunmap_atomic(vapic);
} }
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)
{ {
vcpu->arch.apic->vapic_addr = vapic_addr; if (vapic_addr) {
if (vapic_addr) if (kvm_gfn_to_hva_cache_init(vcpu->kvm,
&vcpu->arch.apic->vapic_cache,
vapic_addr, sizeof(u32)))
return -EINVAL;
__set_bit(KVM_APIC_CHECK_VAPIC, &vcpu->arch.apic_attention); __set_bit(KVM_APIC_CHECK_VAPIC, &vcpu->arch.apic_attention);
else } else {
__clear_bit(KVM_APIC_CHECK_VAPIC, &vcpu->arch.apic_attention); __clear_bit(KVM_APIC_CHECK_VAPIC, &vcpu->arch.apic_attention);
}
vcpu->arch.apic->vapic_addr = vapic_addr;
return 0;
} }
int kvm_x2apic_msr_write(struct kvm_vcpu *vcpu, u32 msr, u64 data) int kvm_x2apic_msr_write(struct kvm_vcpu *vcpu, u32 msr, u64 data)
......
...@@ -34,7 +34,7 @@ struct kvm_lapic { ...@@ -34,7 +34,7 @@ struct kvm_lapic {
*/ */
void *regs; void *regs;
gpa_t vapic_addr; gpa_t vapic_addr;
struct page *vapic_page; struct gfn_to_hva_cache vapic_cache;
unsigned long pending_events; unsigned long pending_events;
unsigned int sipi_vector; unsigned int sipi_vector;
}; };
...@@ -76,7 +76,7 @@ void kvm_set_lapic_tscdeadline_msr(struct kvm_vcpu *vcpu, u64 data); ...@@ -76,7 +76,7 @@ void kvm_set_lapic_tscdeadline_msr(struct kvm_vcpu *vcpu, u64 data);
void kvm_apic_write_nodecode(struct kvm_vcpu *vcpu, u32 offset); void kvm_apic_write_nodecode(struct kvm_vcpu *vcpu, u32 offset);
void kvm_apic_set_eoi_accelerated(struct kvm_vcpu *vcpu, int vector); void kvm_apic_set_eoi_accelerated(struct kvm_vcpu *vcpu, int vector);
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_from_vapic(struct kvm_vcpu *vcpu);
void kvm_lapic_sync_to_vapic(struct kvm_vcpu *vcpu); void kvm_lapic_sync_to_vapic(struct kvm_vcpu *vcpu);
......
...@@ -3214,8 +3214,7 @@ long kvm_arch_vcpu_ioctl(struct file *filp, ...@@ -3214,8 +3214,7 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
r = -EFAULT; r = -EFAULT;
if (copy_from_user(&va, argp, sizeof va)) if (copy_from_user(&va, argp, sizeof va))
goto out; goto out;
r = 0; r = kvm_lapic_set_vapic_addr(vcpu, va.vapic_addr);
kvm_lapic_set_vapic_addr(vcpu, va.vapic_addr);
break; break;
} }
case KVM_X86_SETUP_MCE: { case KVM_X86_SETUP_MCE: {
...@@ -5739,36 +5738,6 @@ static void post_kvm_run_save(struct kvm_vcpu *vcpu) ...@@ -5739,36 +5738,6 @@ static void post_kvm_run_save(struct kvm_vcpu *vcpu)
!kvm_event_needs_reinjection(vcpu); !kvm_event_needs_reinjection(vcpu);
} }
static int vapic_enter(struct kvm_vcpu *vcpu)
{
struct kvm_lapic *apic = vcpu->arch.apic;
struct page *page;
if (!apic || !apic->vapic_addr)
return 0;
page = gfn_to_page(vcpu->kvm, apic->vapic_addr >> PAGE_SHIFT);
if (is_error_page(page))
return -EFAULT;
vcpu->arch.apic->vapic_page = page;
return 0;
}
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) static void update_cr8_intercept(struct kvm_vcpu *vcpu)
{ {
int max_irr, tpr; int max_irr, tpr;
...@@ -6069,11 +6038,6 @@ static int __vcpu_run(struct kvm_vcpu *vcpu) ...@@ -6069,11 +6038,6 @@ static int __vcpu_run(struct kvm_vcpu *vcpu)
struct kvm *kvm = vcpu->kvm; struct kvm *kvm = vcpu->kvm;
vcpu->srcu_idx = srcu_read_lock(&kvm->srcu); vcpu->srcu_idx = srcu_read_lock(&kvm->srcu);
r = vapic_enter(vcpu);
if (r) {
srcu_read_unlock(&kvm->srcu, vcpu->srcu_idx);
return r;
}
r = 1; r = 1;
while (r > 0) { while (r > 0) {
...@@ -6132,8 +6096,6 @@ static int __vcpu_run(struct kvm_vcpu *vcpu) ...@@ -6132,8 +6096,6 @@ static int __vcpu_run(struct kvm_vcpu *vcpu)
srcu_read_unlock(&kvm->srcu, vcpu->srcu_idx); srcu_read_unlock(&kvm->srcu, vcpu->srcu_idx);
vapic_exit(vcpu);
return r; return r;
} }
......
...@@ -1898,6 +1898,9 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, u32 id) ...@@ -1898,6 +1898,9 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, u32 id)
int r; int r;
struct kvm_vcpu *vcpu, *v; struct kvm_vcpu *vcpu, *v;
if (id >= KVM_MAX_VCPUS)
return -EINVAL;
vcpu = kvm_arch_vcpu_create(kvm, id); vcpu = kvm_arch_vcpu_create(kvm, id);
if (IS_ERR(vcpu)) if (IS_ERR(vcpu))
return PTR_ERR(vcpu); return PTR_ERR(vcpu);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment