Skip to content

Commit 83bbb8f

Browse files
committed
Merge tag 'kvmarm-fixes-5.10-5' of git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm into HEAD
kvm/arm64 fixes for 5.10, take #5 - Don't leak page tables on PTE update - Correctly invalidate TLBs on table to block transition - Only update permissions if the fault level matches the expected mapping size
2 parents 339f5a7 + 7d89483 commit 83bbb8f

File tree

4 files changed

+31
-3
lines changed

4 files changed

+31
-3
lines changed

arch/arm64/include/asm/esr.h

+1
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@
104104
/* Shared ISS fault status code(IFSC/DFSC) for Data/Instruction aborts */
105105
#define ESR_ELx_FSC (0x3F)
106106
#define ESR_ELx_FSC_TYPE (0x3C)
107+
#define ESR_ELx_FSC_LEVEL (0x03)
107108
#define ESR_ELx_FSC_EXTABT (0x10)
108109
#define ESR_ELx_FSC_SERROR (0x11)
109110
#define ESR_ELx_FSC_ACCESS (0x08)

arch/arm64/include/asm/kvm_emulate.h

+5
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,11 @@ static __always_inline u8 kvm_vcpu_trap_get_fault_type(const struct kvm_vcpu *vc
350350
return kvm_vcpu_get_esr(vcpu) & ESR_ELx_FSC_TYPE;
351351
}
352352

353+
static __always_inline u8 kvm_vcpu_trap_get_fault_level(const struct kvm_vcpu *vcpu)
354+
{
355+
return kvm_vcpu_get_esr(vcpu) & ESR_ELx_FSC_LEVEL;
356+
}
357+
353358
static __always_inline bool kvm_vcpu_abt_issea(const struct kvm_vcpu *vcpu)
354359
{
355360
switch (kvm_vcpu_trap_get_fault(vcpu)) {

arch/arm64/kvm/hyp/pgtable.c

+16-1
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,15 @@ static bool stage2_map_walker_try_leaf(u64 addr, u64 end, u32 level,
470470
if (!kvm_block_mapping_supported(addr, end, phys, level))
471471
return false;
472472

473+
/*
474+
* If the PTE was already valid, drop the refcount on the table
475+
* early, as it will be bumped-up again in stage2_map_walk_leaf().
476+
* This ensures that the refcount stays constant across a valid to
477+
* valid PTE update.
478+
*/
479+
if (kvm_pte_valid(*ptep))
480+
put_page(virt_to_page(ptep));
481+
473482
if (kvm_set_valid_leaf_pte(ptep, phys, data->attr, level))
474483
goto out;
475484

@@ -493,7 +502,13 @@ static int stage2_map_walk_table_pre(u64 addr, u64 end, u32 level,
493502
return 0;
494503

495504
kvm_set_invalid_pte(ptep);
496-
kvm_call_hyp(__kvm_tlb_flush_vmid_ipa, data->mmu, addr, 0);
505+
506+
/*
507+
* Invalidate the whole stage-2, as we may have numerous leaf
508+
* entries below us which would otherwise need invalidating
509+
* individually.
510+
*/
511+
kvm_call_hyp(__kvm_tlb_flush_vmid, data->mmu);
497512
data->anchor = ptep;
498513
return 0;
499514
}

arch/arm64/kvm/mmu.c

+9-2
Original file line numberDiff line numberDiff line change
@@ -754,10 +754,12 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
754754
gfn_t gfn;
755755
kvm_pfn_t pfn;
756756
bool logging_active = memslot_is_logging(memslot);
757-
unsigned long vma_pagesize;
757+
unsigned long fault_level = kvm_vcpu_trap_get_fault_level(vcpu);
758+
unsigned long vma_pagesize, fault_granule;
758759
enum kvm_pgtable_prot prot = KVM_PGTABLE_PROT_R;
759760
struct kvm_pgtable *pgt;
760761

762+
fault_granule = 1UL << ARM64_HW_PGTABLE_LEVEL_SHIFT(fault_level);
761763
write_fault = kvm_is_write_fault(vcpu);
762764
exec_fault = kvm_vcpu_trap_is_exec_fault(vcpu);
763765
VM_BUG_ON(write_fault && exec_fault);
@@ -896,7 +898,12 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
896898
else if (cpus_have_const_cap(ARM64_HAS_CACHE_DIC))
897899
prot |= KVM_PGTABLE_PROT_X;
898900

899-
if (fault_status == FSC_PERM && !(logging_active && writable)) {
901+
/*
902+
* Under the premise of getting a FSC_PERM fault, we just need to relax
903+
* permissions only if vma_pagesize equals fault_granule. Otherwise,
904+
* kvm_pgtable_stage2_map() should be called to change block size.
905+
*/
906+
if (fault_status == FSC_PERM && vma_pagesize == fault_granule) {
900907
ret = kvm_pgtable_stage2_relax_perms(pgt, fault_ipa, prot);
901908
} else {
902909
ret = kvm_pgtable_stage2_map(pgt, fault_ipa, vma_pagesize,

0 commit comments

Comments
 (0)