KVM: arm64: Save protected-nVHE (pKVM) hyp stacktrace
In protected nVHE mode, the host cannot access private owned hypervisor memory. Also the hypervisor aims to remains simple to reduce the attack surface and does not provide any printk support. For the above reasons, the approach taken to provide hypervisor stacktraces in protected mode is: 1) Unwind and save the hyp stack addresses in EL2 to a shared buffer with the host (done in this patch). 2) Delegate the dumping and symbolization of the addresses to the host in EL1 (later patch in the series). On hyp_panic(), the hypervisor prepares the stacktrace before returning to the host. Signed-off-by: Kalesh Singh <kaleshsingh@google.com> Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20220726073750.3219117-16-kaleshsingh@google.com
This commit is contained in:
parent
25aa73b6db
commit
871c5d9314
|
@ -35,7 +35,60 @@ static void hyp_prepare_backtrace(unsigned long fp, unsigned long pc)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PROTECTED_NVHE_STACKTRACE
|
#ifdef CONFIG_PROTECTED_NVHE_STACKTRACE
|
||||||
|
#include <asm/stacktrace/nvhe.h>
|
||||||
|
|
||||||
DEFINE_PER_CPU(unsigned long [NVHE_STACKTRACE_SIZE/sizeof(long)], pkvm_stacktrace);
|
DEFINE_PER_CPU(unsigned long [NVHE_STACKTRACE_SIZE/sizeof(long)], pkvm_stacktrace);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* pkvm_save_backtrace_entry - Saves a protected nVHE HYP stacktrace entry
|
||||||
|
*
|
||||||
|
* @arg : index of the entry in the stacktrace buffer
|
||||||
|
* @where : the program counter corresponding to the stack frame
|
||||||
|
*
|
||||||
|
* Save the return address of a stack frame to the shared stacktrace buffer.
|
||||||
|
* The host can access this shared buffer from EL1 to dump the backtrace.
|
||||||
|
*/
|
||||||
|
static bool pkvm_save_backtrace_entry(void *arg, unsigned long where)
|
||||||
|
{
|
||||||
|
unsigned long *stacktrace = this_cpu_ptr(pkvm_stacktrace);
|
||||||
|
int size = NVHE_STACKTRACE_SIZE / sizeof(long);
|
||||||
|
int *idx = (int *)arg;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Need 2 free slots: 1 for current entry and 1 for the
|
||||||
|
* delimiter.
|
||||||
|
*/
|
||||||
|
if (*idx > size - 2)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
stacktrace[*idx] = where;
|
||||||
|
stacktrace[++*idx] = 0UL;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* pkvm_save_backtrace - Saves the protected nVHE HYP stacktrace
|
||||||
|
*
|
||||||
|
* @fp : frame pointer at which to start the unwinding.
|
||||||
|
* @pc : program counter at which to start the unwinding.
|
||||||
|
*
|
||||||
|
* Save the unwinded stack addresses to the shared stacktrace buffer.
|
||||||
|
* The host can access this shared buffer from EL1 to dump the backtrace.
|
||||||
|
*/
|
||||||
|
static void pkvm_save_backtrace(unsigned long fp, unsigned long pc)
|
||||||
|
{
|
||||||
|
struct unwind_state state;
|
||||||
|
int idx = 0;
|
||||||
|
|
||||||
|
kvm_nvhe_unwind_init(&state, fp, pc);
|
||||||
|
|
||||||
|
unwind(&state, pkvm_save_backtrace_entry, &idx);
|
||||||
|
}
|
||||||
|
#else /* !CONFIG_PROTECTED_NVHE_STACKTRACE */
|
||||||
|
static void pkvm_save_backtrace(unsigned long fp, unsigned long pc)
|
||||||
|
{
|
||||||
|
}
|
||||||
#endif /* CONFIG_PROTECTED_NVHE_STACKTRACE */
|
#endif /* CONFIG_PROTECTED_NVHE_STACKTRACE */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -50,7 +103,7 @@ DEFINE_PER_CPU(unsigned long [NVHE_STACKTRACE_SIZE/sizeof(long)], pkvm_stacktrac
|
||||||
void kvm_nvhe_prepare_backtrace(unsigned long fp, unsigned long pc)
|
void kvm_nvhe_prepare_backtrace(unsigned long fp, unsigned long pc)
|
||||||
{
|
{
|
||||||
if (is_protected_kvm_enabled())
|
if (is_protected_kvm_enabled())
|
||||||
return;
|
pkvm_save_backtrace(fp, pc);
|
||||||
else
|
else
|
||||||
hyp_prepare_backtrace(fp, pc);
|
hyp_prepare_backtrace(fp, pc);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue