[v2,1/2] KVM: arm64: Assume write fault on S1PTW permission fault on instruction fetch

Message ID 20200915104218.1284701-2-maz@kernel.org
State New
Headers show
Series
  • [v2,1/2] KVM: arm64: Assume write fault on S1PTW permission fault on instruction fetch
Related show

Commit Message

Marc Zyngier Sept. 15, 2020, 10:42 a.m.
KVM currently assumes that an instruction abort can never be a write.
This is in general true, except when the abort is triggered by
a S1PTW on instruction fetch that tries to update the S1 page tables
(to set AF, for example).

This can happen if the page tables have been paged out and brought
back in without seeing a direct write to them (they are thus marked
read only), and the fault handling code will make the PT executable(!)
instead of writable. The guest gets stuck forever.

In these conditions, the permission fault must be considered as
a write so that the Stage-1 update can take place. This is essentially
the I-side equivalent of the problem fixed by 60e21a0ef54c ("arm64: KVM:
Take S1 walks into account when determining S2 write faults").

Update kvm_is_write_fault() to return true on IABT+S1PTW, and introduce
kvm_vcpu_trap_is_exec_fault() that only return true when no faulting
on a S1 fault. Additionally, kvm_vcpu_dabt_iss1tw() is renamed to
kvm_vcpu_abt_iss1tw(), as the above makes it plain that it isn't
specific to data abort.

Cc: stable@vger.kernel.org
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/include/asm/kvm_emulate.h    | 12 ++++++++++--
 arch/arm64/kvm/hyp/include/hyp/switch.h |  2 +-
 arch/arm64/kvm/mmu.c                    |  4 ++--
 3 files changed, 13 insertions(+), 5 deletions(-)

Comments

Sasha Levin Sept. 21, 2020, 12:54 p.m. | #1
Hi

[This is an automated email]

This commit has been processed because it contains a -stable tag.
The stable tag indicates that it's relevant for the following trees: all

The bot has tested the following trees: v5.8.10, v5.4.66, v4.19.146, v4.14.198, v4.9.236, v4.4.236.

v5.8.10: Failed to apply! Possible dependencies:
    09cf57eba304 ("KVM: arm64: Split hyp/switch.c to VHE/nVHE")
    208243c752a7 ("KVM: arm64: Move hyp-init.S to nVHE")
    3a949f4c9354 ("KVM: arm64: Rename HSR to ESR")
    7621712918ad ("KVM: arm64: Add build rules for separate VHE/nVHE object files")
    7b2399ea5640 ("KVM: arm64: Move __smccc_workaround_1_smc to .rodata")
    b877e9849d41 ("KVM: arm64: Build hyp-entry.S separately for VHE/nVHE")
    f50b6f6ae131 ("KVM: arm64: Handle calls to prefixed hyp functions")

v5.4.66: Failed to apply! Possible dependencies:
    0492747c72a3 ("arm64: KVM: Invoke compute_layout() before alternatives are applied")
    0e20f5e25556 ("KVM: arm/arm64: Cleanup MMIO handling")
    29eb5a3c57f7 ("KVM: arm64: Handle PtrAuth traps early")
    3a949f4c9354 ("KVM: arm64: Rename HSR to ESR")
    5c37f1ae1c33 ("KVM: arm64: Ask the compiler to __always_inline functions used at HYP")
    8e01d9a396e6 ("KVM: arm64: vgic-v4: Move the GICv4 residency flow to be driven by vcpu_load/put")
    c726200dd106 ("KVM: arm/arm64: Allow reporting non-ISV data aborts to userspace")

v4.19.146: Failed to apply! Possible dependencies:
    0e20f5e25556 ("KVM: arm/arm64: Cleanup MMIO handling")
    3a949f4c9354 ("KVM: arm64: Rename HSR to ESR")
    5c37f1ae1c33 ("KVM: arm64: Ask the compiler to __always_inline functions used at HYP")
    5ffdfaedfa0a ("arm64: mm: Support Common Not Private translations")
    86d0dd34eaff ("arm64: cpufeature: add feature for CRC32 instructions")
    caab277b1de0 ("treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 234")
    d94d71cb45fd ("treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 266")

v4.14.198: Failed to apply! Possible dependencies:
    1fc5dce78ad1 ("arm64/sve: Low-level SVE architectural state manipulation functions")
    2e0f2478ea37 ("arm64/sve: Probe SVE capabilities and usable vector lengths")
    3a949f4c9354 ("KVM: arm64: Rename HSR to ESR")
    43994d824e84 ("arm64/sve: Detect SVE and activate runtime support")
    5c37f1ae1c33 ("KVM: arm64: Ask the compiler to __always_inline functions used at HYP")
    611a7bc74ed2 ("arm64: docs: describe ELF hwcaps")
    746647c75afb ("arm64: entry.S convert el0_sync")
    7582e22038a2 ("arm64/sve: Backend logic for setting the vector length")
    79ab047c75d6 ("arm64/sve: Support vector length resetting for new processes")
    94ef7ecbdf6f ("arm64: fpsimd: Correctly annotate exception helpers called from asm")
    bc0ee4760364 ("arm64/sve: Core task context handling")
    ddd25ad1fde8 ("arm64/sve: Kconfig update and conditional compilation support")

v4.9.236: Failed to apply! Possible dependencies:
    016f98afd050 ("irqchip/gic-v3: Use nops macro for Cavium ThunderX erratum 23154")
    0e9884fe63c6 ("arm64: sysreg: subsume GICv3 sysreg definitions")
    328191c05ed7 ("irqchip/gic-v3-its: Specialise flush_dcache operation")
    38fd94b0275c ("arm64: Work around Falkor erratum 1003")
    3a949f4c9354 ("KVM: arm64: Rename HSR to ESR")
    43994d824e84 ("arm64/sve: Detect SVE and activate runtime support")
    47863d41ecf8 ("arm64: sysreg: sort by encoding")
    4aa8a472c33f ("arm64: Documentation - Expose CPU feature registers")
    5c37f1ae1c33 ("KVM: arm64: Ask the compiler to __always_inline functions used at HYP")
    611a7bc74ed2 ("arm64: docs: describe ELF hwcaps")
    6e01398fe450 ("arm64: arch_timer: document Hisilicon erratum 161010101")
    b20d1ba3cf4b ("arm64: cpufeature: allow for version discrepancy in PMU implementations")
    b389d7997acb ("arm64: cpufeature: treat unknown fields as RES0")
    bca8f17f57bd ("arm64: Get rid of asm/opcodes.h")
    c7a3c61fc606 ("arm64: sysreg: add performance monitor registers")
    cd9e1927a525 ("arm64: Work around broken .inst when defective gas is detected")
    d9ff80f83ecb ("arm64: Work around Falkor erratum 1009")
    eab43e88734f ("arm64: cpufeature: Cleanup feature bit tables")
    eeb1efbcb83c ("arm64: cpu_errata: Add capability to advertise Cortex-A73 erratum 858921")
    f31deaadff0d ("arm64: cpufeature: Don't enforce system-wide SPE capability")
    fe4fbdbcddea ("arm64: cpufeature: Track user visible fields")

v4.4.236: Failed to apply! Possible dependencies:
    06282fd2c2bf ("arm64: KVM: Implement vgic-v2 save/restore")
    0e9884fe63c6 ("arm64: sysreg: subsume GICv3 sysreg definitions")
    1b8e83c04ee2 ("arm64: KVM: vgic-v3: Avoid accessing ICH registers")
    2d81d425b6d5 ("irqchip/gicv3-its: Introduce two helper functions for accessing BASERn")
    328191c05ed7 ("irqchip/gic-v3-its: Specialise flush_dcache operation")
    3a949f4c9354 ("KVM: arm64: Rename HSR to ESR")
    3c13b8f435ac ("KVM: arm/arm64: vgic-v3: Make the LR indexing macro public")
    3faf24ea894a ("irqchip/gicv3-its: Implement two-level(indirect) device table support")
    466b7d168881 ("irqchip/gicv3-its: Don't allow devices whose ID is outside range")
    4b75c4598b5b ("irqchip/gicv3-its: Add a new function for parsing device table BASERn")
    5c37f1ae1c33 ("KVM: arm64: Ask the compiler to __always_inline functions used at HYP")
    91ef84428a86 ("irqchip/gic-v3: Reset BPR during initialization")
    9347359ad0ae ("irqchip/gicv3-its: Split its_alloc_tables() into two functions")
    b5525ce898eb ("arm64: KVM: Move GIC accessors to arch_gicv3.h")
    c76a0a6695c6 ("arm64: KVM: Add a HYP-specific header file")
    d44ffa5ae70a ("irqchip/gic-v3: Convert arm64 GIC accessors to {read,write}_sysreg_s")
    f68d2b1b73cc ("arm64: KVM: Implement vgic-v3 save/restore")
    fd451b90e78c ("arm64: KVM: vgic-v3: Restore ICH_APR0Rn_EL2 before ICH_APR1Rn_EL2")


NOTE: The patch will not be queued to stable trees until it is upstream.

How should we proceed with this patch?

-- 
Thanks
Sasha

Patch

diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index 49a55be2b9a2..4f618af660ba 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -298,7 +298,7 @@  static __always_inline int kvm_vcpu_dabt_get_rd(const struct kvm_vcpu *vcpu)
 	return (kvm_vcpu_get_esr(vcpu) & ESR_ELx_SRT_MASK) >> ESR_ELx_SRT_SHIFT;
 }
 
