KVM: arm64: Reject stub hypercalls after pKVM has been initialised
authorWill Deacon <will@kernel.org>
Fri, 8 Oct 2021 13:58:36 +0000 (14:58 +0100)
committerMarc Zyngier <maz@kernel.org>
Mon, 11 Oct 2021 08:07:28 +0000 (09:07 +0100)
The stub hypercalls provide mechanisms to reset and replace the EL2 code,
so uninstall them once pKVM has been initialised in order to ensure the
integrity of the hypervisor code.

To ensure pKVM initialisation remains functional, split cpu_hyp_reinit()
into two helper functions to separate usage of the stub from usage of
pkvm hypercalls either side of __pkvm_init on the boot CPU.

Cc: Marc Zyngier <maz@kernel.org>
Cc: Quentin Perret <qperret@google.com>
Signed-off-by: Will Deacon <will@kernel.org>
Signed-off-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20211008135839.1193-4-will@kernel.org
arch/arm64/kvm/arm.c
arch/arm64/kvm/hyp/nvhe/host.S

index fe102cd..9506cf8 100644 (file)
@@ -1579,25 +1579,33 @@ static void cpu_set_hyp_vector(void)
                kvm_call_hyp_nvhe(__pkvm_cpu_set_vector, data->slot);
 }
 
-static void cpu_hyp_reinit(void)
+static void cpu_hyp_init_context(void)
 {
        kvm_init_host_cpu_context(&this_cpu_ptr_hyp_sym(kvm_host_data)->host_ctxt);
 
-       cpu_hyp_reset();
-
-       if (is_kernel_in_hyp_mode())
-               kvm_timer_init_vhe();
-       else
+       if (!is_kernel_in_hyp_mode())
                cpu_init_hyp_mode();
+}
 
+static void cpu_hyp_init_features(void)
+{
        cpu_set_hyp_vector();
-
        kvm_arm_init_debug();
 
+       if (is_kernel_in_hyp_mode())
+               kvm_timer_init_vhe();
+
        if (vgic_present)
                kvm_vgic_init_cpu_hardware();
 }
 
+static void cpu_hyp_reinit(void)
+{
+       cpu_hyp_reset();
+       cpu_hyp_init_context();
+       cpu_hyp_init_features();
+}
+
 static void _kvm_arch_hardware_enable(void *discard)
 {
        if (!__this_cpu_read(kvm_arm_hardware_enabled)) {
@@ -1788,10 +1796,17 @@ static int do_pkvm_init(u32 hyp_va_bits)
        int ret;
 
        preempt_disable();
-       hyp_install_host_vector();
+       cpu_hyp_init_context();
        ret = kvm_call_hyp_nvhe(__pkvm_init, hyp_mem_base, hyp_mem_size,
                                num_possible_cpus(), kern_hyp_va(per_cpu_base),
                                hyp_va_bits);
+       cpu_hyp_init_features();
+
+       /*
+        * The stub hypercalls are now disabled, so set our local flag to
+        * prevent a later re-init attempt in kvm_arch_hardware_enable().
+        */
+       __this_cpu_write(kvm_arm_hardware_enabled, 1);
        preempt_enable();
 
        return ret;
index 4b652ff..0c6116d 100644 (file)
@@ -110,17 +110,14 @@ SYM_FUNC_START(__hyp_do_panic)
        b       __host_enter_for_panic
 SYM_FUNC_END(__hyp_do_panic)
 
-.macro host_el1_sync_vect
-       .align 7
-.L__vect_start\@:
-       stp     x0, x1, [sp, #-16]!
-       mrs     x0, esr_el2
-       lsr     x0, x0, #ESR_ELx_EC_SHIFT
-       cmp     x0, #ESR_ELx_EC_HVC64
-       b.ne    __host_exit
-
+SYM_FUNC_START(__host_hvc)
        ldp     x0, x1, [sp]            // Don't fixup the stack yet
 
+       /* No stub for you, sonny Jim */
+alternative_if ARM64_KVM_PROTECTED_MODE
+       b       __host_exit
+alternative_else_nop_endif
+
        /* Check for a stub HVC call */
        cmp     x0, #HVC_STUB_HCALL_NR
        b.hs    __host_exit
@@ -137,6 +134,17 @@ SYM_FUNC_END(__hyp_do_panic)
        ldr     x5, =__kvm_handle_stub_hvc
        hyp_pa  x5, x6
        br      x5
+SYM_FUNC_END(__host_hvc)
+
+.macro host_el1_sync_vect
+       .align 7
+.L__vect_start\@:
+       stp     x0, x1, [sp, #-16]!
+       mrs     x0, esr_el2
+       lsr     x0, x0, #ESR_ELx_EC_SHIFT
+       cmp     x0, #ESR_ELx_EC_HVC64
+       b.eq    __host_hvc
+       b       __host_exit
 .L__vect_end\@:
 .if ((.L__vect_end\@ - .L__vect_start\@) > 0x80)
        .error "host_el1_sync_vect larger than vector entry"