Commit 6d35786d authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull kvm fixes from Paolo Bonzini:
 "Three bug fixes for x86:

   - Check that nEPT/nNPT is enabled in slow flush hypercalls. If it is
     not, the hypercalls can be processed as usual even while running a
     nested guest

   - Fix shadow paging use-after-free due to page tables changing
     outside execution of the guest. A bug that is 16 years old and
     stems from an imprecision in the very first KVM series

   - Scan IRR whenever PID.ON is true, even if PIR is empty, which
     avoids a somewhat rare WARN"

* tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm:
  KVM: x86: Fix shadow paging use-after-free due to unexpected GFN
  KVM: x86: Fix misleading variable names and add more comments for PIR=>IRR flow
  KVM: x86: Do IRR scan in __kvm_apic_update_irr even if PIR is empty
  KVM: x86: check for nEPT/nNPT in slow flush hypercalls
parents 7fd2df20 0cb2af2e
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -2040,7 +2040,7 @@ static u64 kvm_hv_flush_tlb(struct kvm_vcpu *vcpu, struct kvm_hv_hcall *hc)
	 * flush).  Translate the address here so the memory can be uniformly
	 * read with kvm_read_guest().
	 */
	if (!hc->fast && is_guest_mode(vcpu)) {
	if (!hc->fast && mmu_is_nested(vcpu)) {
		hc->ingpa = translate_nested_gpa(vcpu, hc->ingpa, 0, NULL);
		if (unlikely(hc->ingpa == INVALID_GPA))
			return HV_STATUS_INVALID_HYPERCALL_INPUT;
+13 −11
Original line number Diff line number Diff line
@@ -667,13 +667,15 @@ bool __kvm_apic_update_irr(unsigned long *pir, void *regs, int *max_irr)
	u32 *__pir = (void *)pir_vals;
	u32 i, vec;
	u32 irr_val, prev_irr_val;
	int max_updated_irr;
	int max_new_irr;

	max_updated_irr = -1;
	*max_irr = -1;

	if (!pi_harvest_pir(pir, pir_vals))
	if (!pi_harvest_pir(pir, pir_vals)) {
		*max_irr = apic_find_highest_vector(regs + APIC_IRR);
		return false;
	}

	max_new_irr = -1;
	*max_irr = -1;

	for (i = vec = 0; i <= 7; i++, vec += 32) {
		u32 *p_irr = (u32 *)(regs + APIC_IRR + i * 0x10);
@@ -688,25 +690,25 @@ bool __kvm_apic_update_irr(unsigned long *pir, void *regs, int *max_irr)
				 !try_cmpxchg(p_irr, &prev_irr_val, irr_val));

			if (prev_irr_val != irr_val)
				max_updated_irr = __fls(irr_val ^ prev_irr_val) + vec;
				max_new_irr = __fls(irr_val ^ prev_irr_val) + vec;
		}
		if (irr_val)
			*max_irr = __fls(irr_val) + vec;
	}

	return ((max_updated_irr != -1) &&
		(max_updated_irr == *max_irr));
	return max_new_irr != -1 && max_new_irr == *max_irr;
}
EXPORT_SYMBOL_FOR_KVM_INTERNAL(__kvm_apic_update_irr);

bool kvm_apic_update_irr(struct kvm_vcpu *vcpu, unsigned long *pir, int *max_irr)
{
	struct kvm_lapic *apic = vcpu->arch.apic;
	bool irr_updated = __kvm_apic_update_irr(pir, apic->regs, max_irr);
	bool max_irr_is_from_pir;

	if (unlikely(!apic->apicv_active && irr_updated))
	max_irr_is_from_pir = __kvm_apic_update_irr(pir, apic->regs, max_irr);
	if (unlikely(!apic->apicv_active && max_irr_is_from_pir))
		apic->irr_pending = true;
	return irr_updated;
	return max_irr_is_from_pir;
}
EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_apic_update_irr);

+14 −21
Original line number Diff line number Diff line
@@ -182,6 +182,8 @@ static struct kmem_cache *pte_list_desc_cache;
struct kmem_cache *mmu_page_header_cache;

static void mmu_spte_set(u64 *sptep, u64 spte);
static int mmu_page_zap_pte(struct kvm *kvm, struct kvm_mmu_page *sp,
			    u64 *spte, struct list_head *invalid_list);

struct kvm_mmu_role_regs {
	const unsigned long cr0;
@@ -1287,19 +1289,6 @@ static void drop_spte(struct kvm *kvm, u64 *sptep)
		rmap_remove(kvm, sptep);
}

static void drop_large_spte(struct kvm *kvm, u64 *sptep, bool flush)
{
	struct kvm_mmu_page *sp;

	sp = sptep_to_sp(sptep);
	WARN_ON_ONCE(sp->role.level == PG_LEVEL_4K);

	drop_spte(kvm, sptep);

	if (flush)
		kvm_flush_remote_tlbs_sptep(kvm, sptep);
}

