KVM: arm64: Disable privileged hypercalls after pKVM finalisation
[linux-block.git] / arch / arm64 / kvm / hyp / nvhe / hyp-main.c
index 2da6aa8da8680d1e6c17415e0ee16d13fd26d3bc..8566805ef62c3e576c8ed7047e866d1cdb982914 100644 (file)
@@ -165,36 +165,51 @@ typedef void (*hcall_t)(struct kvm_cpu_context *);
 #define HANDLE_FUNC(x) [__KVM_HOST_SMCCC_FUNC_##x] = (hcall_t)handle_##x
 
 static const hcall_t host_hcall[] = {
-       HANDLE_FUNC(__kvm_vcpu_run),
+       /* ___kvm_hyp_init */
+       HANDLE_FUNC(__kvm_get_mdcr_el2),
+       HANDLE_FUNC(__pkvm_init),
+       HANDLE_FUNC(__pkvm_create_private_mapping),
+       HANDLE_FUNC(__pkvm_cpu_set_vector),
+       HANDLE_FUNC(__kvm_enable_ssbs),
+       HANDLE_FUNC(__vgic_v3_init_lrs),
+       HANDLE_FUNC(__vgic_v3_get_gic_config),
+       HANDLE_FUNC(__pkvm_prot_finalize),
+
+       HANDLE_FUNC(__pkvm_host_share_hyp),
        HANDLE_FUNC(__kvm_adjust_pc),
+       HANDLE_FUNC(__kvm_vcpu_run),
        HANDLE_FUNC(__kvm_flush_vm_context),
        HANDLE_FUNC(__kvm_tlb_flush_vmid_ipa),
        HANDLE_FUNC(__kvm_tlb_flush_vmid),
        HANDLE_FUNC(__kvm_flush_cpu_context),
        HANDLE_FUNC(__kvm_timer_set_cntvoff),
-       HANDLE_FUNC(__kvm_enable_ssbs),
-       HANDLE_FUNC(__vgic_v3_get_gic_config),
        HANDLE_FUNC(__vgic_v3_read_vmcr),
        HANDLE_FUNC(__vgic_v3_write_vmcr),
-       HANDLE_FUNC(__vgic_v3_init_lrs),
-       HANDLE_FUNC(__kvm_get_mdcr_el2),
        HANDLE_FUNC(__vgic_v3_save_aprs),
        HANDLE_FUNC(__vgic_v3_restore_aprs),
-       HANDLE_FUNC(__pkvm_init),
-       HANDLE_FUNC(__pkvm_cpu_set_vector),
-       HANDLE_FUNC(__pkvm_host_share_hyp),
-       HANDLE_FUNC(__pkvm_create_private_mapping),
-       HANDLE_FUNC(__pkvm_prot_finalize),
 };
 
 static void handle_host_hcall(struct kvm_cpu_context *host_ctxt)
 {
        DECLARE_REG(unsigned long, id, host_ctxt, 0);
+       unsigned long hcall_min = 0;
        hcall_t hfn;
 
+       /*
+        * If pKVM has been initialised then reject any calls to the
+        * early "privileged" hypercalls. Note that we cannot reject
+        * calls to __pkvm_prot_finalize for two reasons: (1) The static
+        * key used to determine initialisation must be toggled prior to
+        * finalisation and (2) finalisation is performed on a per-CPU
+        * basis. This is all fine, however, since __pkvm_prot_finalize
+        * returns -EPERM after the first call for a given CPU.
+        */
+       if (static_branch_unlikely(&kvm_protected_mode_initialized))
+               hcall_min = __KVM_HOST_SMCCC_FUNC___pkvm_prot_finalize;
+
        id -= KVM_HOST_SMCCC_ID(0);
 
-       if (unlikely(id >= ARRAY_SIZE(host_hcall)))
+       if (unlikely(id < hcall_min || id >= ARRAY_SIZE(host_hcall)))
                goto inval;
 
        hfn = host_hcall[id];