diff --git a/arch/arm64/kvm/hyp/nvhe/mem_protect.c b/arch/arm64/kvm/hyp/nvhe/mem_protect.c index 905e50f2d49e..9f71e226d95f 100644 --- a/arch/arm64/kvm/hyp/nvhe/mem_protect.c +++ b/arch/arm64/kvm/hyp/nvhe/mem_protect.c @@ -2027,12 +2027,12 @@ static int restrict_host_page_perms(u64 addr, kvm_pte_t pte, u32 level, enum kvm int module_change_host_page_prot(u64 pfn, enum kvm_pgtable_prot prot) { u64 addr = hyp_pfn_to_phys(pfn); - struct hyp_page *page; + struct hyp_page *page = NULL; kvm_pte_t pte; u32 level; int ret; - if ((prot & KVM_PGTABLE_PROT_RWX) != prot || !addr_is_memory(addr)) + if ((prot & KVM_PGTABLE_PROT_RWX) != prot) return -EINVAL; host_lock_component(); @@ -2040,6 +2040,14 @@ int module_change_host_page_prot(u64 pfn, enum kvm_pgtable_prot prot) if (ret) goto unlock; + /* + * There is no hyp_vmemmap covering MMIO regions, which makes tracking + * of module-owned MMIO regions hard, so we trust the modules not to + * mess things up. + */ + if (!addr_is_memory(addr)) + goto update; + ret = -EPERM; page = hyp_phys_to_page(addr); @@ -2054,14 +2062,15 @@ int module_change_host_page_prot(u64 pfn, enum kvm_pgtable_prot prot) goto unlock; } - if (prot == KVM_PGTABLE_PROT_RWX) +update: + if (prot == default_host_prot(!!page)) ret = host_stage2_set_owner_locked(addr, PAGE_SIZE, PKVM_ID_HOST); else if (!prot) ret = host_stage2_set_owner_locked(addr, PAGE_SIZE, PKVM_ID_PROTECTED); else ret = restrict_host_page_perms(addr, pte, level, prot); - if (ret) + if (ret || !page) goto unlock; if (prot != KVM_PGTABLE_PROT_RWX)