ANDROID: KVM: arm64: Sanity check the input to pKVM module mm APIs

Now that the pKVM memory-management module APIs are exposed outside of
core pKVM, make sure to sanity check the input to
__pkvm_map_module_page() which expects a VA that was previously
allocated in the private range.

We can't easily check that each private VA page is used to map the
module it was allocated for, but we can at least check that all module
pages fall in the private range, which is still desirable to enforce
some degree of consitency. This is all best effort really.

Bug: 264070847
Change-Id: Ib95e464f57beaf0c32d15075938ca283fe52f720
Signed-off-by: Quentin Perret <qperret@google.com>
This commit is contained in:
Quentin Perret
2023-01-04 17:00:27 +00:00
parent 3c064ef0c9
commit 1feb6a8aee

View File

@@ -102,13 +102,40 @@ int __pkvm_create_private_mapping(phys_addr_t phys, size_t size,
return err;
}
#ifdef CONFIG_NVHE_EL2_DEBUG
static unsigned long mod_range_start = ULONG_MAX;
static unsigned long mod_range_end;
static void update_mod_range(unsigned long addr, size_t size)
{
mod_range_start = min(mod_range_start, addr);
mod_range_end = max(mod_range_end, addr + size);
}
static void assert_in_mod_range(unsigned long addr)
{
/*
* This is not entirely watertight if there are private range
* allocations between modules being loaded, but in practice that is
* probably going to be allocation initiated by the modules themselves.
*/
WARN_ON(addr < mod_range_start || mod_range_end <= addr);
}
#else
static inline void update_mod_range(unsigned long addr, size_t size) { }
static inline void assert_in_mod_range(unsigned long addr) { }
#endif
void *__pkvm_alloc_module_va(u64 nr_pages)
{
size_t size = nr_pages << PAGE_SHIFT;
unsigned long addr = 0;
pkvm_modules_lock();
if (pkvm_modules_enabled())
pkvm_alloc_private_va_range(nr_pages << PAGE_SHIFT, &addr);
if (pkvm_modules_enabled()) {
if (!pkvm_alloc_private_va_range(size, &addr))
update_mod_range(addr, size);
}
pkvm_modules_unlock();
return (void *)addr;
@@ -116,10 +143,13 @@ void *__pkvm_alloc_module_va(u64 nr_pages)
int __pkvm_map_module_page(u64 pfn, void *va, enum kvm_pgtable_prot prot)
{
unsigned long addr = (unsigned long)va;
int ret = -EACCES;
pkvm_modules_lock();
assert_in_mod_range(addr);
if (!pkvm_modules_enabled())
goto err;
@@ -127,7 +157,7 @@ int __pkvm_map_module_page(u64 pfn, void *va, enum kvm_pgtable_prot prot)
if (ret)
goto err;
ret = __pkvm_create_mappings((unsigned long)va, PAGE_SIZE, hyp_pfn_to_phys(pfn), prot);
ret = __pkvm_create_mappings(addr, PAGE_SIZE, hyp_pfn_to_phys(pfn), prot);
err:
pkvm_modules_unlock();