From 00e78be8aa49b34fc38a5ae9d182a9ead46b0f24 Mon Sep 17 00:00:00 2001 From: Coiby Xu Date: Mon, 4 Mar 2024 17:18:46 +0800 Subject: [PATCH 1/4] Get uuid by MAJ:MIN Signed-off-by: Coiby Xu --- kdump-lib.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kdump-lib.sh b/kdump-lib.sh index 79714f9b..5ecde818 100755 --- a/kdump-lib.sh +++ b/kdump-lib.sh @@ -1095,6 +1095,10 @@ get_luks_crypt_dev() done } +maj_min_to_uuid() { + lsblk -o uuid,MAJ:MIN | grep $1 | cut -d" " -f1 +} + # kdump_get_maj_min # Prints the major and minor of a device node. # Example: From 757aed9cedbabc512407d5246e64f91b5f224145 Mon Sep 17 00:00:00 2001 From: Coiby Xu Date: Mon, 7 Aug 2023 15:19:36 +0800 Subject: [PATCH 2/4] Support dumping to a LUKS-encrypted target Based on the new kernel feature that dm-crypt keys can persist for the kdump kernel [1], this patch which is adapted from [2] 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. [1] https://github.com/coiby/linux/blob/dm_crypt_v15/Documentation/ABI/testing/crash_dm_crypt_keys [2] https://lists.fedorahosted.org/archives/list/kexec@lists.fedoraproject.org/message/Y3KUSJQPN3JHUUC2FPIK7H4HTSX2TUCX/ Signed-off-by: Coiby Xu --- Makefile | 2 +- dracut-module-setup.sh | 44 ++++++++++++++++++++++++++++++++++++++++++ kdumpctl | 36 ++++++++++++++++++++++++++++++++++ kexec-crypt-setup.sh | 8 ++++++++ mkdumprd | 15 -------------- 5 files changed, 89 insertions(+), 16 deletions(-) create mode 100644 kexec-crypt-setup.sh diff --git a/Makefile b/Makefile index e1a511cf..ea9be17d 100644 --- a/Makefile +++ b/Makefile @@ -58,7 +58,7 @@ install: dracut-modules kdump-conf kdump-sysconfig manpages install -D -m 755 mkdumprd $(DESTDIR)$(sbindir)/mkdumprd install -D -m 644 kdump.conf $(DESTDIR)$(sysconfdir) install -D -m 644 kdump.sysconfig $(DESTDIR)$(sysconfdir)/sysconfig/kdump - install -D -m 755 kdump-lib.sh kdump-lib-initramfs.sh kdump-logger.sh -t $(DESTDIR)$(pkglibdir) + install -D -m 755 kdump-lib.sh kdump-lib-initramfs.sh kdump-logger.sh kexec-crypt-setup.sh -t $(DESTDIR)$(pkglibdir) ifeq ($(ARCH), $(filter ppc64le ppc64,$(ARCH))) install -m 755 mkfadumprd $(DESTDIR)$(sbindir) diff --git a/dracut-module-setup.sh b/dracut-module-setup.sh index 89d99599..e606111f 100755 --- a/dracut-module-setup.sh +++ b/dracut-module-setup.sh @@ -1004,6 +1004,48 @@ ForwardToConsole=yes EOF } +kdump_check_crypt_targets() { + local _luks_dev _count _devuuid _key_desc + declare -a _luks_devs + + _luks_devs=($(get_all_kdump_crypt_dev)) + _count=${#_luks_devs[@]} + + if [[ $_count -lt 1 ]]; then + return + fi + + # This overrides behaviour of 90crypt + inst_hook cmdline 20 "/usr/lib/kdump/kexec-crypt-setup.sh" + + inst cryptsetup + instmods dm_crypt + + mkdir -p $hookdir/initqueue/finished + + for _luks_dev in "${_luks_devs[@]}"; do + _devuuid=$(maj_min_to_uuid "$_luks_dev") + echo "kdump_luks_uuid=${_devuuid} " >"${initdir}/etc/cmdline.d/62kdump_luks.conf" + + _key_desc=cryptsetup:$_devuuid + + mkdir -p "${initdir}/etc/udev/rules.d/" + { + printf -- 'ENV{ID_FS_UUID}=="%s", ' "$_devuuid" + printf -- 'RUN+="/sbin/initqueue --settled --unique --onetime ' + printf -- '--name kdump-crypt-target-%%k %s ' "$(command -v cryptsetup)" + printf -- 'luksOpen --volume-key-keyring %s $env{DEVNAME} %s"\n' "%%user:$_key_desc" "luks-$_devuuid" + } >>"${initdir}/etc/udev/rules.d/70-luks-kdump.rules" + + + done + + echo >"$initdir/etc/cmdline.d/90crypt.conf" + echo >"$initdir/etc/crypttab" + + dracut_need_initqueue +} + remove_cpu_online_rule() { local file=${initdir}/usr/lib/udev/rules.d/40-redhat.rules @@ -1065,6 +1107,8 @@ install() { # at some point of time. kdump_check_iscsi_targets + 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/kdumpctl b/kdumpctl index 30eb27dd..7b92a39c 100755 --- a/kdumpctl +++ b/kdumpctl @@ -711,6 +711,8 @@ load_kdump() chcon -t boot_t "$KDUMP_KERNEL" fi + prepare_luks + ddebug "$KEXEC $KEXEC_ARGS $standard_kexec_args --command-line=$KDUMP_COMMANDLINE --initrd=$TARGET_INITRD $KDUMP_KERNEL" # The '12' represents an intermediate temporary file descriptor @@ -1030,6 +1032,40 @@ check_final_action_config() esac } +LUKS_SYSFS=/sys/kernel/crash_dm_crypt_keys +prepare_luks() +{ + local _luks_dev _count _cmds _cmd _state + declare -a _luks_devs + + _state=$(< $LUKS_SYSFS) + + if [[ $_state == recorded ]]; then + return 0 + elif [[ $_state == reuse ]]; then + return 0 + elif [[ $_state != fresh ]] && [[ $_state != initialized ]]; then + derror "Unknow state about the LUKS keys" + return 1 + fi + + _luks_devs=($(get_all_kdump_crypt_dev)) + _count=${#_luks_devs[@]} + + if [[ $_count -lt 1 ]]; then + return + fi + + if [[ $_state == fresh ]]; then + printf "init %s" "$_count" > $LUKS_SYSFS + fi + + for _luks_dev in "${_luks_devs[@]}"; do + _devuuid=$(maj_min_to_uuid "$_luks_dev") + printf "record cryptsetup:%s" "$_devuuid" > $LUKS_SYSFS + done +} + start() { check_dump_feasibility || return diff --git a/kexec-crypt-setup.sh b/kexec-crypt-setup.sh new file mode 100644 index 00000000..f4e50dba --- /dev/null +++ b/kexec-crypt-setup.sh @@ -0,0 +1,8 @@ +#!/bin/sh +# +_devuuid=$(getarg kdump_luks_uuid=) + +if [[ -n $_devuuid ]]; then + _key_desc=cryptsetup:$_devuuid + echo -n "$_key_desc" > /sys/kernel/crash_dm_crypt_keys +fi diff --git a/mkdumprd b/mkdumprd index 27eed5e3..19ecc99e 100644 --- a/mkdumprd +++ b/mkdumprd @@ -308,21 +308,6 @@ handle_default_dump_target() check_size fs "$_target" } -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_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) if [[ -f $keyfile ]]; then From be458d88d029d0654cf70037e50052e2ef86c5bb Mon Sep 17 00:00:00 2001 From: Coiby Xu Date: Tue, 4 Jun 2024 15:51:47 +0800 Subject: [PATCH 3/4] LUKS: make /usr writable Since commit ffc1ec73b3 ("pid1: add ProtectSystem= as system-wide configuration, and default it to true in the initrd"), systemd makes /usr read-only by default and it will cause dracut to not wait for the LUKS-encrypted devices to be unlocked, dracut-cmdline[296]: mv: inter-device move failed: '/tmp/294-daemon-reload.sh' to '/lib/dracut/hooks/initqueue/daemon-reload.sh'; unable to remove target: Read-only file syste dracut-cmdline[294]: /sbin/initqueue: line 71: /lib/dracut/hooks/initqueue/work: Read-only file system dracut-cmdline[221]: /lib/dracut-dev-lib.sh: line 118: /lib/dracut/hooks/initqueue/finished/devexists-\x2fdev\x2fmyvg\x2fluks_lv.sh: Read-only file system dracut-cmdline[221]: /lib/dracut-dev-lib.sh: line 103: /lib/dracut/hooks/emergency/80-\x2fdev\x2fmyvg\x2fluks_lv.sh: Read-only file system Fix the above issue by making /usr writable. Signed-off-by: Coiby Xu --- dracut-module-setup.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dracut-module-setup.sh b/dracut-module-setup.sh index e606111f..8cd6e19d 100755 --- a/dracut-module-setup.sh +++ b/dracut-module-setup.sh @@ -1043,6 +1043,13 @@ kdump_check_crypt_targets() { echo >"$initdir/etc/cmdline.d/90crypt.conf" echo >"$initdir/etc/crypttab" + # latest systemd makes /usr read-only by default + mkdir -p "${initdir}/etc/systemd/system.conf.d" + { + echo "[Manager]" + echo "ProtectSystem=false" + } >>"${initdir}/etc/systemd/system.conf.d/kdump_luks.conf" + dracut_need_initqueue } From 9b48a73196d714eb1bb7c63ec40661df8049efbc Mon Sep 17 00:00:00 2001 From: Coiby Xu Date: Tue, 4 Jun 2024 15:44:11 +0800 Subject: [PATCH 4/4] LUKS: hotplug support Send reuse command to /sys/kernel/crash_dm_crypt_keys [1] to reuse saved dm crypt keys. [1] https://github.com/coiby/linux/blob/dm_crypt_v15/Documentation/ABI/testing/crash_dm_crypt_keys Signed-off-by: Coiby Xu --- kdumpctl | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/kdumpctl b/kdumpctl index 7b92a39c..06dccde4 100755 --- a/kdumpctl +++ b/kdumpctl @@ -1033,6 +1033,19 @@ check_final_action_config() } LUKS_SYSFS=/sys/kernel/crash_dm_crypt_keys +reuse_loaded_luks_keys() +{ + local _luks_dev _count _cmds _cmd _state + declare -a _luks_devs + + _state=$(< $LUKS_SYSFS) + + if [[ $_state == loaded ]]; then + echo -n reuse > $LUKS_SYSFS + return 0 + fi +} + prepare_luks() { local _luks_dev _count _cmds _cmd _state @@ -1738,6 +1751,7 @@ main() exit $EXIT_CODE ;; reload) + reuse_loaded_luks_keys reload ;; restart)