CONFIG_CRASH_DM_CRYPT has been introduced to support LUKS-encrypted
device dump target by addressing two challenges [1],
 - Kdump kernel may not be able to decrypt the LUKS partition. For some
   machines, a system administrator may not have a chance to enter the
   password to decrypt the device in kdump initramfs after the 1st kernel
   crashes

 - LUKS2 by default use the memory-hard Argon2 key derivation function
   which is quite memory-consuming compared to the limited memory reserved
   for kdump.

To also enable this feature for PowerPC, we only need to let 1st kernel
build up the kernel command parameter dmcryptkeys as similar to
elfcorehdr to pass the memory address of the stored info of dm-crypt
keys to the kdump kernel.

Note to avoid a building failure [2] caused by undeclared function
crash_load_dm_crypt_keys when CONFIG_CRASH_DUMP is not enabled,
realign the function declaration with CONFIG_CRASH_DM_CRYPT.

[1] https://lore.kernel.org/all/[email protected]/
[2] https://lore.kernel.org/oe-kbuild-all/[email protected]/

Cc: Thomas Staudt <[email protected]>
Cc: Arnaud Lefebvre <[email protected]>
Cc: Baoquan he <[email protected]>
Cc: Dave Young <[email protected]>
Cc: Kairui Song <[email protected]>
Cc: Pingfan Liu <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Sourabh Jain <[email protected]>
Signed-off-by: Coiby Xu <[email protected]>
---
v2:
- fix double kfree issue [Sourabh]
- corretly kfree old modified_cmdline
- use imperative mood for commit message
- fix a compiling error caught by kernel test robot

 arch/powerpc/include/asm/kexec.h |  3 ++-
 arch/powerpc/kexec/elf_64.c      | 27 ++++++++++++++++++++++++++-
 arch/powerpc/kexec/file_load.c   | 18 ++++++++++--------
 include/linux/crash_core.h       | 14 +++++++-------
 4 files changed, 45 insertions(+), 17 deletions(-)

diff --git a/arch/powerpc/include/asm/kexec.h b/arch/powerpc/include/asm/kexec.h
index bd4a6c42a5f3..f3d098d543b4 100644
--- a/arch/powerpc/include/asm/kexec.h
+++ b/arch/powerpc/include/asm/kexec.h
@@ -80,7 +80,8 @@ struct kimage_arch {
 };
 
 char *setup_kdump_cmdline(struct kimage *image, char *cmdline,
-                         unsigned long cmdline_len);
+                         unsigned long cmdline_len,
+                         char *name, unsigned long addr);
 int setup_purgatory(struct kimage *image, const void *slave_code,
                    const void *fdt, unsigned long kernel_load_addr,
                    unsigned long fdt_load_addr);
diff --git a/arch/powerpc/kexec/elf_64.c b/arch/powerpc/kexec/elf_64.c
index 5d6d616404cf..995d7e8e98e1 100644
--- a/arch/powerpc/kexec/elf_64.c
+++ b/arch/powerpc/kexec/elf_64.c
@@ -81,13 +81,38 @@ static void *elf64_load(struct kimage *image, char 
*kernel_buf,
 
                /* Setup cmdline for kdump kernel case */
                modified_cmdline = setup_kdump_cmdline(image, cmdline,
-                                                      cmdline_len);
+                                                      cmdline_len,
+                                                      "elfcorehdr",
+                                                      image->elf_load_addr);
                if (!modified_cmdline) {
                        pr_err("Setting up cmdline for kdump kernel failed\n");
                        ret = -EINVAL;
                        goto out;
                }
                cmdline = modified_cmdline;
