Skip to content

Commit dac000a

Browse files
Marc Zyngierpull[bot]
authored andcommitted
KVM: arm64: Inject exception on out-of-IPA-range translation fault
When taking a translation fault for an IPA that is outside of the range defined by the hypervisor (between the HW PARange and the IPA range), we stupidly treat it as an IO and forward the access to userspace. Of course, userspace can't do much with it, and things end badly. Arguably, the guest is braindead, but we should at least catch the case and inject an exception. Check the faulting IPA against: - the sanitised PARange: inject an address size fault - the IPA size: inject an abort Reported-by: Christoffer Dall <[email protected]> Signed-off-by: Marc Zyngier <[email protected]>
1 parent c9f4cab commit dac000a

File tree

3 files changed

+48
-0
lines changed

3 files changed

+48
-0
lines changed

arch/arm64/include/asm/kvm_emulate.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ void kvm_inject_undefined(struct kvm_vcpu *vcpu);
4040
void kvm_inject_vabt(struct kvm_vcpu *vcpu);
4141
void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr);
4242
void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr);
43+
void kvm_inject_size_fault(struct kvm_vcpu *vcpu);
4344

4445
void kvm_vcpu_wfi(struct kvm_vcpu *vcpu);
4546

arch/arm64/kvm/inject_fault.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,34 @@ void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr)
145145
inject_abt64(vcpu, true, addr);
146146
}
147147

148+
void kvm_inject_size_fault(struct kvm_vcpu *vcpu)
149+
{
150+
unsigned long addr, esr;
151+
152+
addr = kvm_vcpu_get_fault_ipa(vcpu);
153+
addr |= kvm_vcpu_get_hfar(vcpu) & GENMASK(11, 0);
154+
155+
if (kvm_vcpu_trap_is_iabt(vcpu))
156+
kvm_inject_pabt(vcpu, addr);
157+
else
158+
kvm_inject_dabt(vcpu, addr);
159+
160+
/*
161+
* If AArch64 or LPAE, set FSC to 0 to indicate an Address
162+
* Size Fault at level 0, as if exceeding PARange.
163+
*
164+
* Non-LPAE guests will only get the external abort, as there
165+
* is no way to to describe the ASF.
166+
*/
167+
if (vcpu_el1_is_32bit(vcpu) &&
168+
!(vcpu_read_sys_reg(vcpu, TCR_EL1) & TTBCR_EAE))
169+
return;
170+
171+
esr = vcpu_read_sys_reg(vcpu, ESR_EL1);
172+
esr &= ~GENMASK_ULL(5, 0);
173+
vcpu_write_sys_reg(vcpu, esr, ESR_EL1);
174+
}
175+
148176
/**
149177
* kvm_inject_undefined - inject an undefined instruction into the guest
150178
* @vcpu: The vCPU in which to inject the exception

arch/arm64/kvm/mmu.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1337,6 +1337,25 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu)
13371337
fault_ipa = kvm_vcpu_get_fault_ipa(vcpu);
13381338
is_iabt = kvm_vcpu_trap_is_iabt(vcpu);
13391339

1340+
if (fault_status == FSC_FAULT) {
1341+
/* Beyond sanitised PARange (which is the IPA limit) */
1342+
if (fault_ipa >= BIT_ULL(get_kvm_ipa_limit())) {
1343+
kvm_inject_size_fault(vcpu);
1344+
return 1;
1345+
}
1346+
1347+
/* Falls between the IPA range and the PARange? */
1348+
if (fault_ipa >= BIT_ULL(vcpu->arch.hw_mmu->pgt->ia_bits)) {
1349+
fault_ipa |= kvm_vcpu_get_hfar(vcpu) & GENMASK(11, 0);
1350+
1351+
if (is_iabt)
1352+
kvm_inject_pabt(vcpu, fault_ipa);
1353+
else
1354+
kvm_inject_dabt(vcpu, fault_ipa);
1355+
return 1;
1356+
}
1357+
}
1358+
13401359
/* Synchronous External Abort? */
13411360
if (kvm_vcpu_abt_issea(vcpu)) {
13421361
/*

0 commit comments

Comments
 (0)