717c7c894d
In kernels built with CONFIG_BOOT_CONFIG_FORCE=y, /proc/cmdline will show all kernel boot parameters, both those supplied by the boot loader and those embedded in the kernel image. This works well for those who just want to see all of the kernel boot parameters, but is not helpful to those who need to see only those parameters supplied by the boot loader. This is especially important when these parameters are presented to the boot loader by automation that might gather them from diverse sources. It is also useful when booting the next kernel via kexec(), in which case it is necessary to supply only those kernel command-line arguments from the boot loader, and most definitely not those that were embedded into the current kernel. Therefore, add comments to /proc/bootconfig of the form: # Parameters from bootloader: # root=UUID=ac0f0548-a69d-43ca-a06b-7db01bcbd5ad ro quiet ... The second added line shows only those kernel boot parameters supplied by the boot loader. Link: https://lore.kernel.org/all/20231005171747.541123-2-paulmck@kernel.org/ Link: https://lore.kernel.org/all/CAHk-=wjpVAW3iRq_bfKnVfs0ZtASh_aT67bQBG11b4W6niYVUw@mail.gmail.com/ Link: https://lore.kernel.org/all/20230731233130.424913-1-paulmck@kernel.org/ Co-developed-by: Masami Hiramatsu <mhiramat@kernel.org> Signed-off-by: Paul E. McKenney <paulmck@kernel.org> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Stephen Rothwell <sfr@canb.auug.org.au> Cc: Arnd Bergmann <arnd@kernel.org> Cc: Nick Desaulniers <ndesaulniers@google.com> Cc: Alexey Dobriyan <adobriyan@gmail.com> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Kees Cook <keescook@chromium.org> Cc: <linux-trace-kernel@vger.kernel.org> Cc: <linux-fsdevel@vger.kernel.org> Acked-by: Masami Hiramatsu (Google) <mhiramat@kernel.org> Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
103 lines
2.2 KiB
C
103 lines
2.2 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* /proc/bootconfig - Extra boot configuration
|
|
*/
|
|
#include <linux/fs.h>
|
|
#include <linux/init.h>
|
|
#include <linux/printk.h>
|
|
#include <linux/proc_fs.h>
|
|
#include <linux/seq_file.h>
|
|
#include <linux/bootconfig.h>
|
|
#include <linux/slab.h>
|
|
|
|
static char *saved_boot_config;
|
|
|
|
static int boot_config_proc_show(struct seq_file *m, void *v)
|
|
{
|
|
if (saved_boot_config)
|
|
seq_puts(m, saved_boot_config);
|
|
return 0;
|
|
}
|
|
|
|
/* Rest size of buffer */
|
|
#define rest(dst, end) ((end) > (dst) ? (end) - (dst) : 0)
|
|
|
|
/* Return the needed total length if @size is 0 */
|
|
static int __init copy_xbc_key_value_list(char *dst, size_t size)
|
|
{
|
|
struct xbc_node *leaf, *vnode;
|
|
char *key, *end = dst + size;
|
|
const char *val;
|
|
char q;
|
|
int ret = 0;
|
|
|
|
key = kzalloc(XBC_KEYLEN_MAX, GFP_KERNEL);
|
|
if (!key)
|
|
return -ENOMEM;
|
|
|
|
xbc_for_each_key_value(leaf, val) {
|
|
ret = xbc_node_compose_key(leaf, key, XBC_KEYLEN_MAX);
|
|
if (ret < 0)
|
|
break;
|
|
ret = snprintf(dst, rest(dst, end), "%s = ", key);
|
|
if (ret < 0)
|
|
break;
|
|
dst += ret;
|
|
vnode = xbc_node_get_child(leaf);
|
|
if (vnode) {
|
|
xbc_array_for_each_value(vnode, val) {
|
|
if (strchr(val, '"'))
|
|
q = '\'';
|
|
else
|
|
q = '"';
|
|
ret = snprintf(dst, rest(dst, end), "%c%s%c%s",
|
|
q, val, q, xbc_node_is_array(vnode) ? ", " : "\n");
|
|
if (ret < 0)
|
|
goto out;
|
|
dst += ret;
|
|
}
|
|
} else {
|
|
ret = snprintf(dst, rest(dst, end), "\"\"\n");
|
|
if (ret < 0)
|
|
break;
|
|
dst += ret;
|
|
}
|
|
if (ret >= 0 && boot_command_line[0]) {
|
|
ret = snprintf(dst, rest(dst, end), "# Parameters from bootloader:\n# %s\n",
|
|
boot_command_line);
|
|
if (ret > 0)
|
|
dst += ret;
|
|
}
|
|
}
|
|
out:
|
|
kfree(key);
|
|
|
|
return ret < 0 ? ret : dst - (end - size);
|
|
}
|
|
|
|
static int __init proc_boot_config_init(void)
|
|
{
|
|
int len;
|
|
|
|
len = copy_xbc_key_value_list(NULL, 0);
|
|
if (len < 0)
|
|
return len;
|
|
|
|
if (len > 0) {
|
|
saved_boot_config = kzalloc(len + 1, GFP_KERNEL);
|
|
if (!saved_boot_config)
|
|
return -ENOMEM;
|
|
|
|
len = copy_xbc_key_value_list(saved_boot_config, len + 1);
|
|
if (len < 0) {
|
|
kfree(saved_boot_config);
|
|
return len;
|
|
}
|
|
}
|
|
|
|
proc_create_single("bootconfig", 0, NULL, boot_config_proc_show);
|
|
|
|
return 0;
|
|
}
|
|
fs_initcall(proc_boot_config_init);
|