Skip to content

Commit b757b47

Browse files
willdeaconMarc Zyngier
authored andcommitted
KVM: arm64: Don't inherit exec permission across page-table levels
If a stage-2 page-table contains an executable, read-only mapping at the pte level (e.g. due to dirty logging being enabled), a subsequent write fault to the same page which tries to install a larger block mapping (e.g. due to dirty logging having been disabled) will erroneously inherit the exec permission and consequently skip I-cache invalidation for the rest of the block. Ensure that exec permission is only inherited by write faults when the new mapping is of the same size as the existing one. A subsequent instruction abort will result in I-cache invalidation for the entire block mapping. Signed-off-by: Will Deacon <[email protected]> Signed-off-by: Marc Zyngier <[email protected]> Tested-by: Quentin Perret <[email protected]> Reviewed-by: Quentin Perret <[email protected]> Cc: Marc Zyngier <[email protected]> Cc: <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent bf4086b commit b757b47

File tree

1 file changed

+6
-5
lines changed

1 file changed

+6
-5
lines changed

arch/arm64/kvm/mmu.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1326,7 +1326,7 @@ static bool stage2_get_leaf_entry(struct kvm *kvm, phys_addr_t addr,
13261326
return true;
13271327
}
13281328

1329-
static bool stage2_is_exec(struct kvm *kvm, phys_addr_t addr)
1329+
static bool stage2_is_exec(struct kvm *kvm, phys_addr_t addr, unsigned long sz)
13301330
{
13311331
pud_t *pudp;
13321332
pmd_t *pmdp;
@@ -1338,11 +1338,11 @@ static bool stage2_is_exec(struct kvm *kvm, phys_addr_t addr)
13381338
return false;
13391339

13401340
if (pudp)
1341-
return kvm_s2pud_exec(pudp);
1341+
return sz <= PUD_SIZE && kvm_s2pud_exec(pudp);
13421342
else if (pmdp)
1343-
return kvm_s2pmd_exec(pmdp);
1343+
return sz <= PMD_SIZE && kvm_s2pmd_exec(pmdp);
13441344
else
1345-
return kvm_s2pte_exec(ptep);
1345+
return sz == PAGE_SIZE && kvm_s2pte_exec(ptep);
13461346
}
13471347

13481348
static int stage2_set_pte(struct kvm *kvm, struct kvm_mmu_memory_cache *cache,
@@ -1958,7 +1958,8 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
19581958
* execute permissions, and we preserve whatever we have.
19591959
*/
19601960
needs_exec = exec_fault ||
1961-
(fault_status == FSC_PERM && stage2_is_exec(kvm, fault_ipa));
1961+
(fault_status == FSC_PERM &&
1962+
stage2_is_exec(kvm, fault_ipa, vma_pagesize));
19621963

19631964
if (vma_pagesize == PUD_SIZE) {
19641965
pud_t new_pud = kvm_pfn_pud(pfn, mem_type);

0 commit comments

Comments
 (0)