History

Merge tag 'kvmarm-fixes-6.3-4' of git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm into HEAD

KVM/arm64 fixes for 6.3, part #4 - 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.

Paolo Bonzini committed 3 years ago

Commit 265b97c2 parents 0bf9601 a25bc842 files · +20 −1Browse files

Unified · Split

2 files
  1. arch/arm64/include/asm/kvm_host.h +18 −1
  2. arch/arm64/kvm/hypercalls.c +2 −0
arch/arm64/include/asm/kvm_host.h+18−1
@@ -576,9 +576,22 @@ struct kvm_vcpu_arch { · 575 unmodified lines
576576 ({ \
577577 __build_check_flag(v, flagset, f, m); \
578578 \
579− v->arch.flagset & (m); \
579+ READ_ONCE(v->arch.flagset) & (m); \
580580 })
581581
582+/*
583+ * Note that the set/clear accessors must be preempt-safe in order to
584+ * avoid nesting them with load/put which also manipulate flags...
585+ */
586+#ifdef __KVM_NVHE_HYPERVISOR__
587+/* the nVHE hypervisor is always non-preemptible */
588+#define __vcpu_flags_preempt_disable()
589+#define __vcpu_flags_preempt_enable()
590+#else
591+#define __vcpu_flags_preempt_disable() preempt_disable()
592+#define __vcpu_flags_preempt_enable() preempt_enable()
593+#endif
594+
582595 #define __vcpu_set_flag(v, flagset, f, m) \
583596 do { \
584597 typeof(v->arch.flagset) *fset; \
@@ -586,9 +599,11 @@ struct kvm_vcpu_arch { · 1 unmodified line
586599 __build_check_flag(v, flagset, f, m); \
587600 \
588601 fset = &v->arch.flagset; \
602+ __vcpu_flags_preempt_disable(); \
589603 if (HWEIGHT(m) > 1) \
590604 *fset &= ~(m); \
591605 *fset |= (f); \
606+ __vcpu_flags_preempt_enable(); \
592607 } while (0)
593608
594609 #define __vcpu_clear_flag(v, flagset, f, m) \
@@ -598,7 +613,9 @@ struct kvm_vcpu_arch { · 3 unmodified lines
598613 __build_check_flag(v, flagset, f, m); \
599614 \
600615 fset = &v->arch.flagset; \
616+ __vcpu_flags_preempt_disable(); \
601617 *fset &= ~(m); \
618+ __vcpu_flags_preempt_enable(); \
602619 } while (0)
603620
604621 #define vcpu_get_flag(v, ...) __vcpu_get_flag((v), __VA_ARGS__)
arch/arm64/kvm/hypercalls.c+2−0
@@ -397,6 +397,8 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) · 396 unmodified lines
397397 u64 val;
398398 int wa_level;
399399
400+ if (KVM_REG_SIZE(reg->id) != sizeof(val))
401+ return -ENOENT;
400402 if (copy_from_user(&val, uaddr, KVM_REG_SIZE(reg->id)))
401403 return -EFAULT;
402404