Skip to content

Commit 4ea7c17

Browse files
committed
Merge tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm
Pull kvm fixes from Paolo Bonzini: "Arm: - Fix trapping regression when no in-kernel irqchip is present - Check host-provided, untrusted ranges and offsets in pKVM - Fix regression restoring the ID_PFR1_EL1 register - Fix vgic ITS locking issues when LPIs are not directly injected Arm selftests: - Correct target CPU programming in vgic_lpi_stress selftest - Fix exposure of SCTLR2_EL2 and ZCR_EL2 in get-reg-list selftest RISC-V: - Fix check for local interrupts on riscv32 - Read HGEIP CSR on the correct cpu when checking for IMSIC interrupts - Remove automatic I/O mapping from kvm_arch_prepare_memory_region() x86: - Inject #UD if the guest attempts to execute SEAMCALL or TDCALL as KVM doesn't support virtualization the instructions, but the instructions are gated only by VMXON. That is, they will VM-Exit instead of taking a #UD and until now this resulted in KVM exiting to userspace with an emulation error. - Unload the "FPU" when emulating INIT of XSTATE features if and only if the FPU is actually loaded, instead of trying to predict when KVM will emulate an INIT (CET support missed the MP_STATE path). Add sanity checks to detect and harden against similar bugs in the future. - Unregister KVM's GALog notifier (for AVIC) when kvm-amd.ko is unloaded. - Use a raw spinlock for svm->ir_list_lock as the lock is taken during schedule(), and "normal" spinlocks are sleepable locks when PREEMPT_RT=y. - Remove guest_memfd bindings on memslot deletion when a gmem file is dying to fix a use-after-free race found by syzkaller. - Fix a goof in the EPT Violation handler where KVM checks the wrong variable when determining if the reported GVA is valid. - Fix and simplify the handling of LBR virtualization on AMD, which was made buggy and unnecessarily complicated by nested VM support Misc: - Update Oliver's email address" * tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm: (28 commits) KVM: nSVM: Fix and simplify LBR virtualization handling with nested KVM: nSVM: Always recalculate LBR MSR intercepts in svm_update_lbrv() KVM: SVM: Mark VMCB_LBR dirty when MSR_IA32_DEBUGCTLMSR is updated MAINTAINERS: Switch myself to using kernel.org address KVM: arm64: vgic-v3: Release reserved slot outside of lpi_xa's lock KVM: arm64: vgic-v3: Reinstate IRQ lock ordering for LPI xarray KVM: arm64: Limit clearing of ID_{AA64PFR0,PFR1}_EL1.GIC to userspace irqchip KVM: arm64: Set ID_{AA64PFR0,PFR1}_EL1.GIC when GICv3 is configured KVM: arm64: Make all 32bit ID registers fully writable KVM: VMX: Fix check for valid GVA on an EPT violation KVM: guest_memfd: Remove bindings on memslot deletion when gmem is dying KVM: SVM: switch to raw spinlock for svm->ir_list_lock KVM: SVM: Make avic_ga_log_notifier() local to avic.c KVM: SVM: Unregister KVM's GALog notifier on kvm-amd.ko exit KVM: SVM: Initialize per-CPU svm_data at the end of hardware setup KVM: x86: Call out MSR_IA32_S_CET is not handled by XSAVES KVM: x86: Harden KVM against imbalanced load/put of guest FPU state KVM: x86: Unload "FPU" state on INIT if and only if its currently in-use KVM: arm64: Check the untrusted offset in FF-A memory share KVM: arm64: Check range args for pKVM mem transitions ...
2 parents e9a6fb0 + 8a48214 commit 4ea7c17

25 files changed

Lines changed: 296 additions & 196 deletions

File tree

