When kdump is used to capture system memory after a panic(), any secret keys currently in RAM end up in the dump. Add an opt-in atomic notifier chain, crash_wipe_secrets_notifier_list, invoked late into __crash_kexec(). Subsystems holding secrets can register a callback to wipe them. Callbacks are run after machine_crash_shutdown() has already stopped the other CPUs and disabled preemption. Callbacks must not wait on locks, which will never be released. This is a best-effort, defence-in-depth measure, not a guarantee. Secrets in flight on the stack, in registers, in DMA buffers, or in other places in memory are out of scope. Signed-off-by: Jan Sebastian Götte --- include/linux/crash_core.h | 16 ++++++++++++++++ kernel/Kconfig.kexec | 16 ++++++++++++++++ kernel/crash_core.c | 29 +++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+) diff --git a/include/linux/crash_core.h b/include/linux/crash_core.h index bc087124cd78..4230463f3faa 100644 --- a/include/linux/crash_core.h +++ b/include/linux/crash_core.h @@ -5,6 +5,7 @@ #include #include #include +#include struct kimage; @@ -34,6 +35,21 @@ static inline void arch_kexec_protect_crashkres(void) { } static inline void arch_kexec_unprotect_crashkres(void) { } #endif +#ifdef CONFIG_CRASH_WIPE_SECRETS +int crash_wipe_secrets_register(struct notifier_block *nb); +int crash_wipe_secrets_unregister(struct notifier_block *nb); +#else +static inline int crash_wipe_secrets_register(struct notifier_block *nb) +{ + return 0; +} + +static inline int crash_wipe_secrets_unregister(struct notifier_block *nb) +{ + return 0; +} +#endif + #ifndef arch_crash_handle_hotplug_event static inline void arch_crash_handle_hotplug_event(struct kimage *image, void *arg) { } #endif diff --git a/kernel/Kconfig.kexec b/kernel/Kconfig.kexec index 15632358bcf7..1d2d273145df 100644 --- a/kernel/Kconfig.kexec +++ b/kernel/Kconfig.kexec @@ -179,4 +179,20 @@ config CRASH_MAX_MEMORY_RANGES the computation behind the value provided through the /sys/kernel/crash_elfcorehdr_size attribute. +config CRASH_WIPE_SECRETS + bool "Wipe secrets before kdump" + depends on CRASH_DUMP + help + Wipe secrets (e.g. kernel keyring and memfd_secret pages) on crash or + panic. This is a best effort, defense-in-depth feature: If the panic + happens at a really bad time, or if copies of the secrets are present + in places like on the stack, in I/O buffers, or in userspace memory + not allocated through memfd_secret, they may still be leaked. + + Note that enabling this feature carries some risk of crashing the + system during the wipe process if the kernel was already unstable + when the panic happened. + + If unsure, say N. + endmenu diff --git a/kernel/crash_core.c b/kernel/crash_core.c index 2b36aa9fade0..95f5c0415e60 100644 --- a/kernel/crash_core.c +++ b/kernel/crash_core.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -33,6 +34,33 @@ /* Per cpu memory for storing cpu states in case of system crash. */ note_buf_t __percpu *crash_notes; +#ifdef CONFIG_CRASH_WIPE_SECRETS +ATOMIC_NOTIFIER_HEAD(crash_wipe_secrets_notifier_list); + +int crash_wipe_secrets_register(struct notifier_block *nb) +{ + return atomic_notifier_chain_register( + &crash_wipe_secrets_notifier_list, nb); +} +EXPORT_SYMBOL_GPL(crash_wipe_secrets_register); + +int crash_wipe_secrets_unregister(struct notifier_block *nb) +{ + return atomic_notifier_chain_unregister( + &crash_wipe_secrets_notifier_list, nb); +} +EXPORT_SYMBOL_GPL(crash_wipe_secrets_unregister); + +static void crash_wipe_secrets(void) +{ + pr_info("Wiping sensitive secrets...\n"); + atomic_notifier_call_chain(&crash_wipe_secrets_notifier_list, 0, NULL); + pr_info("Done wiping secrets.\n"); +} +#else +static inline void crash_wipe_secrets(void) { } +#endif /* CONFIG_CRASH_WIPE_SECRETS */ + /* time to wait for possible DMA to finish before starting the kdump kernel * when a CMA reservation is used */ @@ -142,6 +170,7 @@ void __noclone __crash_kexec(struct pt_regs *regs) crash_save_vmcoreinfo(); machine_crash_shutdown(&fixed_regs); crash_cma_clear_pending_dma(); + crash_wipe_secrets(); machine_kexec(kexec_crash_image); } kexec_unlock(); -- 2.53.0