Commit 2caeeb9d authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull kvm fixes from Paolo Bonzini:
 "Two serious ARM fixes:

   - Plug a buffer overflow due to the use of the user-provided register
     width for firmware regs. Outright reject accesses where the user
     register width does not match the kernel representation.

   - Protect non-atomic RMW operations on vCPU flags against preemption,
     as an update to the flags by an intervening preemption could be
     lost"

* tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm:
  KVM: arm64: Fix buffer overflow in kvm_arm_set_fw_reg()
  KVM: arm64: Make vcpu flag updates non-preemptible
parents 84ebdb8e 265b97cb
Loading
Loading
Loading
Loading
+18 −1
Original line number Diff line number Diff line
@@ -576,9 +576,22 @@ struct kvm_vcpu_arch {
	({							\
		__build_check_flag(v, flagset, f, m);		\
								\
		v->arch.flagset & (m);				\
		READ_ONCE(v->arch.flagset) & (m);		\
	})

/*
 * Note that the set/clear accessors must be preempt-safe in order to
 * avoid nesting them with load/put which also manipulate flags...
 */
#ifdef __KVM_NVHE_HYPERVISOR__
/* the nVHE hypervisor is always non-preemptible */
#define __vcpu_flags_preempt_disable()
#define __vcpu_flags_preempt_enable()
#else
#define __vcpu_flags_preempt_disable()	preempt_disable()
#define __vcpu_flags_preempt_enable()	preempt_enable()
#endif

#define __vcpu_set_flag(v, flagset, f, m)			\
	do {							\
		typeof(v->arch.flagset) *fset;			\
@@ -586,9 +599,11 @@ struct kvm_vcpu_arch {
		__build_check_flag(v, flagset, f, m);		\
								\
		fset = &v->arch.flagset;			\
		__vcpu_flags_preempt_disable();			\
		if (HWEIGHT(m) > 1)				\
			*fset &= ~(m);				\
		*fset |= (f);					\
		__vcpu_flags_preempt_enable();			\
	} while (0)

#define __vcpu_clear_flag(v, flagset, f, m)			\
@@ -598,7 +613,9 @@ struct kvm_vcpu_arch {
		__build_check_flag(v, flagset, f, m);		\
								\
		fset = &v->arch.flagset;			\
		__vcpu_flags_preempt_disable();			\
		*fset &= ~(m);					\
		__vcpu_flags_preempt_enable();			\
	} while (0)

#define vcpu_get_flag(v, ...)	__vcpu_get_flag((v), __VA_ARGS__)
+2 −0
Original line number Diff line number Diff line
@@ -397,6 +397,8 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
	u64 val;
	int wa_level;

	if (KVM_REG_SIZE(reg->id) != sizeof(val))
		return -ENOENT;
	if (copy_from_user(&val, uaddr, KVM_REG_SIZE(reg->id)))
		return -EFAULT;