.mailmap

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -605,7 +605,8 @@ Oleksij Rempel <o.rempel@pengutronix.de>
605605
Oleksij Rempel <o.rempel@pengutronix.de> <ore@pengutronix.de>
606606
Oliver Hartkopp <socketcan@hartkopp.net> <oliver.hartkopp@volkswagen.de>
607607
Oliver Hartkopp <socketcan@hartkopp.net> <oliver@hartkopp.net>
608-
Oliver Upton <oliver.upton@linux.dev> <oupton@google.com>
608+
Oliver Upton <oupton@kernel.org> <oupton@google.com>
609+
Oliver Upton <oupton@kernel.org> <oliver.upton@linux.dev>
609610
Ondřej Jirman <megi@xff.cz> <megous@megous.com>
610611
Oza Pawandeep <quic_poza@quicinc.com> <poza@codeaurora.org>
611612
Pali Rohár <pali@kernel.org> <pali.rohar@gmail.com>

MAINTAINERS

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13659,7 +13659,7 @@ F: virt/kvm/*
1365913659

1366013660
KERNEL VIRTUAL MACHINE FOR ARM64 (KVM/arm64)
1366113661
M: Marc Zyngier <maz@kernel.org>
13662-
M: Oliver Upton <oliver.upton@linux.dev>
13662+
M: Oliver Upton <oupton@kernel.org>
1366313663
R: Joey Gouly <joey.gouly@arm.com>
1366413664
R: Suzuki K Poulose <suzuki.poulose@arm.com>
1366513665
R: Zenghui Yu <yuzenghui@huawei.com>

arch/arm64/kvm/hyp/nvhe/ffa.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -479,7 +479,7 @@ static void __do_ffa_mem_xfer(const u64 func_id,
479479
struct ffa_mem_region_attributes *ep_mem_access;
480480
struct ffa_composite_mem_region *reg;
481481
struct ffa_mem_region *buf;
482-
u32 offset, nr_ranges;
482+
u32 offset, nr_ranges, checked_offset;
483483
int ret = 0;
484484

485485
if (addr_mbz || npages_mbz || fraglen > len ||
@@ -516,7 +516,12 @@ static void __do_ffa_mem_xfer(const u64 func_id,
516516
goto out_unlock;
517517
}
518518

519-
if (fraglen < offset + sizeof(struct ffa_composite_mem_region)) {
519+
if (check_add_overflow(offset, sizeof(struct ffa_composite_mem_region), &checked_offset)) {
520+
ret = FFA_RET_INVALID_PARAMETERS;
521+
goto out_unlock;
522+
}
523+
524+
if (fraglen < checked_offset) {
520525
ret = FFA_RET_INVALID_PARAMETERS;
521526
goto out_unlock;
522527
}

arch/arm64/kvm/hyp/nvhe/mem_protect.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,19 @@ static int host_stage2_unmap_dev_all(void)
367367
return kvm_pgtable_stage2_unmap(pgt, addr, BIT(pgt->ia_bits) - addr);
368368
}
369369

370+
/*
371+
* Ensure the PFN range is contained within PA-range.
372+
*
373+
* This check is also robust to overflows and is therefore a requirement before
374+
* using a pfn/nr_pages pair from an untrusted source.
375+
*/
376+
static bool pfn_range_is_valid(u64 pfn, u64 nr_pages)
377+
{
378+
u64 limit = BIT(kvm_phys_shift(&host_mmu.arch.mmu) - PAGE_SHIFT);
379+
380+
return pfn < limit && ((limit - pfn) >= nr_pages);
381+
}
382+
370383
struct kvm_mem_range {
371384
u64 start;
372385
u64 end;
@@ -776,6 +789,9 @@ int __pkvm_host_donate_hyp(u64 pfn, u64 nr_pages)
776789
void *virt = __hyp_va(phys);
777790
int ret;
778791

792+
if (!pfn_range_is_valid(pfn, nr_pages))
793+
return -EINVAL;
794+
779795
host_lock_component();
780796
hyp_lock_component();
781797

@@ -804,6 +820,9 @@ int __pkvm_hyp_donate_host(u64 pfn, u64 nr_pages)
804820
u64 virt = (u64)__hyp_va(phys);
805821
int ret;
806822

823+
if (!pfn_range_is_valid(pfn, nr_pages))
824+
return -EINVAL;
825+
807826
host_lock_component();
808827
hyp_lock_component();
809828

@@ -887,6 +906,9 @@ int __pkvm_host_share_ffa(u64 pfn, u64 nr_pages)
887906
u64 size = PAGE_SIZE * nr_pages;
888907
int ret;
889908

909+
if (!pfn_range_is_valid(pfn, nr_pages))
910+
return -EINVAL;
911+
890912
host_lock_component();
891913
ret = __host_check_page_state_range(phys, size, PKVM_PAGE_OWNED);
892914
if (!ret)
@@ -902,6 +924,9 @@ int __pkvm_host_unshare_ffa(u64 pfn, u64 nr_pages)
902924
u64 size = PAGE_SIZE * nr_pages;
903925
int ret;
904926

927+
if (!pfn_range_is_valid(pfn, nr_pages))
928+
return -EINVAL;
929+
905930
host_lock_component();
906931
ret = __host_check_page_state_range(phys, size, PKVM_PAGE_SHARED_OWNED);
907932
if (!ret)
@@ -945,6 +970,9 @@ int __pkvm_host_share_guest(u64 pfn, u64 gfn, u64 nr_pages, struct pkvm_hyp_vcpu
945970
if (prot & ~KVM_PGTABLE_PROT_RWX)
946971
return -EINVAL;
947972

973+
if (!pfn_range_is_valid(pfn, nr_pages))
974+
return -EINVAL;
975+
948976
ret = __guest_check_transition_size(phys, ipa, nr_pages, &size);
949977
if (ret)
950978
return ret;

arch/arm64/kvm/sys_regs.c

Lines changed: 38 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2595,19 +2595,23 @@ static bool bad_redir_trap(struct kvm_vcpu *vcpu,
25952595
.val = 0, \
25962596
}
25972597

2598-
/* sys_reg_desc initialiser for known cpufeature ID registers */
2599-
#define AA32_ID_SANITISED(name) { \
2600-
ID_DESC(name), \
2601-
.visibility = aa32_id_visibility, \
2602-
.val = 0, \
2603-
}
2604-
26052598
/* sys_reg_desc initialiser for writable ID registers */
26062599
#define ID_WRITABLE(name, mask) { \
26072600
ID_DESC(name), \
26082601
.val = mask, \
26092602
}
26102603

