diff options
Diffstat (limited to 'arch/x86/kvm/lapic.c')
| -rw-r--r-- | arch/x86/kvm/lapic.c | 20 | 
1 files changed, 18 insertions, 2 deletions
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index e542cf285b51..3c300a196bdf 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -229,6 +229,23 @@ static int kvm_recalculate_phys_map(struct kvm_apic_map *new,  	u32 physical_id;  	/* +	 * For simplicity, KVM always allocates enough space for all possible +	 * xAPIC IDs.  Yell, but don't kill the VM, as KVM can continue on +	 * without the optimized map. +	 */ +	if (WARN_ON_ONCE(xapic_id > new->max_apic_id)) +		return -EINVAL; + +	/* +	 * Bail if a vCPU was added and/or enabled its APIC between allocating +	 * the map and doing the actual calculations for the map.  Note, KVM +	 * hardcodes the x2APIC ID to vcpu_id, i.e. there's no TOCTOU bug if +	 * the compiler decides to reload x2apic_id after this check. +	 */ +	if (x2apic_id > new->max_apic_id) +		return -E2BIG; + +	/*  	 * Deliberately truncate the vCPU ID when detecting a mismatched APIC  	 * ID to avoid false positives if the vCPU ID, i.e. x2APIC ID, is a  	 * 32-bit value.  Any unwanted aliasing due to truncation results will @@ -253,8 +270,7 @@ static int kvm_recalculate_phys_map(struct kvm_apic_map *new,  	 */  	if (vcpu->kvm->arch.x2apic_format) {  		/* See also kvm_apic_match_physical_addr(). */ -		if ((apic_x2apic_mode(apic) || x2apic_id > 0xff) && -			x2apic_id <= new->max_apic_id) +		if (apic_x2apic_mode(apic) || x2apic_id > 0xff)  			new->phys_map[x2apic_id] = apic;  		if (!apic_x2apic_mode(apic) && !new->phys_map[xapic_id])  |