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
576 ({ \576 ({ \
577 __build_check_flag(v, flagset, f, m); \577 __build_check_flag(v, flagset, f, m); \
578 \578 \
579 v->arch.flagset & (m); \579 READ_ONCE(v->arch.flagset) & (m); \
580 })580 })
581 581
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
582#define __vcpu_set_flag(v, flagset, f, m) \595#define __vcpu_set_flag(v, flagset, f, m) \
583 do { \596 do { \
584 typeof(v->arch.flagset) *fset; \597 typeof(v->arch.flagset) *fset; \
@@ -586,9 +599,11 @@ struct kvm_vcpu_arch { · 1 unmodified line
586 __build_check_flag(v, flagset, f, m); \599 __build_check_flag(v, flagset, f, m); \
587 \600 \
588 fset = &v->arch.flagset; \601 fset = &v->arch.flagset; \
602 __vcpu_flags_preempt_disable(); \
589 if (HWEIGHT(m) > 1) \603 if (HWEIGHT(m) > 1) \
590 *fset &= ~(m); \604 *fset &= ~(m); \
591 *fset |= (f); \605 *fset |= (f); \
606 __vcpu_flags_preempt_enable(); \
592 } while (0)607 } while (0)
593 608
594#define __vcpu_clear_flag(v, flagset, f, m) \609#define __vcpu_clear_flag(v, flagset, f, m) \
@@ -598,7 +613,9 @@ struct kvm_vcpu_arch { · 3 unmodified lines
598 __build_check_flag(v, flagset, f, m); \613 __build_check_flag(v, flagset, f, m); \
599 \614 \
600 fset = &v->arch.flagset; \615 fset = &v->arch.flagset; \
616 __vcpu_flags_preempt_disable(); \
601 *fset &= ~(m); \617 *fset &= ~(m); \
618 __vcpu_flags_preempt_enable(); \
602 } while (0)619 } while (0)
603 620
604#define vcpu_get_flag(v, ...) __vcpu_get_flag((v), __VA_ARGS__)621#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
397 u64 val;397 u64 val;
398 int wa_level;398 int wa_level;
399 399
400 if (KVM_REG_SIZE(reg->id) != sizeof(val))
401 return -ENOENT;
400 if (copy_from_user(&val, uaddr, KVM_REG_SIZE(reg->id)))402 if (copy_from_user(&val, uaddr, KVM_REG_SIZE(reg->id)))
401 return -EFAULT;403 return -EFAULT;
402 404