2604+
/*
2605+
* 32bit ID regs are fully writable when the guest is 32bit
2606+
* capable. Nothing in the KVM code should rely on 32bit features
2607+
* anyway, only 64bit, so let the VMM do its worse.
2608+
*/
2609+
#define AA32_ID_WRITABLE(name) { \
2610+
ID_DESC(name), \
2611+
.visibility = aa32_id_visibility, \
2612+
.val = GENMASK(31, 0), \
2613+
}
2614+
26112615
/* sys_reg_desc initialiser for cpufeature ID registers that need filtering */
26122616
#define ID_FILTERED(sysreg, name, mask) { \
26132617
ID_DESC(sysreg), \
@@ -3128,40 +3132,39 @@ static const struct sys_reg_desc sys_reg_descs[] = {
31283132

31293133
/* AArch64 mappings of the AArch32 ID registers */
31303134
/* CRm=1 */
3131-
AA32_ID_SANITISED(ID_PFR0_EL1),
3132-
AA32_ID_SANITISED(ID_PFR1_EL1),
3135+
AA32_ID_WRITABLE(ID_PFR0_EL1),
3136+
AA32_ID_WRITABLE(ID_PFR1_EL1),
31333137
{ SYS_DESC(SYS_ID_DFR0_EL1),
31343138
.access = access_id_reg,
31353139
.get_user = get_id_reg,
31363140
.set_user = set_id_dfr0_el1,
31373141
.visibility = aa32_id_visibility,
31383142
.reset = read_sanitised_id_dfr0_el1,
3139-
.val = ID_DFR0_EL1_PerfMon_MASK |
3140-
ID_DFR0_EL1_CopDbg_MASK, },
3143+
.val = GENMASK(31, 0) },
31413144
ID_HIDDEN(ID_AFR0_EL1),
3142-
AA32_ID_SANITISED(ID_MMFR0_EL1),
3143-
AA32_ID_SANITISED(ID_MMFR1_EL1),
3144-
AA32_ID_SANITISED(ID_MMFR2_EL1),
3145-
AA32_ID_SANITISED(ID_MMFR3_EL1),
3145+
AA32_ID_WRITABLE(ID_MMFR0_EL1),
3146+
AA32_ID_WRITABLE(ID_MMFR1_EL1),
3147+
AA32_ID_WRITABLE(ID_MMFR2_EL1),
3148+
AA32_ID_WRITABLE(ID_MMFR3_EL1),
31463149