/*
 * Write-protect on the specified @sptep, @pt_protect indicates whether
 * spte write-protection is caused by protecting shadow page table.
@@ -2466,7 +2455,8 @@ static struct kvm_mmu_page *kvm_mmu_get_child_sp(struct kvm_vcpu *vcpu,
{
	union kvm_mmu_page_role role;

	if (is_shadow_present_pte(*sptep) && !is_large_pte(*sptep))
	if (is_shadow_present_pte(*sptep) && !is_large_pte(*sptep) &&
	    spte_to_child_sp(*sptep) && spte_to_child_sp(*sptep)->gfn == gfn)
		return ERR_PTR(-EEXIST);

	role = kvm_mmu_child_role(sptep, direct, access);
@@ -2544,13 +2534,16 @@ static void __link_shadow_page(struct kvm *kvm,

	BUILD_BUG_ON(VMX_EPT_WRITABLE_MASK != PT_WRITABLE_MASK);

	/*
	 * If an SPTE is present already, it must be a leaf and therefore
	 * a large one.  Drop it, and flush the TLB if needed, before
	 * installing sp.
	 */
	if (is_shadow_present_pte(*sptep))
		drop_large_spte(kvm, sptep, flush);
	if (is_shadow_present_pte(*sptep)) {
		struct kvm_mmu_page *parent_sp;
		LIST_HEAD(invalid_list);

		parent_sp = sptep_to_sp(sptep);
		WARN_ON_ONCE(parent_sp->role.level == PG_LEVEL_4K);

		mmu_page_zap_pte(kvm, parent_sp, sptep, &invalid_list);
		kvm_mmu_remote_flush_or_zap(kvm, &invalid_list, true);
	}

	spte = make_nonleaf_spte(sp->spt, sp_ad_disabled(sp));

+32 −8
Original line number Diff line number Diff line
@@ -7029,8 +7029,8 @@ static void vmx_set_rvi(int vector)
int vmx_sync_pir_to_irr(struct kvm_vcpu *vcpu)
{
	struct vcpu_vt *vt = to_vt(vcpu);
	bool max_irr_is_from_pir;
	int max_irr;
	bool got_posted_interrupt;

	if (KVM_BUG_ON(!enable_apicv, vcpu->kvm))
		return -EIO;
@@ -7042,17 +7042,22 @@ int vmx_sync_pir_to_irr(struct kvm_vcpu *vcpu)
		 * But on x86 this is just a compiler barrier anyway.
		 */
		smp_mb__after_atomic();
		got_posted_interrupt =
			kvm_apic_update_irr(vcpu, vt->pi_desc.pir, &max_irr);
		max_irr_is_from_pir = kvm_apic_update_irr(vcpu, vt->pi_desc.pir,
							  &max_irr);
	} else {
		max_irr = kvm_lapic_find_highest_irr(vcpu);
		got_posted_interrupt = false;
		max_irr_is_from_pir = false;
	}

	/*
	 * Newly recognized interrupts are injected via either virtual interrupt
	 * delivery (RVI) or KVM_REQ_EVENT.  Virtual interrupt delivery is
	 * disabled in two cases:
	 * If APICv is enabled and L2 is not active, then update the Requesting
	 * Virtual Interrupt (RVI) portion of vmcs01.GUEST_INTR_STATUS with the
	 * highest priority IRR to deliver the IRQ via Virtual Interrupt
	 * Delivery.  Note, this is required even if the highest priority IRQ
	 * was already pending in the IRR, as RVI isn't updated in lockstep with
	 * the IRR (unlike apic->irr_pending).
	 *
	 * For the cases where Virtual Interrupt Delivery can't be used:
	 *
	 * 1) If L2 is running and the vCPU has a new pending interrupt.  If L1
	 * wants to exit on interrupts, KVM_REQ_EVENT is needed to synthesize a
@@ -7063,10 +7068,29 @@ int vmx_sync_pir_to_irr(struct kvm_vcpu *vcpu)
	 * 2) If APICv is disabled for this vCPU, assigned devices may still
	 * attempt to post interrupts.  The posted interrupt vector will cause
	 * a VM-Exit and the subsequent entry will call sync_pir_to_irr.
	 *
	 * In both cases, set KVM_REQ_EVENT if and only if the highest priority
	 * pending IRQ came from the PIR, as setting KVM_REQ_EVENT if any IRQ
	 * is pending may put the vCPU into an infinite loop, e.g. if the IRQ
	 * is blocked, then it will stay pending until an IRQ window is opened.
	 *
	 * Note!  It's possible that one or more IRQs were moved from the PIR
	 * to the IRR _without_ max_irr_is_from_pir being true!  I.e. if there
	 * was a higher priority IRQ already pending in the IRR.  Not setting
	 * KVM_REQ_EVENT in this case is intentional and safe.  If APICv is
	 * inactive, or L2 is running with exit-on-interrupt off (in vmcs12),
	 * i.e. without nested virtual interrupt delivery, then there's no need
	 * to request an IRQ window as the lower priority IRQ only needs to be
	 * delivered when the higher priority IRQ is dismissed from the ISR,
	 * i.e. on the next EOI, and EOIs are always intercepted if APICv is
	 * disabled or if L2 is running without nested VID.  If L2 is running
	 * exit-on-interrupt on (in vmcs12), then the higher priority IRQ will
	 * trigger a nested VM-Exit, at which point KVM will re-evaluate L1's
	 * pending IRQs.
	 */
	if (!is_guest_mode(vcpu) && kvm_vcpu_apicv_active(vcpu))
		vmx_set_rvi(max_irr);
	else if (got_posted_interrupt)
	else if (max_irr_is_from_pir)
		kvm_make_request(KVM_REQ_EVENT, vcpu);

	return max_irr;