bootconfig: Fix to remove bootconfig data from initrd while boot

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: 7684b8582c ("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>
This commit is contained in:
Masami Hiramatsu 2020-04-26 15:53:30 +09:00 committed by Steven Rostedt (VMware)
parent 6a8b55ed40
commit de462e5f10

View File

@ -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;
@ -357,9 +398,12 @@ static void __init setup_boot_config(const char *cmdline)
int pos;
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);
@ -367,27 +411,12 @@ static void __init setup_boot_config(const char *cmdline)
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;
@ -420,8 +449,14 @@ static void __init setup_boot_config(const char *cmdline)
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)
{