init: print out unknown kernel parameters
authorAndrew Halaney <ahalaney@redhat.com>
Thu, 1 Jul 2021 01:56:28 +0000 (18:56 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 1 Jul 2021 18:06:06 +0000 (11:06 -0700)
It is easy to foobar setting a kernel parameter on the command line
without realizing it, there's not much output that you can use to assess
what the kernel did with that parameter by default.

Make it a little more explicit which parameters on the command line
_looked_ like a valid parameter for the kernel, but did not match anything
and ultimately got tossed to init.  This is very similar to the unknown
parameter message received when loading a module.

This assumes the parameters are processed in a normal fashion, some
parameters (dyndbg= for example) don't register their parameter with the
rest of the kernel's parameters, and therefore always show up in this list
(and are also given to init - like the rest of this list).

Another example is BOOT_IMAGE= is highlighted as an offender, which it
technically is, but is passed by LILO and GRUB so most systems will see
that complaint.

An example output where "foobared" and "unrecognized" are intentionally
invalid parameters:

  Kernel command line: BOOT_IMAGE=/boot/vmlinuz-5.12-dirty debug log_buf_len=4M foobared unrecognized=foo
  Unknown command line parameters: foobared BOOT_IMAGE=/boot/vmlinuz-5.12-dirty unrecognized=foo

Link: https://lkml.kernel.org/r/20210511211009.42259-1-ahalaney@redhat.com
Signed-off-by: Andrew Halaney <ahalaney@redhat.com>
Suggested-by: Steven Rostedt <rostedt@goodmis.org>
Suggested-by: Borislav Petkov <bp@suse.de>
Acked-by: Borislav Petkov <bp@suse.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
init/main.c

index e9c42a1..d4f7af4 100644 (file)
@@ -872,6 +872,47 @@ void __init __weak arch_call_rest_init(void)
        rest_init();
 }
 
+static void __init print_unknown_bootoptions(void)
+{
+       char *unknown_options;
+       char *end;
+       const char *const *p;
+       size_t len;
+
+       if (panic_later || (!argv_init[1] && !envp_init[2]))
+               return;
+
+       /*
+        * Determine how many options we have to print out, plus a space
+        * before each
+        */
+       len = 1; /* null terminator */
+       for (p = &argv_init[1]; *p; p++) {
+               len++;
+               len += strlen(*p);
+       }
+       for (p = &envp_init[2]; *p; p++) {
+               len++;
+               len += strlen(*p);
+       }
+
+       unknown_options = memblock_alloc(len, SMP_CACHE_BYTES);
+       if (!unknown_options) {
+               pr_err("%s: Failed to allocate %zu bytes\n",
+                       __func__, len);
+               return;
+       }
+       end = unknown_options;
+
+       for (p = &argv_init[1]; *p; p++)
+               end += sprintf(end, " %s", *p);
+       for (p = &envp_init[2]; *p; p++)
+               end += sprintf(end, " %s", *p);
+
+       pr_notice("Unknown command line parameters:%s\n", unknown_options);
+       memblock_free(__pa(unknown_options), len);
+}
+
 asmlinkage __visible void __init __no_sanitize_address start_kernel(void)
 {
        char *command_line;
@@ -913,6 +954,7 @@ asmlinkage __visible void __init __no_sanitize_address start_kernel(void)
                                  static_command_line, __start___param,
                                  __stop___param - __start___param,
                                  -1, -1, NULL, &unknown_bootoption);
+       print_unknown_bootoptions();
        if (!IS_ERR_OR_NULL(after_dashes))
                parse_args("Setting init args", after_dashes, NULL, 0, -1, -1,
                           NULL, set_init_arg);