| From de462e5f10718517bacf2f84c8aa2804567ef7df Mon Sep 17 00:00:00 2001 |
| From: Masami Hiramatsu <mhiramat@kernel.org> |
| Date: Sun, 26 Apr 2020 15:53:30 +0900 |
| Subject: bootconfig: Fix to remove bootconfig data from initrd while boot |
| |
| From: Masami Hiramatsu <mhiramat@kernel.org> |
| |
| commit de462e5f10718517bacf2f84c8aa2804567ef7df upstream. |
| |
| If there is a bootconfig data in the tail of initrd/initramfs, |
| initrd image sanity check caused an error while decompression |
| stage as follows. |
| |
| [ 0.883882] Unpacking initramfs... |
| [ 2.696429] Initramfs unpacking failed: invalid magic at start of compressed archive |
| |
| This error will be ignored if CONFIG_BLK_DEV_RAM=n, |
| but CONFIG_BLK_DEV_RAM=y the kernel failed to mount rootfs |
| and causes a panic. |
| |
| To fix this issue, shrink down the initrd_end for removing |
| tailing bootconfig data while boot the kernel. |
| |
| Link: http://lkml.kernel.org/r/158788401014.24243.17424755854115077915.stgit@devnote2 |
| |
| Cc: Borislav Petkov <bp@alien8.de> |
| Cc: Kees Cook <keescook@chromium.org> |
| Cc: Ingo Molnar <mingo@kernel.org> |
| Cc: Andrew Morton <akpm@linux-foundation.org> |
| Cc: stable@vger.kernel.org |
| Fixes: 7684b8582c24 ("bootconfig: Load boot config from the tail of initrd") |
| Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org> |
| Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| init/main.c | 69 +++++++++++++++++++++++++++++++++++++++++++++--------------- |
| 1 file changed, 52 insertions(+), 17 deletions(-) |
| |
| --- a/init/main.c |
| +++ b/init/main.c |
| @@ -257,6 +257,47 @@ static int __init loglevel(char *str) |
| |
| early_param("loglevel", loglevel); |
| |
| +#ifdef CONFIG_BLK_DEV_INITRD |
| +static void * __init get_boot_config_from_initrd(u32 *_size, u32 *_csum) |
| +{ |
| + u32 size, csum; |
| + char *data; |
| + u32 *hdr; |
| + |
| + if (!initrd_end) |
| + return NULL; |
| + |
| + data = (char *)initrd_end - BOOTCONFIG_MAGIC_LEN; |
| + if (memcmp(data, BOOTCONFIG_MAGIC, BOOTCONFIG_MAGIC_LEN)) |
| + return NULL; |
| + |
| + hdr = (u32 *)(data - 8); |
| + size = hdr[0]; |
| + csum = hdr[1]; |
| + |
| + data = ((void *)hdr) - size; |
| + if ((unsigned long)data < initrd_start) { |
| + pr_err("bootconfig size %d is greater than initrd size %ld\n", |
| + size, initrd_end - initrd_start); |
| + return NULL; |
| + } |
| + |
| + /* Remove bootconfig from initramfs/initrd */ |
| + initrd_end = (unsigned long)data; |
| + if (_size) |
| + *_size = size; |
| + if (_csum) |
| + *_csum = csum; |
| + |
| + return data; |
| +} |
| +#else |
| +static void * __init get_boot_config_from_initrd(u32 *_size, u32 *_csum) |
| +{ |
| + return NULL; |
| +} |
| +#endif |
| + |
| #ifdef CONFIG_BOOT_CONFIG |
| |
| char xbc_namebuf[XBC_KEYLEN_MAX] __initdata; |
| @@ -355,9 +396,12 @@ static void __init setup_boot_config(con |
| static char tmp_cmdline[COMMAND_LINE_SIZE] __initdata; |
| u32 size, csum; |
| char *data, *copy; |
| - u32 *hdr; |
| int ret; |
| |
| + data = get_boot_config_from_initrd(&size, &csum); |
| + if (!data) |
| + goto not_found; |
| + |
| strlcpy(tmp_cmdline, boot_command_line, COMMAND_LINE_SIZE); |
| parse_args("bootconfig", tmp_cmdline, NULL, 0, 0, 0, NULL, |
| bootconfig_params); |
| @@ -365,27 +409,12 @@ static void __init setup_boot_config(con |
| if (!bootconfig_found) |
| return; |
| |
| - if (!initrd_end) |
| - goto not_found; |
| - |
| - data = (char *)initrd_end - BOOTCONFIG_MAGIC_LEN; |
| - if (memcmp(data, BOOTCONFIG_MAGIC, BOOTCONFIG_MAGIC_LEN)) |
| - goto not_found; |
| - |
| - hdr = (u32 *)(data - 8); |
| - size = hdr[0]; |
| - csum = hdr[1]; |
| - |
| if (size >= XBC_DATA_MAX) { |
| pr_err("bootconfig size %d greater than max size %d\n", |
| size, XBC_DATA_MAX); |
| return; |
| } |
| |
| - data = ((void *)hdr) - size; |
| - if ((unsigned long)data < initrd_start) |
| - goto not_found; |
| - |
| if (boot_config_checksum((unsigned char *)data, size) != csum) { |
| pr_err("bootconfig checksum failed\n"); |
| return; |
| @@ -414,8 +443,14 @@ static void __init setup_boot_config(con |
| not_found: |
| pr_err("'bootconfig' found on command line, but no bootconfig found\n"); |
| } |
| + |
| #else |
| -#define setup_boot_config(cmdline) do { } while (0) |
| + |
| +static void __init setup_boot_config(const char *cmdline) |
| +{ |
| + /* Remove bootconfig data from initrd */ |
| + get_boot_config_from_initrd(NULL, NULL); |
| +} |
| |
| static int __init warn_bootconfig(char *str) |
| { |