ANDROID: KVM: arm64: Block module loading based on cmdline or HVC
Disable module loading, based on the cmdline option kvm-arm.protected_modules. If enabled, the feature can later be irreversibly disabled with the HVC __pkvm_close_module_registration(). Bug: 357781595 Bug: 244543039 Bug: 244373730 Change-Id: I693a1db350ae15bcaab59103a68b60f087dcc6b4 Signed-off-by: Vincent Donnefort <vdonnefort@google.com> Signed-off-by: Quentin Perret <qperret@google.com>
This commit is contained in:
committed by
Keir Fraser
parent
a871b30b2d
commit
7089457a75
@@ -66,10 +66,6 @@ enum __kvm_host_smccc_func {
|
||||
__KVM_HOST_SMCCC_FUNC___kvm_tlb_flush_vmid,
|
||||
__KVM_HOST_SMCCC_FUNC___kvm_tlb_flush_vmid_range,
|
||||
__KVM_HOST_SMCCC_FUNC___kvm_flush_cpu_context,
|
||||
__KVM_HOST_SMCCC_FUNC___pkvm_alloc_module_va,
|
||||
__KVM_HOST_SMCCC_FUNC___pkvm_map_module_page,
|
||||
__KVM_HOST_SMCCC_FUNC___pkvm_unmap_module_page,
|
||||
__KVM_HOST_SMCCC_FUNC___pkvm_init_module,
|
||||
__KVM_HOST_SMCCC_FUNC___pkvm_prot_finalize,
|
||||
|
||||
/* Hypercalls available after pKVM finalisation */
|
||||
@@ -98,6 +94,11 @@ enum __kvm_host_smccc_func {
|
||||
__KVM_HOST_SMCCC_FUNC___pkvm_enable_event,
|
||||
__KVM_HOST_SMCCC_FUNC___pkvm_selftest_event,
|
||||
__KVM_HOST_SMCCC_FUNC___pkvm_register_hcall,
|
||||
__KVM_HOST_SMCCC_FUNC___pkvm_alloc_module_va,
|
||||
__KVM_HOST_SMCCC_FUNC___pkvm_map_module_page,
|
||||
__KVM_HOST_SMCCC_FUNC___pkvm_unmap_module_page,
|
||||
__KVM_HOST_SMCCC_FUNC___pkvm_init_module,
|
||||
__KVM_HOST_SMCCC_FUNC___pkvm_close_module_registration,
|
||||
|
||||
/*
|
||||
* Start of the dynamically registered hypercalls. Start a bit
|
||||
|
||||
@@ -147,4 +147,7 @@ extern u64 kvm_nvhe_sym(id_aa64smfr0_el1_sys_val);
|
||||
extern unsigned long kvm_nvhe_sym(__icache_flags);
|
||||
extern unsigned int kvm_nvhe_sym(kvm_arm_vmid_bits);
|
||||
extern unsigned int kvm_nvhe_sym(kvm_host_sve_max_vl);
|
||||
|
||||
extern bool kvm_nvhe_sym(__pkvm_modules_enabled);
|
||||
|
||||
#endif /* __ARM64_KVM_HYP_H__ */
|
||||
|
||||
@@ -7,6 +7,10 @@
|
||||
int __pkvm_init_module(void *module_init);
|
||||
int __pkvm_register_hcall(unsigned long hfn_hyp_va);
|
||||
int handle_host_dynamic_hcall(struct kvm_cpu_context *host_ctxt);
|
||||
void pkvm_modules_lock(void);
|
||||
void pkvm_modules_unlock(void);
|
||||
bool pkvm_modules_enabled(void);
|
||||
int __pkvm_close_module_registration(void);
|
||||
#else
|
||||
static inline int __pkvm_init_module(void *module_init) { return -EOPNOTSUPP; }
|
||||
static inline int
|
||||
@@ -15,4 +19,8 @@ static inline int handle_host_dynamic_hcall(struct kvm_cpu_context *host_ctxt)
|
||||
{
|
||||
return HCALL_UNHANDLED;
|
||||
}
|
||||
static inline void pkvm_modules_lock(void) { }
|
||||
static inline void pkvm_modules_unlock(void) { }
|
||||
static inline bool pkvm_modules_enabled(void) { return false; }
|
||||
static inline int __pkvm_close_module_registration(void) { return -EOPNOTSUPP; }
|
||||
#endif
|
||||
|
||||
@@ -1318,6 +1318,12 @@ static void handle___pkvm_register_hcall(struct kvm_cpu_context *host_ctxt)
|
||||
cpu_reg(host_ctxt, 1) = __pkvm_register_hcall(hfn_hyp_va);
|
||||
}
|
||||
|
||||
static void
|
||||
handle___pkvm_close_module_registration(struct kvm_cpu_context *host_ctxt)
|
||||
{
|
||||
cpu_reg(host_ctxt, 1) = __pkvm_close_module_registration();
|
||||
}
|
||||
|
||||
typedef void (*hcall_t)(struct kvm_cpu_context *);
|
||||
|
||||
#define HANDLE_FUNC(x) [__KVM_HOST_SMCCC_FUNC_##x] = (hcall_t)handle_##x
|
||||
@@ -1368,6 +1374,7 @@ static const hcall_t host_hcall[] = {
|
||||
HANDLE_FUNC(__pkvm_unmap_module_page),
|
||||
HANDLE_FUNC(__pkvm_init_module),
|
||||
HANDLE_FUNC(__pkvm_register_hcall),
|
||||
HANDLE_FUNC(__pkvm_close_module_registration),
|
||||
};
|
||||
|
||||
static void handle_host_hcall(struct kvm_cpu_context *host_ctxt)
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <nvhe/memory.h>
|
||||
#include <nvhe/mem_protect.h>
|
||||
#include <nvhe/mm.h>
|
||||
#include <nvhe/modules.h>
|
||||
#include <nvhe/spinlock.h>
|
||||
|
||||
struct kvm_pgtable pkvm_pgtable;
|
||||
@@ -112,29 +113,44 @@ int __pkvm_create_private_mapping(phys_addr_t phys, size_t size,
|
||||
|
||||
void *__pkvm_alloc_module_va(u64 nr_pages)
|
||||
{
|
||||
unsigned long addr;
|
||||
int ret;
|
||||
unsigned long addr = 0;
|
||||
|
||||
ret = pkvm_alloc_private_va_range(nr_pages << PAGE_SHIFT, &addr);
|
||||
pkvm_modules_lock();
|
||||
if (pkvm_modules_enabled())
|
||||
pkvm_alloc_private_va_range(nr_pages << PAGE_SHIFT, &addr);
|
||||
pkvm_modules_unlock();
|
||||
|
||||
return ret ? NULL : (void *)addr;
|
||||
return (void *)addr;
|
||||
}
|
||||
|
||||
int __pkvm_map_module_page(u64 pfn, void *va, enum kvm_pgtable_prot prot)
|
||||
{
|
||||
int ret;
|
||||
int ret = -EACCES;
|
||||
|
||||
pkvm_modules_lock();
|
||||
|
||||
if (!pkvm_modules_enabled())
|
||||
goto err;
|
||||
|
||||
ret = __pkvm_host_donate_hyp(pfn, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto err;
|
||||
|
||||
return __pkvm_create_mappings((unsigned long)va, PAGE_SIZE, hyp_pfn_to_phys(pfn), prot);
|
||||
ret = __pkvm_create_mappings((unsigned long)va, PAGE_SIZE, hyp_pfn_to_phys(pfn), prot);
|
||||
err:
|
||||
pkvm_modules_unlock();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void __pkvm_unmap_module_page(u64 pfn, void *va)
|
||||
{
|
||||
WARN_ON(__pkvm_hyp_donate_host(pfn, 1));
|
||||
pkvm_remove_mappings(va, va + PAGE_SIZE);
|
||||
pkvm_modules_lock();
|
||||
if (pkvm_modules_enabled()) {
|
||||
WARN_ON(__pkvm_hyp_donate_host(pfn, 1));
|
||||
pkvm_remove_mappings(va, va + PAGE_SIZE);
|
||||
}
|
||||
pkvm_modules_unlock();
|
||||
}
|
||||
|
||||
int pkvm_create_mappings_locked(void *from, void *to, enum kvm_pgtable_prot prot)
|
||||
|
||||
@@ -11,6 +11,42 @@
|
||||
#include <nvhe/spinlock.h>
|
||||
#include <nvhe/trap_handler.h>
|
||||
|
||||
DEFINE_HYP_SPINLOCK(modules_lock);
|
||||
|
||||
bool __pkvm_modules_enabled __ro_after_init;
|
||||
|
||||
void pkvm_modules_lock(void)
|
||||
{
|
||||
hyp_spin_lock(&modules_lock);
|
||||
}
|
||||
|
||||
void pkvm_modules_unlock(void)
|
||||
{
|
||||
hyp_spin_unlock(&modules_lock);
|
||||
}
|
||||
|
||||
bool pkvm_modules_enabled(void)
|
||||
{
|
||||
return __pkvm_modules_enabled;
|
||||
}
|
||||
|
||||
int __pkvm_close_module_registration(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
pkvm_modules_lock();
|
||||
ret = __pkvm_modules_enabled ? 0 : -EACCES;
|
||||
if (!ret) {
|
||||
void *addr = hyp_fixmap_map(__hyp_pa(&__pkvm_modules_enabled));
|
||||
*(bool *)addr = false;
|
||||
hyp_fixmap_unmap();
|
||||
}
|
||||
pkvm_modules_unlock();
|
||||
|
||||
/* The fuse is blown! No way back until reset */
|
||||
return ret;
|
||||
}
|
||||
|
||||
const struct pkvm_module_ops module_ops = {
|
||||
.create_private_mapping = __pkvm_create_private_mapping,
|
||||
.register_serial_driver = __pkvm_register_serial_driver,
|
||||
@@ -24,7 +60,15 @@ int __pkvm_init_module(void *module_init)
|
||||
int (*do_module_init)(const struct pkvm_module_ops *ops) = module_init;
|
||||
int ret;
|
||||
|
||||
pkvm_modules_lock();
|
||||
if (!pkvm_modules_enabled()) {
|
||||
ret = -EACCES;
|
||||
goto err;
|
||||
}
|
||||
ret = do_module_init(&module_ops);
|
||||
err:
|
||||
pkvm_modules_unlock();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -72,15 +116,21 @@ end:
|
||||
int __pkvm_register_hcall(unsigned long hvn_hyp_va)
|
||||
{
|
||||
dyn_hcall_t hfn = (void *)hvn_hyp_va;
|
||||
int reserved_id;
|
||||
int reserved_id, ret;
|
||||
|
||||
pkvm_modules_lock();
|
||||
if (!pkvm_modules_enabled()) {
|
||||
ret = -EACCES;
|
||||
goto err;
|
||||
}
|
||||
|
||||
hyp_spin_lock(&dyn_hcall_lock);
|
||||
|
||||
reserved_id = atomic_read(&num_dynamic_hcalls);
|
||||
|
||||
if (reserved_id >= MAX_DYNAMIC_HCALLS) {
|
||||
hyp_spin_unlock(&dyn_hcall_lock);
|
||||
return -ENOMEM;
|
||||
ret = -ENOMEM;
|
||||
goto err_hcall_unlock;
|
||||
}
|
||||
|
||||
WRITE_ONCE(host_dynamic_hcalls[reserved_id], hfn);
|
||||
@@ -91,7 +141,11 @@ int __pkvm_register_hcall(unsigned long hvn_hyp_va)
|
||||
*/
|
||||
atomic_set_release(&num_dynamic_hcalls, reserved_id + 1);
|
||||
|
||||
ret = reserved_id + __KVM_HOST_SMCCC_FUNC___dynamic_hcalls;
|
||||
err_hcall_unlock:
|
||||
hyp_spin_unlock(&dyn_hcall_lock);
|
||||
err:
|
||||
pkvm_modules_unlock();
|
||||
|
||||
return reserved_id + __KVM_HOST_SMCCC_FUNC___dynamic_hcalls;
|
||||
return ret;
|
||||
};
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <linux/of_reserved_mem.h>
|
||||
#include <linux/sort.h>
|
||||
|
||||
#include <asm/kvm_hyp.h>
|
||||
#include <asm/kvm_mmu.h>
|
||||
#include <asm/kvm_pkvm.h>
|
||||
#include <asm/kvm_pkvm_module.h>
|
||||
@@ -480,6 +481,16 @@ int pkvm_vm_ioctl_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MODULES
|
||||
static int __init early_pkvm_enable_modules(char *arg)
|
||||
{
|
||||
kvm_nvhe_sym(__pkvm_modules_enabled) = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
early_param("kvm-arm.protected_modules", early_pkvm_enable_modules);
|
||||
#endif
|
||||
|
||||
struct pkvm_mod_sec_mapping {
|
||||
struct pkvm_module_section *sec;
|
||||
enum kvm_pgtable_prot prot;
|
||||
|
||||
Reference in New Issue
Block a user