-static __always_inline bool kvm_vcpu_dabt_iss1tw(const struct kvm_vcpu *vcpu)
+static __always_inline bool kvm_vcpu_abt_iss1tw(const struct kvm_vcpu *vcpu)
 {
 	return !!(kvm_vcpu_get_esr(vcpu) & ESR_ELx_S1PTW);
 }
@@ -306,7 +306,7 @@  static __always_inline bool kvm_vcpu_dabt_iss1tw(const struct kvm_vcpu *vcpu)
 static __always_inline bool kvm_vcpu_dabt_iswrite(const struct kvm_vcpu *vcpu)
 {
 	return !!(kvm_vcpu_get_esr(vcpu) & ESR_ELx_WNR) ||
-		kvm_vcpu_dabt_iss1tw(vcpu); /* AF/DBM update */
+		kvm_vcpu_abt_iss1tw(vcpu); /* AF/DBM update */
 }
 
 static inline bool kvm_vcpu_dabt_is_cm(const struct kvm_vcpu *vcpu)
@@ -335,6 +335,11 @@  static inline bool kvm_vcpu_trap_is_iabt(const struct kvm_vcpu *vcpu)
 	return kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_IABT_LOW;
 }
 
+static inline bool kvm_vcpu_trap_is_exec_fault(const struct kvm_vcpu *vcpu)
+{
+	return kvm_vcpu_trap_is_iabt(vcpu) && !kvm_vcpu_abt_iss1tw(vcpu);
+}
+
 static __always_inline u8 kvm_vcpu_trap_get_fault(const struct kvm_vcpu *vcpu)
 {
 	return kvm_vcpu_get_esr(vcpu) & ESR_ELx_FSC;
@@ -372,6 +377,9 @@  static __always_inline int kvm_vcpu_sys_get_rt(struct kvm_vcpu *vcpu)
 
 static inline bool kvm_is_write_fault(struct kvm_vcpu *vcpu)
 {
+	if (kvm_vcpu_abt_iss1tw(vcpu))
+		return true;
+
 	if (kvm_vcpu_trap_is_iabt(vcpu))
 		return false;
 
diff --git a/arch/arm64/kvm/hyp/include/hyp/switch.h b/arch/arm64/kvm/hyp/include/hyp/switch.h
index 426ef65601dd..d64c5d56c860 100644
--- a/arch/arm64/kvm/hyp/include/hyp/switch.h
+++ b/arch/arm64/kvm/hyp/include/hyp/switch.h
@@ -445,7 +445,7 @@  static inline bool fixup_guest_exit(struct kvm_vcpu *vcpu, u64 *exit_code)
 			kvm_vcpu_trap_get_fault_type(vcpu) == FSC_FAULT &&
 			kvm_vcpu_dabt_isvalid(vcpu) &&
 			!kvm_vcpu_abt_issea(vcpu) &&
-			!kvm_vcpu_dabt_iss1tw(vcpu);
+			!kvm_vcpu_abt_iss1tw(vcpu);
 
 		if (valid) {
 			int ret = __vgic_v2_perform_cpuif_access(vcpu);
diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
index f58d657a898d..9aec1ce491d2 100644
--- a/arch/arm64/kvm/mmu.c
+++ b/arch/arm64/kvm/mmu.c
@@ -1843,7 +1843,7 @@  static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
 	struct kvm_s2_mmu *mmu = vcpu->arch.hw_mmu;
 
 	write_fault = kvm_is_write_fault(vcpu);
-	exec_fault = kvm_vcpu_trap_is_iabt(vcpu);
+	exec_fault = kvm_vcpu_trap_is_exec_fault(vcpu);
 	VM_BUG_ON(write_fault && exec_fault);
 
 	if (fault_status == FSC_PERM && !write_fault && !exec_fault) {
@@ -2125,7 +2125,7 @@  int kvm_handle_guest_abort(struct kvm_vcpu *vcpu)
 			goto out;
 		}
 
-		if (kvm_vcpu_dabt_iss1tw(vcpu)) {
+		if (kvm_vcpu_abt_iss1tw(vcpu)) {
 			kvm_inject_dabt(vcpu, kvm_vcpu_get_hfar(vcpu));
 			ret = 1;
 			goto out_unlock;