+               cmdline_len = strlen(cmdline) + 1;
+
+               ret = crash_load_dm_crypt_keys(image);
+               if (ret == -ENOENT) {
+                       kexec_dprintk("No dm crypt key to load\n");
+               } else if (ret) {
+                       pr_err("Failed to load dm crypt keys\n");
+                       return ERR_PTR(ret);
+               }
+
+               if (image->dm_crypt_keys_addr != 0) {
+                       modified_cmdline = setup_kdump_cmdline(image, cmdline,
+                                                              cmdline_len,
+                                                              "dmcryptkeys",
+                                                              
image->dm_crypt_keys_addr);
+                       kfree(cmdline);
+                       if (!modified_cmdline) {
+                               pr_err("Setting up cmdline for kdump kernel 
failed\n");
+                               ret = -EINVAL;
+                               goto out;
+                       }
+                       cmdline = modified_cmdline;
+               }
        }
 
        if (initrd != NULL) {
diff --git a/arch/powerpc/kexec/file_load.c b/arch/powerpc/kexec/file_load.c
index 4284f76cbef5..9964c57785f5 100644
--- a/arch/powerpc/kexec/file_load.c
+++ b/arch/powerpc/kexec/file_load.c
@@ -23,36 +23,38 @@
 #define SLAVE_CODE_SIZE                256     /* First 0x100 bytes */
 
 /**
- * setup_kdump_cmdline - Prepend "elfcorehdr=<addr> " to command line
+ * setup_kdump_cmdline - Prepend "<name>=<addr> " to command line
  *                       of kdump kernel for exporting the core.
  * @image:               Kexec image
  * @cmdline:             Command line parameters to update.
  * @cmdline_len:         Length of the cmdline parameters.
+ * @name:                Name e.g elfcorehdr.
+ * @addr:                Memory address.
  *
  * kdump segment must be setup before calling this function.
  *
  * Returns new cmdline buffer for kdump kernel on success, NULL otherwise.
  */
 char *setup_kdump_cmdline(struct kimage *image, char *cmdline,
-                         unsigned long cmdline_len)
+                         unsigned long cmdline_len,
+                         char *name, unsigned long addr)
 {
-       int elfcorehdr_strlen;
+       unsigned long parameter_len;
        char *cmdline_ptr;
 
        cmdline_ptr = kzalloc(COMMAND_LINE_SIZE, GFP_KERNEL);
        if (!cmdline_ptr)
                return NULL;
 
-       elfcorehdr_strlen = sprintf(cmdline_ptr, "elfcorehdr=0x%lx ",
-                                   image->elf_load_addr);
+       parameter_len = sprintf(cmdline_ptr, "%s=0x%lx ", name, addr);
 
-       if (elfcorehdr_strlen + cmdline_len > COMMAND_LINE_SIZE) {
-               pr_err("Appending elfcorehdr=<addr> exceeds cmdline size\n");
+       if (parameter_len + cmdline_len > COMMAND_LINE_SIZE) {
+               pr_err("Appending %s=<addr> exceeds cmdline size\n", name);
                kfree(cmdline_ptr);
                return NULL;
        }
 
-       memcpy(cmdline_ptr + elfcorehdr_strlen, cmdline, cmdline_len);
+       memcpy(cmdline_ptr + parameter_len, cmdline, cmdline_len);
        // Ensure it's nul terminated
        cmdline_ptr[COMMAND_LINE_SIZE - 1] = '\0';
        return cmdline_ptr;
diff --git a/include/linux/crash_core.h b/include/linux/crash_core.h
index d35726d6a415..e128270c703f 100644
--- a/include/linux/crash_core.h
+++ b/include/linux/crash_core.h
@@ -34,13 +34,6 @@ static inline void arch_kexec_protect_crashkres(void) { }
 static inline void arch_kexec_unprotect_crashkres(void) { }
 #endif
 
-#ifdef CONFIG_CRASH_DM_CRYPT
-int crash_load_dm_crypt_keys(struct kimage *image);
-ssize_t dm_crypt_keys_read(char *buf, size_t count, u64 *ppos);
-#else
-static inline int crash_load_dm_crypt_keys(struct kimage *image) {return 0; }
-#endif
-
 #ifndef arch_crash_handle_hotplug_event
 static inline void arch_crash_handle_hotplug_event(struct kimage *image, void 
*arg) { }
 #endif
@@ -96,4 +89,11 @@ static inline void crash_save_cpu(struct pt_regs *regs, int 
cpu) {};
 static inline int kimage_crash_copy_vmcoreinfo(struct kimage *image) { return 
0; };
 #endif /* CONFIG_CRASH_DUMP*/
 
+#ifdef CONFIG_CRASH_DM_CRYPT
+int crash_load_dm_crypt_keys(struct kimage *image);
+ssize_t dm_crypt_keys_read(char *buf, size_t count, u64 *ppos);
+#else
+static inline int crash_load_dm_crypt_keys(struct kimage *image) { return 0; }
+#endif
+
 #endif /* LINUX_CRASH_CORE_H */

base-commit: 7f98ab9da046865d57c102fd3ca9669a29845f67
-- 
2.52.0


Reply via email to