mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git/
synced 2026-04-07 09:17:44 -04:00
KVM: arm64: Adjust range correctly during host stage-2 faults
host_stage2_adjust_range() tries to find the largest block mapping that
fits within a memory or mmio region (represented by a kvm_mem_range in
this function) during host stage-2 faults under pKVM. To do so, it walks
the host stage-2 page-table, finds the faulting PTE and its level, and
then progressively increments the level until it finds a granule of the
appropriate size. However, the condition in the loop implementing the
above is broken as it checks kvm_level_supports_block_mapping() for the
next level instead of the current, so pKVM may attempt to map a region
larger than can be covered with a single block.
This is not a security problem and is quite rare in practice (the
kvm_mem_range check usually forces host_stage2_adjust_range() to choose a
smaller granule), but this is clearly not the expected behaviour.
Refactor the loop to fix the bug and improve readability.
Fixes: c4f0935e4d ("KVM: arm64: Optimize host memory aborts")
Signed-off-by: Quentin Perret <qperret@google.com>
Link: https://lore.kernel.org/r/20250625105548.984572-1-qperret@google.com
Signed-off-by: Marc Zyngier <maz@kernel.org>
This commit is contained in:
committed by
Marc Zyngier
parent
af040a9a29
commit
e728e70580
@@ -479,6 +479,7 @@ static int host_stage2_adjust_range(u64 addr, struct kvm_mem_range *range)
|
||||
{
|
||||
struct kvm_mem_range cur;
|
||||
kvm_pte_t pte;
|
||||
u64 granule;
|
||||
s8 level;
|
||||
int ret;
|
||||
|
||||
@@ -496,18 +497,21 @@ static int host_stage2_adjust_range(u64 addr, struct kvm_mem_range *range)
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
do {
|
||||
u64 granule = kvm_granule_size(level);
|
||||
for (; level <= KVM_PGTABLE_LAST_LEVEL; level++) {
|
||||
if (!kvm_level_supports_block_mapping(level))
|
||||
continue;
|
||||
granule = kvm_granule_size(level);
|
||||
cur.start = ALIGN_DOWN(addr, granule);
|
||||
cur.end = cur.start + granule;
|
||||
level++;
|
||||
} while ((level <= KVM_PGTABLE_LAST_LEVEL) &&
|
||||
!(kvm_level_supports_block_mapping(level) &&
|
||||
range_included(&cur, range)));
|
||||
if (!range_included(&cur, range))
|
||||
continue;
|
||||
*range = cur;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*range = cur;
|
||||
WARN_ON(1);
|
||||
|
||||
return 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int host_stage2_idmap_locked(phys_addr_t addr, u64 size,
|
||||
|
||||
Reference in New Issue
Block a user