Skip to content

Commit ca00c3a

Browse files
committed
Merge tag 'kvmarm-fixes-6.18-2' of git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm into HEAD
KVM/arm654 fixes for 6.18, take #2 * Core fixes - Fix trapping regression when no in-kernel irqchip is present (20251021094358.1963807-1-sascha.bischoff@arm.com) - Check host-provided, untrusted ranges and offsets in pKVM (20251016164541.3771235-1-vdonnefort@google.com) (20251017075710.2605118-1-sebastianene@google.com) - Fix regression restoring the ID_PFR1_EL1 register (20251030122707.2033690-1-maz@kernel.org - Fix vgic ITS locking issues when LPIs are not directly injected (20251107184847.1784820-1-oupton@kernel.org) * Test fixes - Correct target CPU programming in vgic_lpi_stress selftest (20251020145946.48288-1-mdittgen@amazon.de) - Fix exposure of SCTLR2_EL2 and ZCR_EL2 in get-reg-list selftest (20251023-b4-kvm-arm64-get-reg-list-sctlr-el2-v1-1-088f88ff992a@kernel.org) (20251024-kvm-arm64-get-reg-list-zcr-el2-v1-1-0cd0ff75e22f@kernel.org) * Misc - Update Oliver's email address (20251107012830.1708225-1-oupton@kernel.org)
2 parents 0e5ba55 + 4af235b commit ca00c3a

File tree

12 files changed

+137
-64
lines changed

12 files changed

+137
-64
lines changed

.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
@@ -13656,7 +13656,7 @@ F: virt/kvm/*
1365613656

1365713657
KERNEL VIRTUAL MACHINE FOR ARM64 (KVM/arm64)
1365813658
M: Marc Zyngier <maz@kernel.org>
13659-
M: Oliver Upton <oliver.upton@linux.dev>
13659+
M: Oliver Upton <oupton@kernel.org>
1366013660
R: Joey Gouly <joey.gouly@arm.com>
1366113661
R: Suzuki K Poulose <suzuki.poulose@arm.com>
1366213662
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)