31473150
/* CRm=2 */
3148-
AA32_ID_SANITISED(ID_ISAR0_EL1),
3149-
AA32_ID_SANITISED(ID_ISAR1_EL1),
3150-
AA32_ID_SANITISED(ID_ISAR2_EL1),
3151-
AA32_ID_SANITISED(ID_ISAR3_EL1),
3152-
AA32_ID_SANITISED(ID_ISAR4_EL1),
3153-
AA32_ID_SANITISED(ID_ISAR5_EL1),
3154-
AA32_ID_SANITISED(ID_MMFR4_EL1),
3155-
AA32_ID_SANITISED(ID_ISAR6_EL1),
3151+
AA32_ID_WRITABLE(ID_ISAR0_EL1),
3152+
AA32_ID_WRITABLE(ID_ISAR1_EL1),
3153+
AA32_ID_WRITABLE(ID_ISAR2_EL1),
3154+
AA32_ID_WRITABLE(ID_ISAR3_EL1),
3155+
AA32_ID_WRITABLE(ID_ISAR4_EL1),
3156+
AA32_ID_WRITABLE(ID_ISAR5_EL1),
3157+
AA32_ID_WRITABLE(ID_MMFR4_EL1),
3158+
AA32_ID_WRITABLE(ID_ISAR6_EL1),
31563159

31573160
/* CRm=3 */
3158-
AA32_ID_SANITISED(MVFR0_EL1),
3159-
AA32_ID_SANITISED(MVFR1_EL1),
3160-
AA32_ID_SANITISED(MVFR2_EL1),
3161+
AA32_ID_WRITABLE(MVFR0_EL1),
3162+
AA32_ID_WRITABLE(MVFR1_EL1),
3163+
AA32_ID_WRITABLE(MVFR2_EL1),
31613164
ID_UNALLOCATED(3,3),
3162-
AA32_ID_SANITISED(ID_PFR2_EL1),
3165+
AA32_ID_WRITABLE(ID_PFR2_EL1),
31633166
ID_HIDDEN(ID_DFR1_EL1),
3164-
AA32_ID_SANITISED(ID_MMFR5_EL1),
3167+
AA32_ID_WRITABLE(ID_MMFR5_EL1),
31653168
ID_UNALLOCATED(3,7),
31663169

31673170
/* AArch64 ID registers */
@@ -5606,11 +5609,13 @@ int kvm_finalize_sys_regs(struct kvm_vcpu *vcpu)
56065609

56075610
guard(mutex)(&kvm->arch.config_lock);
56085611

