From 748b3c3ee098139286f6d2b95c3feb786689bc78 Mon Sep 17 00:00:00 2001 From: Coiby Xu Date: Thu, 9 Oct 2025 16:49:53 +0800 Subject: [PATCH] Support dumping to a LUKS-encrypted target Resolves: https://issues.redhat.com/browse/RHEL-104940 Conflict: Manually resolve conflict in kdumpctl and mkdumprd. Install 99kdumpbase/kexec-crypt-setup.sh in kexec-tools.spec. commit 5cbd7ddd2e164d13f2cd992373df89912fe6e79f Author: Coiby Xu Date: Mon Aug 7 15:19:36 2023 +0800 Support dumping to a LUKS-encrypted target Based on the new kernel feature that dm-crypt keys can persist for the kdump kernel [1][2], this patch which is adapted from [3] 1) ask the 1st kernel to save a copy of the LUKS volume keys 2) ask the kdump kernel to add the copy of the LUKS volume keys to specified keyring and then use --volume-key-keyring the unlock the LUKS device. Users need to set up the link-volume-key option in /etc/crypttab (man crypttab) so kdumpctl can read the key from @u::%logon:cryptsetup:UUID and instruct the kernel to save it to kdump-reserved memory. [1] https://github.com/torvalds/linux/blob/master/Documentation/admin-guide/kdump/kdump.rst#write-the-dump-file-to-encrypted-disk-volume [2] https://github.com/torvalds/linux/commit/180cf31af7c313790f1e0fba1c7aa42512144dd5 [3] https://lists.fedorahosted.org/archives/list/kexec@lists.fedoraproject.org/message/Y3KUSJQPN3JHUUC2FPIK7H4HTSX2TUCX/ Signed-off-by: Coiby Xu Signed-off-by: Coiby Xu --- dracut-kexec-crypt-setup.sh | 3 +++ dracut-module-setup.sh | 46 +++++++++++++++++++++++++++++++++++++ kdump-lib-initramfs.sh | 4 ++++ kdumpctl | 36 +++++++++++++++++++++++++++++ kexec-tools.spec | 2 ++ mkdumprd | 14 ----------- supported-kdump-targets.txt | 1 + 7 files changed, 92 insertions(+), 14 deletions(-) create mode 100644 dracut-kexec-crypt-setup.sh diff --git a/dracut-kexec-crypt-setup.sh b/dracut-kexec-crypt-setup.sh new file mode 100644 index 0000000..7d79ed5 --- /dev/null +++ b/dracut-kexec-crypt-setup.sh @@ -0,0 +1,3 @@ +#!/bin/sh +# +echo true > /sys/kernel/config/crash_dm_crypt_keys/restore diff --git a/dracut-module-setup.sh b/dracut-module-setup.sh index c32b381..2673a87 100755 --- a/dracut-module-setup.sh +++ b/dracut-module-setup.sh @@ -1145,6 +1145,50 @@ remove_cpu_online_rule() { sed -i '/SUBSYSTEM=="cpu"/d' "$file" } +kdump_check_crypt_targets() { + local _luks_dev _devuuid _key_desc + declare -a _luks_devs + + mapfile -t _luks_devs < <(get_all_kdump_crypt_dev) + + if [[ ${#_luks_devs[@]} -lt 1 ]]; then + return + fi + + if [[ ! -d $LUKS_CONFIGFS ]]; then + dwarn "$LUKS_CONFIGFS not available" + return 1 + fi + + # This overrides behaviour of 90crypt + inst cryptsetup + instmods dm_crypt + + echo > "$initdir/etc/cmdline.d/90crypt.conf" + echo > "$initdir/etc/crypttab" + echo > "${initdir}/sbin/crypt-run-generator" + + # configfs is mounted after dracut pre-udev hook + # shellcheck disable=SC2154 + inst_hook initqueue 20 "$moddir/kexec-crypt-setup.sh" + + # shellcheck disable=SC2154 + mkdir -p "$hookdir/initqueue/finished" + CRYPTSETUP_PATH=$(command -v cryptsetup) + for _luks_dev in "${_luks_devs[@]}"; do + _devuuid=$(maj_min_to_uuid "$_luks_dev") + _key_desc=$LUKS_KEY_PRFIX$_devuuid + cat << EOF >> "${initdir}/etc/udev/rules.d/70-luks-kdump.rules" +ENV{ID_FS_UUID}=="$_devuuid", \ +RUN+="/sbin/initqueue --settled --unique --onetime --name kdump-crypt-target-%k \ +$CRYPTSETUP_PATH luksOpen --volume-key-keyring \ +%%user:$_key_desc \$env{DEVNAME} luks-$_devuuid" +EOF + done + + dracut_need_initqueue +} + install() { declare -A unique_netifs ipv4_usage ipv6_usage local arch has_ovs_bridge is_nvmf @@ -1204,6 +1248,8 @@ install() { kdump_check_nvmf_target + kdump_check_crypt_targets + kdump_install_systemd_conf # nfs/ssh dump will need to get host ip in second kernel and need to call 'ip' tool, see get_host_ip for more detail diff --git a/kdump-lib-initramfs.sh b/kdump-lib-initramfs.sh index e1b5d53..7b0fa49 100755 --- a/kdump-lib-initramfs.sh +++ b/kdump-lib-initramfs.sh @@ -8,6 +8,10 @@ KDUMP_CONFIG_FILE="/etc/kdump.conf" FENCE_KDUMP_CONFIG_FILE="/etc/sysconfig/fence_kdump" FENCE_KDUMP_SEND="/usr/libexec/fence_kdump_send" LVM_CONF="/etc/lvm/lvm.conf" +# shellcheck disable=SC2034 +LUKS_CONFIGFS=/sys/kernel/config/crash_dm_crypt_keys +# shellcheck disable=SC2034 +LUKS_KEY_PRFIX="systemd-cryptsetup:vk-" # Read kdump config in well formated style kdump_read_conf() diff --git a/kdumpctl b/kdumpctl index 107137d..c572954 100755 --- a/kdumpctl +++ b/kdumpctl @@ -47,6 +47,7 @@ trap ' ret=$?; is_mounted $TMPMNT && umount -f $TMPMNT; rm -rf "$KDUMP_TMPDIR" + [[ -d $LUKS_CONFIGFS ]] && find $LUKS_CONFIGFS/ -mindepth 1 -type d -delete exit $ret; ' EXIT @@ -677,6 +678,11 @@ load_kdump() chcon -t boot_t "$KDUMP_KERNEL" fi + if ! prepare_luks; then + derror "kexec: failed to prepare for a LUKS target" + return 1 + fi + ddebug "$KEXEC $KEXEC_ARGS $standard_kexec_args --command-line=$KDUMP_COMMANDLINE --initrd=$TARGET_INITRD $KDUMP_KERNEL" # shellcheck disable=SC2086 @@ -1051,6 +1057,36 @@ check_final_action_config() fi } +prepare_luks() +{ + local _luks_dev _key_id _key_des + declare -a _luks_devs + + mapfile -t _luks_devs < <(get_all_kdump_crypt_dev) + + if [[ ${#_luks_devs[@]} -lt 1 ]]; then + return + fi + + if [[ ! -d $LUKS_CONFIGFS ]]; then + dwarn "$LUKS_CONFIGFS not available, please use a newer kernel." + return 1 + fi + + for _luks_dev in "${_luks_devs[@]}"; do + _devuuid=$(maj_min_to_uuid "$_luks_dev") + _key_dir=$LUKS_CONFIGFS/$_devuuid + _key_des=$LUKS_KEY_PRFIX$_devuuid + if _key_id=$(keyctl request logon "$_key_des" 2> /dev/null); then + mkdir "$_key_dir" + printf "%s" "$_key_des" > "$_key_dir"/description + else + derror "Failed to get logon key $_key_des. Ensure the link-volume-key option is correctly set up in /etc/crypttab (see man crypttab) and that the key is available." + return 1 + fi + done +} + start() { if ! check_dump_feasibility; then diff --git a/kexec-tools.spec b/kexec-tools.spec index 061981f..6c9a1c3 100644 --- a/kexec-tools.spec +++ b/kexec-tools.spec @@ -60,6 +60,7 @@ Source106: dracut-kdump-capture.service Source107: dracut-kdump-emergency.target Source108: dracut-early-kdump.sh Source109: dracut-early-kdump-module-setup.sh +Source110: dracut-kexec-crypt-setup.sh Source200: dracut-fadump-init-fadump.sh Source201: dracut-fadump-module-setup.sh @@ -250,6 +251,7 @@ cp %{SOURCE102} $RPM_BUILD_ROOT/etc/kdump-adv-conf/kdump_dracut_modules/99kdumpb cp %{SOURCE104} $RPM_BUILD_ROOT/etc/kdump-adv-conf/kdump_dracut_modules/99kdumpbase/%{remove_dracut_prefix %{SOURCE104}} cp %{SOURCE106} $RPM_BUILD_ROOT/etc/kdump-adv-conf/kdump_dracut_modules/99kdumpbase/%{remove_dracut_prefix %{SOURCE106}} cp %{SOURCE107} $RPM_BUILD_ROOT/etc/kdump-adv-conf/kdump_dracut_modules/99kdumpbase/%{remove_dracut_prefix %{SOURCE107}} +cp %{SOURCE110} $RPM_BUILD_ROOT/etc/kdump-adv-conf/kdump_dracut_modules/99kdumpbase/%{remove_dracut_prefix %{SOURCE110}} chmod 755 $RPM_BUILD_ROOT/etc/kdump-adv-conf/kdump_dracut_modules/99kdumpbase/%{remove_dracut_prefix %{SOURCE100}} chmod 755 $RPM_BUILD_ROOT/etc/kdump-adv-conf/kdump_dracut_modules/99kdumpbase/%{remove_dracut_prefix %{SOURCE101}} mkdir -p -m755 $RPM_BUILD_ROOT/etc/kdump-adv-conf/kdump_dracut_modules/99earlykdump diff --git a/mkdumprd b/mkdumprd index 77c3538..d4a7de4 100644 --- a/mkdumprd +++ b/mkdumprd @@ -359,24 +359,10 @@ check_resettable() return 1 } -check_crypt() -{ - local _dev - - for _dev in $(get_kdump_targets); do - if [[ -n $(get_luks_crypt_dev "$(get_maj_min "$_dev")") ]]; then - derror "Device $_dev is encrypted." && return 1 - fi - done -} - if ! check_resettable; then exit 1 fi -if ! check_crypt; then - dwarn "Warning: Encrypted device is in dump path, which is not recommended, see kexec-kdump-howto.txt for more details." -fi # firstly get right SSH_KEY_LOCATION keyfile=$(kdump_get_conf_val sshkey) diff --git a/supported-kdump-targets.txt b/supported-kdump-targets.txt index 4ae0d59..71e7ecc 100644 --- a/supported-kdump-targets.txt +++ b/supported-kdump-targets.txt @@ -49,6 +49,7 @@ storage: NVMe-FC (qla2xxx, lpfc) NVMe/TCP configured by NVMe Boot Firmware Table (users may need to increase the crashkernel value) + LUKS-encrypted volume network: Hardware using kernel modules: (igb, ixgbe, ice, i40e, e1000e, igc,