Skip to content

Commit 2caeeb9

Browse files
committed
Merge tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm
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
2 parents 84ebdb8 + 265b97c commit 2caeeb9

File tree

2 files changed

+20
-1
lines changed

2 files changed

+20
-1
lines changed

arch/arm64/include/asm/kvm_host.h

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -576,19 +576,34 @@ struct kvm_vcpu_arch {
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; \
585598
\
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 {
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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,8 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
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

0 commit comments

Comments
 (0)