5609-
if (!(static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif) &&
5610-
irqchip_in_kernel(kvm) &&
5611-
kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3)) {
5612-
kvm->arch.id_regs[IDREG_IDX(SYS_ID_AA64PFR0_EL1)] &= ~ID_AA64PFR0_EL1_GIC_MASK;
5613-
kvm->arch.id_regs[IDREG_IDX(SYS_ID_PFR1_EL1)] &= ~ID_PFR1_EL1_GIC_MASK;
5612+
if (!irqchip_in_kernel(kvm)) {
5613+
u64 val;
5614+
5615+
val = kvm_read_vm_id_reg(kvm, SYS_ID_AA64PFR0_EL1) & ~ID_AA64PFR0_EL1_GIC;
5616+
kvm_set_vm_id_reg(kvm, SYS_ID_AA64PFR0_EL1, val);
5617+
val = kvm_read_vm_id_reg(kvm, SYS_ID_PFR1_EL1) & ~ID_PFR1_EL1_GIC;
5618+
kvm_set_vm_id_reg(kvm, SYS_ID_PFR1_EL1, val);
56145619
}
56155620

56165621
if (vcpu_has_nv(vcpu)) {

arch/arm64/kvm/vgic/vgic-debug.c

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,29 +64,37 @@ static void iter_next(struct kvm *kvm, struct vgic_state_iter *iter)
6464
static int iter_mark_lpis(struct kvm *kvm)
6565
{
6666
struct vgic_dist *dist = &kvm->arch.vgic;
67+
unsigned long intid, flags;
6768
struct vgic_irq *irq;
68-
unsigned long intid;
6969
int nr_lpis = 0;
7070

71+
xa_lock_irqsave(&dist->lpi_xa, flags);
72+
7173
xa_for_each(&dist->lpi_xa, intid, irq) {
7274
if (!vgic_try_get_irq_ref(irq))
7375
continue;
7476

75-
xa_set_mark(&dist->lpi_xa, intid, LPI_XA_MARK_DEBUG_ITER);
77+
__xa_set_mark(&dist->lpi_xa, intid, LPI_XA_MARK_DEBUG_ITER);
7678
nr_lpis++;
7779
}
7880

81+
xa_unlock_irqrestore(&dist->lpi_xa, flags);
82+
7983
return nr_lpis;
8084
}
8185

8286
static void iter_unmark_lpis(struct kvm *kvm)
8387
{
8488
struct vgic_dist *dist = &kvm->arch.vgic;
89+
unsigned long intid, flags;
8590
struct vgic_irq *irq;
86-
unsigned long intid;
8791

8892
xa_for_each_marked(&dist->lpi_xa, intid, irq, LPI_XA_MARK_DEBUG_ITER) {
89-
xa_clear_mark(&dist->lpi_xa, intid, LPI_XA_MARK_DEBUG_ITER);
93+
xa_lock_irqsave(&dist->lpi_xa, flags);
94+
__xa_clear_mark(&dist->lpi_xa, intid, LPI_XA_MARK_DEBUG_ITER);
95+
xa_unlock_irqrestore(&dist->lpi_xa, flags);
96+
97+
/* vgic_put_irq() expects to be called outside of the xa_lock */
9098
vgic_put_irq(kvm, irq);
9199
}
92100
}

arch/arm64/kvm/vgic/vgic-init.c

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ void kvm_vgic_early_init(struct kvm *kvm)
5353
{
5454
struct vgic_dist *dist = &kvm->arch.vgic;
5555

56-
xa_init(&dist->lpi_xa);
56+
xa_init_flags(&dist->lpi_xa, XA_FLAGS_LOCK_IRQ);
5757
}
5858

5959
/* CREATION */
@@ -71,6 +71,7 @@ static int vgic_allocate_private_irqs_locked(struct kvm_vcpu *vcpu, u32 type);
7171
int kvm_vgic_create(struct kvm *kvm, u32 type)
7272
{
7373
struct kvm_vcpu *vcpu;
74+
u64 aa64pfr0, pfr1;
7475
unsigned long i;
7576
int ret;
7677

@@ -161,10 +162,19 @@ int kvm_vgic_create(struct kvm *kvm, u32 type)
161162

162163
kvm->arch.vgic.vgic_dist_base = VGIC_ADDR_UNDEF;
163164

164-
if (type == KVM_DEV_TYPE_ARM_VGIC_V2)
165+
aa64pfr0 = kvm_read_vm_id_reg(kvm, SYS_ID_AA64PFR0_EL1) & ~ID_AA64PFR0_EL1_GIC;
166+
pfr1 = kvm_read_vm_id_reg(kvm, SYS_ID_PFR1_EL1) & ~ID_PFR1_EL1_GIC;
167+
168+
if (type == KVM_DEV_TYPE_ARM_VGIC_V2) {
165169
kvm->arch.vgic.vgic_cpu_base = VGIC_ADDR_UNDEF;
166-
else
170+
} else {
167171
INIT_LIST_HEAD(&kvm->arch.vgic.rd_regions);
172+
aa64pfr0 |= SYS_FIELD_PREP_ENUM(ID_AA64PFR0_EL1, GIC, IMP);
173+
pfr1 |= SYS_FIELD_PREP_ENUM(ID_PFR1_EL1, GIC, GICv3);
174+
}
175+
176+
kvm_set_vm_id_reg(kvm, SYS_ID_AA64PFR0_EL1, aa64pfr0);
177+
kvm_set_vm_id_reg(kvm, SYS_ID_PFR1_EL1, pfr1);
168178

169179
if (type == KVM_DEV_TYPE_ARM_VGIC_V3)
170180
kvm->arch.vgic.nassgicap = system_supports_direct_sgis();

arch/arm64/kvm/vgic/vgic-its.c

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ static struct vgic_irq *vgic_add_lpi(struct kvm *kvm, u32 intid,
7878
{
7979
struct vgic_dist *dist = &kvm->arch.vgic;
8080
struct vgic_irq *irq = vgic_get_irq(kvm, intid), *oldirq;
81+
unsigned long flags;
8182
int ret;
8283

8384
/* In this case there is no put, since we keep the reference. */
@@ -88,7 +89,7 @@ static struct vgic_irq *vgic_add_lpi(struct kvm *kvm, u32 intid,
8889
if (!irq)
8990
return ERR_PTR(-ENOMEM);
9091

91-
ret = xa_reserve(&dist->lpi_xa, intid, GFP_KERNEL_ACCOUNT);
92+
ret = xa_reserve_irq(&dist->lpi_xa, intid, GFP_KERNEL_ACCOUNT);
9293
if (ret) {
9394
kfree(irq);
9495
return ERR_PTR(ret);
@@ -103,7 +104,7 @@ static struct vgic_irq *vgic_add_lpi(struct kvm *kvm, u32 intid,
103104
irq->target_vcpu = vcpu;
104105
irq->group = 1;
105106

106-
xa_lock(&dist->lpi_xa);
107+
xa_lock_irqsave(&dist->lpi_xa, flags);
107108

108109
/*
109110
* There could be a race with another vgic_add_lpi(), so we need to
@@ -114,21 +115,18 @@ static struct vgic_irq *vgic_add_lpi(struct kvm *kvm, u32 intid,
114115
/* Someone was faster with adding this LPI, lets use that. */
115116
kfree(irq);
116117
irq = oldirq;
117-
118-
goto out_unlock;
118+
} else {
119+
ret = xa_err(__xa_store(&dist->lpi_xa, intid, irq, 0));
119120
}
120121

121-
ret = xa_err(__xa_store(&dist->lpi_xa, intid, irq, 0));
122+
xa_unlock_irqrestore(&dist->lpi_xa, flags);
123+
122124
if (ret) {
123125
xa_release(&dist->lpi_xa, intid);
124126
kfree(irq);
125-
}
126-
127-
out_unlock:
128-
xa_unlock(&dist->lpi_xa);
129127

130-
if (ret)
131128
return ERR_PTR(ret);
129+
}
132130

133131
/*
134132
* We "cache" the configuration table entries in our struct vgic_irq's.

arch/arm64/kvm/vgic/vgic-v3.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,8 @@ void vcpu_set_ich_hcr(struct kvm_vcpu *vcpu)
301301
return;
302302

303303
/* Hide GICv3 sysreg if necessary */
304-
if (vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V2) {
304+
if (vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V2 ||
305+
!irqchip_in_kernel(vcpu->kvm)) {
305306
vgic_v3->vgic_hcr |= (ICH_HCR_EL2_TALL0 | ICH_HCR_EL2_TALL1 |
306307
ICH_HCR_EL2_TC);
307308
return;

0 commit comments

Comments
 (0)