forked from Minki/linux
Four security fixes for KVM on x86. Thanks to Andrew Honig and Lars Bull
from Google for reporting them. -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iQIcBAABAgAGBQJSqi7GAAoJEBvWZb6bTYbyy94P/jdBo/J+4zxujJNDfw9D15xP 81/ByzZ1qxAZhrKKCqlOMWEYIOhEV6sjoJayMMIPkV0i9aYfOl3N4OUTGx8xuDhl eIIQDRQdnFmqi69R2inBTxFYb8uGngsJwGF0iuiIImg/gJvoIAfywFADFPPUbtRP BQQ69IHSCR/rblGVW3hyio7Y/dFtE4dqNYKTH7pamkSVdCz4j3FdVPz+COcXMsc+ wOhphbe0zRnrq8MmwsqMXKefSJtihD34wx+M85tiltGKXx4Jumi3eQcfFTnMCbH1 loA6fGLztXuyul5kpkaLdvoYgvxZDueZ7pO0OO1Wqh60T6OyDRqc/jKohdbzI/g3 /2OCZ7P8yHgxJb1tLAZBr3aWwCQtRhlF8O6eP+bBPQo8Di5Z6xYHDVggvLpHCE7f KRQy1V1ooXbZ1UoytqA0QauCXURUb1jC+tzuZvZzcJN6oFojY8ojL1oVLlW0iDt6 WYzS6YAmIo5jeJ2qvP42dLG8n4kijkQ1gQgBsI8rfsDOYGXJe8TWu7O2aD1rs8Jz d7aPgL+zz8K7wwZgG+U2PTjzkDOuyjRbhNEi7jrCVio6hxvvdQARiLsi+0Q+QUjF Xk0iiSsseCBcFWj6sDnTPn10YnnXyIj6eDM1OImdd+/2VVqnUIiqzwpUsNr3yzVc a+bZbYEsCUP0MwqlmCcA =auYv -----END PGP SIGNATURE----- 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)
This commit is contained in:
commit
54fb723cc4
@ -143,6 +143,8 @@ static inline int kvm_apic_id(struct kvm_lapic *apic)
|
||||
return (kvm_apic_get_reg(apic, APIC_ID) >> 24) & 0xff;
|
||||
}
|
||||
|
||||
#define KVM_X2APIC_CID_BITS 0
|
||||
|
||||
static void recalculate_apic_map(struct kvm *kvm)
|
||||
{
|
||||
struct kvm_apic_map *new, *old = NULL;
|
||||
@ -180,7 +182,8 @@ static void recalculate_apic_map(struct kvm *kvm)
|
||||
if (apic_x2apic_mode(apic)) {
|
||||
new->ldr_bits = 32;
|
||||
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) &&
|
||||
!new->cid_mask /* flat mode */ &&
|
||||
kvm_apic_get_reg(apic, APIC_DFR) == APIC_DFR_CLUSTER) {
|
||||
@ -841,7 +844,8 @@ static u32 apic_get_tmcct(struct kvm_lapic *apic)
|
||||
ASSERT(apic != NULL);
|
||||
|
||||
/* 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;
|
||||
|
||||
remaining = hrtimer_get_remaining(&apic->lapic_timer.timer);
|
||||
@ -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)
|
||||
{
|
||||
u32 data;
|
||||
void *vapic;
|
||||
|
||||
if (test_bit(KVM_APIC_PV_EOI_PENDING, &vcpu->arch.apic_attention))
|
||||
apic_sync_pv_eoi_from_guest(vcpu, vcpu->arch.apic);
|
||||
@ -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))
|
||||
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);
|
||||
}
|
||||
@ -1737,7 +1739,6 @@ void kvm_lapic_sync_to_vapic(struct kvm_vcpu *vcpu)
|
||||
u32 data, tpr;
|
||||
int max_irr, max_isr;
|
||||
struct kvm_lapic *apic = vcpu->arch.apic;
|
||||
void *vapic;
|
||||
|
||||
apic_sync_pv_eoi_to_guest(vcpu, apic);
|
||||
|
||||
@ -1753,18 +1754,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)
|
||||
{
|
||||
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);
|
||||
else
|
||||
} else {
|
||||
__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)
|
||||
|
@ -34,7 +34,7 @@ struct kvm_lapic {
|
||||
*/
|
||||
void *regs;
|
||||
gpa_t vapic_addr;
|
||||
struct page *vapic_page;
|
||||
struct gfn_to_hva_cache vapic_cache;
|
||||
unsigned long pending_events;
|
||||
unsigned int sipi_vector;
|
||||
};
|
||||
@ -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_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_to_vapic(struct kvm_vcpu *vcpu);
|
||||
|
||||
|
@ -3214,8 +3214,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: {
|
||||
@ -5739,36 +5738,6 @@ static void post_kvm_run_save(struct kvm_vcpu *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)
|
||||
{
|
||||
int max_irr, tpr;
|
||||
@ -6069,11 +6038,6 @@ static int __vcpu_run(struct kvm_vcpu *vcpu)
|
||||
struct kvm *kvm = vcpu->kvm;
|
||||
|
||||
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;
|
||||
while (r > 0) {
|
||||
@ -6132,8 +6096,6 @@ static int __vcpu_run(struct kvm_vcpu *vcpu)
|
||||
|
||||
srcu_read_unlock(&kvm->srcu, vcpu->srcu_idx);
|
||||
|
||||
vapic_exit(vcpu);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -1898,6 +1898,9 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, u32 id)
|
||||
int r;
|
||||
struct kvm_vcpu *vcpu, *v;
|
||||
|
||||
if (id >= KVM_MAX_VCPUS)
|
||||
return -EINVAL;
|
||||
|
||||
vcpu = kvm_arch_vcpu_create(kvm, id);
|
||||
if (IS_ERR(vcpu))
|
||||
return PTR_ERR(vcpu);
|
||||
|
Loading…
Reference in New Issue
Block a user