2020-04-24 16:36:04

by Masami Hiramatsu

[permalink] [raw]
Subject: [BUGFIX PATCH 0/1] bootconfig: Fix wrong initramfs/initrd error with bootconfig

Hello,

I found that the bootconfig breaks initramfs unpacking.
I saw an error message as following if I apply a bootconfig
to initramfs image.

[ 0.883882] Unpacking initramfs...
[ 2.696429] Initramfs unpacking failed: invalid magic at start of compressed archive

Without CONFIG_BLK_DEV_RAM, it has no failback method,
so boot up with unpacked initramfs normally. But with
CONFIG_BLK_DEV_RAM=y, the kernel tries to failback to
initrd and failes to mount rootfs.

To fix this issue, I took a way to shrink the initrd_end
so that the kernel can ignore the bootconfig data.

Any thought?

Thank you,

---

Masami Hiramatsu (1):
bootconfig: Fix to remove bootconfig data from initrd while boot


init/main.c | 62 +++++++++++++++++++++++++++++++++++++++++++----------------
1 file changed, 45 insertions(+), 17 deletions(-)

--
Masami Hiramatsu (Linaro) <[email protected]>


2020-04-24 16:37:53

by Masami Hiramatsu

[permalink] [raw]
Subject: [BUGFIX PATCH 1/1] 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.

Fixes: 7684b8582c24 ("bootconfig: Load boot config from the tail of initrd")
Signed-off-by: Masami Hiramatsu <[email protected]>
Cc: [email protected]
---
init/main.c | 62 +++++++++++++++++++++++++++++++++++++++++++----------------
1 file changed, 45 insertions(+), 17 deletions(-)

diff --git a/init/main.c b/init/main.c
index 295aec3a1a7a..f245a1f37401 100644
--- a/init/main.c
+++ b/init/main.c
@@ -258,6 +258,40 @@ static int __init loglevel(char *str)

early_param("loglevel", loglevel);

+static void *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;
+}
+
#ifdef CONFIG_BOOT_CONFIG

char xbc_namebuf[XBC_KEYLEN_MAX] __initdata;
@@ -358,9 +392,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);
@@ -368,27 +405,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;
@@ -421,8 +443,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 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)
{

2020-04-24 23:02:35

by Steven Rostedt

[permalink] [raw]
Subject: Re: [BUGFIX PATCH 1/1] bootconfig: Fix to remove bootconfig data from initrd while boot

On Sat, 25 Apr 2020 01:34:12 +0900
Masami Hiramatsu <[email protected]> wrote:

> 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.
>
> Fixes: 7684b8582c24 ("bootconfig: Load boot config from the tail of initrd")
> Signed-off-by: Masami Hiramatsu <[email protected]>
> Cc: [email protected]
> ---

Thanks Masami! I pulled this into my urgent queue.

-- Steve

2020-04-25 00:00:25

by Steven Rostedt

[permalink] [raw]
Subject: Re: [BUGFIX PATCH 1/1] bootconfig: Fix to remove bootconfig data from initrd while boot

On Sat, 25 Apr 2020 01:34:12 +0900
Masami Hiramatsu <[email protected]> wrote:

> 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.
>
> Fixes: 7684b8582c24 ("bootconfig: Load boot config from the tail of initrd")
> Signed-off-by: Masami Hiramatsu <[email protected]>
> Cc: [email protected]
> ---
> init/main.c | 62 +++++++++++++++++++++++++++++++++++++++++++----------------
> 1 file changed, 45 insertions(+), 17 deletions(-)
>
>

A build with

$ make allnoconfig

Produces this:

MODPOST vmlinux.o
MODINFO modules.builtin.modinfo
GEN modules.builtin
LD vmlinux
ld: init/main.o: in function `start_kernel':
main.c:(.init.text+0x37f): undefined reference to `initrd_end'
ld: main.c:(.init.text+0x3a7): undefined reference to `initrd_start'
ld: main.c:(.init.text+0x3ae): undefined reference to `initrd_end'
make[1]: *** [/work/git/linux-trace.git/Makefile:1106: vmlinux] Error 1

-- Steve

2020-04-26 07:26:47

by Masami Hiramatsu

[permalink] [raw]
Subject: Re: [BUGFIX PATCH 1/1] bootconfig: Fix to remove bootconfig data from initrd while boot

On Fri, 24 Apr 2020 19:58:33 -0400
Steven Rostedt <[email protected]> wrote:

> On Sat, 25 Apr 2020 01:34:12 +0900
> Masami Hiramatsu <[email protected]> wrote:
>
> > 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.
> >
> > Fixes: 7684b8582c24 ("bootconfig: Load boot config from the tail of initrd")
> > Signed-off-by: Masami Hiramatsu <[email protected]>
> > Cc: [email protected]
> > ---
> > init/main.c | 62 +++++++++++++++++++++++++++++++++++++++++++----------------
> > 1 file changed, 45 insertions(+), 17 deletions(-)
> >
> >
>
> A build with
>
> $ make allnoconfig
>
> Produces this:
>
> MODPOST vmlinux.o
> MODINFO modules.builtin.modinfo
> GEN modules.builtin
> LD vmlinux
> ld: init/main.o: in function `start_kernel':
> main.c:(.init.text+0x37f): undefined reference to `initrd_end'
> ld: main.c:(.init.text+0x3a7): undefined reference to `initrd_start'
> ld: main.c:(.init.text+0x3ae): undefined reference to `initrd_end'
> make[1]: *** [/work/git/linux-trace.git/Makefile:1106: vmlinux] Error 1

Oops, that depends on initrd. OK, I'll fix it.

Thanks!

--
Masami Hiramatsu <[email protected]>

2020-04-26 07:27:09

by Masami Hiramatsu

[permalink] [raw]
Subject: [BUGFIX PATCH v2 1/1] 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.

Fixes: 7684b8582c24 ("bootconfig: Load boot config from the tail of initrd")
Signed-off-by: Masami Hiramatsu <[email protected]>
Cc: [email protected]
---
Changes in v2:
- Make new functions __init.
- Do nothing if CONFIG_BLK_DEV_INITRD=n
---
init/main.c | 69 ++++++++++++++++++++++++++++++++++++++++++++---------------
1 file changed, 52 insertions(+), 17 deletions(-)

diff --git a/init/main.c b/init/main.c
index 295aec3a1a7a..f55cb15f23d2 100644
--- a/init/main.c
+++ b/init/main.c
@@ -258,6 +258,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;
@@ -358,9 +399,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);
@@ -368,27 +412,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;
@@ -421,8 +450,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)
{