lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <YHg541E24iy5nddg@gunter>
Date:   Thu, 15 Apr 2021 15:04:35 +0200
From:   Jessica Yu <jeyu@...nel.org>
To:     Stephen Boyd <swboyd@...omium.org>
Cc:     Andrew Morton <akpm@...ux-foundation.org>,
        linux-kernel@...r.kernel.org, Jiri Olsa <jolsa@...nel.org>,
        Alexei Starovoitov <ast@...nel.org>,
        Evan Green <evgreen@...omium.org>,
        Hsin-Yi Wang <hsinyi@...omium.org>,
        Petr Mladek <pmladek@...e.com>,
        Steven Rostedt <rostedt@...dmis.org>,
        Sergey Senozhatsky <sergey.senozhatsky@...il.com>,
        Andy Shevchenko <andriy.shevchenko@...ux.intel.com>,
        Rasmus Villemoes <linux@...musvillemoes.dk>,
        linux-doc@...r.kernel.org, Matthew Wilcox <willy@...radead.org>
Subject: Re: [PATCH v4 05/13] module: Add printk formats to add module build
 ID to stacktraces

+++ Stephen Boyd [09/04/21 18:52 -0700]:
>Let's make kernel stacktraces easier to identify by including the build
>ID[1] of a module if the stacktrace is printing a symbol from a module.
>This makes it simpler for developers to locate a kernel module's full
>debuginfo for a particular stacktrace. Combined with
>scripts/decode_stracktrace.sh, a developer can download the matching
>debuginfo from a debuginfod[2] server and find the exact file and line
>number for the functions plus offsets in a stacktrace that match the
>module. This is especially useful for pstore crash debugging where the
>kernel crashes are recorded in something like console-ramoops and the
>recovery kernel/modules are different or the debuginfo doesn't exist on
>the device due to space concerns (the debuginfo can be too large for
>space limited devices).
>
>Originally, I put this on the %pS format, but that was quickly rejected
>given that %pS is used in other places such as ftrace where build IDs
>aren't meaningful. There was some discussions on the list to put every
>module build ID into the "Modules linked in:" section of the stacktrace
>message but that quickly becomes very hard to read once you have more
>than three or four modules linked in. It also provides too much
>information when we don't expect each module to be traversed in a
>stacktrace. Having the build ID for modules that aren't important just
>makes things messy. Splitting it to multiple lines for each module
>quickly explodes the number of lines printed in an oops too, possibly
>wrapping the warning off the console. And finally, trying to stash away
>each module used in a callstack to provide the ID of each symbol printed
>is cumbersome and would require changes to each architecture to stash
>away modules and return their build IDs once unwinding has completed.
>
>Instead, we opt for the simpler approach of introducing new printk
>formats '%pS[R]b' for "pointer symbolic backtrace with module build ID"
>and '%pBb' for "pointer backtrace with module build ID" and then
>updating the few places in the architecture layer where the stacktrace
>is printed to use this new format.
>
>Example:
>
> WARNING: CPU: 3 PID: 3373 at drivers/misc/lkdtm/bugs.c:83 lkdtm_WARNING+0x28/0x30 [lkdtm]
> Modules linked in: lkdtm rfcomm algif_hash algif_skcipher af_alg xt_cgroup uinput xt_MASQUERADE hci_uart <modules trimmed>
> CPU: 3 PID: 3373 Comm: bash Not tainted 5.11 #12 a8c0d47f7051f3e6670ceaea724af66a39c6cec8
> Hardware name: Google Lazor (rev3+) with KB Backlight (DT)
> pstate: 00400009 (nzcv daif +PAN -UAO -TCO BTYPE=--)
> pc : lkdtm_WARNING+0x28/0x30 [lkdtm]
> lr : lkdtm_do_action+0x24/0x40 [lkdtm]
> sp : ffffffc013febca0
> x29: ffffffc013febca0 x28: ffffff88d9438040
> x27: 0000000000000000 x26: 0000000000000000
> x25: 0000000000000000 x24: ffffffdd0e9772c0
> x23: 0000000000000020 x22: ffffffdd0e975366
> x21: ffffffdd0e9772e0 x20: ffffffc013febde0
> x19: 0000000000000008 x18: 0000000000000000
> x17: 0000000000000000 x16: 0000000000000037
> x15: ffffffdd102ab174 x14: 0000000000000003
> x13: 0000000000000004 x12: 0000000000000000
> x11: 0000000000000000 x10: 0000000000000000
> x9 : 0000000000000001 x8 : ffffffdd0e979000
> x7 : 0000000000000000 x6 : ffffffdd10ff6b54
> x5 : 0000000000000000 x4 : 0000000000000000
> x3 : ffffffc013feb938 x2 : ffffff89fef05a70
> x1 : ffffff89feef5788 x0 : ffffffdd0e9772e0
> Call trace:
>  lkdtm_WARNING+0x28/0x30 [lkdtm 6c2215028606bda50de823490723dc4bc5bf46f9]
>  direct_entry+0x16c/0x1b4 [lkdtm 6c2215028606bda50de823490723dc4bc5bf46f9]
>  full_proxy_write+0x74/0xa4
>  vfs_write+0xec/0x2e8
>  ksys_write+0x84/0xf0
>  __arm64_sys_write+0x24/0x30
>  el0_svc_common+0xf4/0x1c0
>  do_el0_svc_compat+0x28/0x3c
>  el0_svc_compat+0x10/0x1c
>  el0_sync_compat_handler+0xa8/0xcc
>  el0_sync_compat+0x178/0x180
> ---[ end trace f89bc7f5417cbcc6 ]---
>
>Cc: Jiri Olsa <jolsa@...nel.org>
>Cc: Alexei Starovoitov <ast@...nel.org>
>Cc: Jessica Yu <jeyu@...nel.org>
>Cc: Evan Green <evgreen@...omium.org>
>Cc: Hsin-Yi Wang <hsinyi@...omium.org>
>Cc: Petr Mladek <pmladek@...e.com>
>Cc: Steven Rostedt <rostedt@...dmis.org>
>Cc: Sergey Senozhatsky <sergey.senozhatsky@...il.com>
>Cc: Andy Shevchenko <andriy.shevchenko@...ux.intel.com>
>Cc: Rasmus Villemoes <linux@...musvillemoes.dk>
>Cc: <linux-doc@...r.kernel.org>
>Cc: Matthew Wilcox <willy@...radead.org>
>Link: https://fedoraproject.org/wiki/Releases/FeatureBuildId [1]
>Link: https://sourceware.org/elfutils/Debuginfod.html [2]
>Signed-off-by: Stephen Boyd <swboyd@...omium.org>
>---
> Documentation/core-api/printk-formats.rst | 11 +++
> include/linux/kallsyms.h                  | 20 ++++-
> include/linux/module.h                    |  6 +-
> kernel/kallsyms.c                         | 95 ++++++++++++++++++-----
> kernel/module.c                           | 24 +++++-
> lib/vsprintf.c                            |  8 +-
> 6 files changed, 139 insertions(+), 25 deletions(-)
>
>diff --git a/Documentation/core-api/printk-formats.rst b/Documentation/core-api/printk-formats.rst
>index 160e710d992f..5f60533f2a56 100644
>--- a/Documentation/core-api/printk-formats.rst
>+++ b/Documentation/core-api/printk-formats.rst
>@@ -114,6 +114,17 @@ used when printing stack backtraces. The specifier takes into
> consideration the effect of compiler optimisations which may occur
> when tail-calls are used and marked with the noreturn GCC attribute.
>
>+If the pointer is within a module, the module name and optionally build ID is
>+printed after the symbol name with an extra ``b`` appended to the end of the
>+specifier.
>+
>+::
>+	%pS	versatile_init+0x0/0x110 [module_name]
>+	%pSb	versatile_init+0x0/0x110 [module_name ed5019fdf5e53be37cb1ba7899292d7e143b259e]
>+	%pSRb	versatile_init+0x9/0x110 [module_name ed5019fdf5e53be37cb1ba7899292d7e143b259e]
>+		(with __builtin_extract_return_addr() translation)
>+	%pBb	prev_fn_of_versatile_init+0x88/0x88 [module_name ed5019fdf5e53be37cb1ba7899292d7e143b259e]
>+
> Probed Pointers from BPF / tracing
> ----------------------------------
>
>diff --git a/include/linux/kallsyms.h b/include/linux/kallsyms.h
>index 465060acc981..f760cb839775 100644
>--- a/include/linux/kallsyms.h
>+++ b/include/linux/kallsyms.h
>@@ -7,6 +7,7 @@
> #define _LINUX_KALLSYMS_H
>
> #include <linux/errno.h>
>+#include <linux/buildid.h>
> #include <linux/kernel.h>
> #include <linux/stddef.h>
> #include <linux/mm.h>
>@@ -15,8 +16,9 @@
> #include <asm/sections.h>
>
> #define KSYM_NAME_LEN 128
>-#define KSYM_SYMBOL_LEN (sizeof("%s+%#lx/%#lx [%s]") + (KSYM_NAME_LEN - 1) + \
>-			 2*(BITS_PER_LONG*3/10) + (MODULE_NAME_LEN - 1) + 1)
>+#define KSYM_SYMBOL_LEN (sizeof("%s+%#lx/%#lx [%s %s]") + (KSYM_NAME_LEN - 1) + \
>+			 2*(BITS_PER_LONG*3/10) + (MODULE_NAME_LEN - 1) + \
>+			 (BUILD_ID_SIZE_MAX * 2) + 1)
>
> struct cred;
> struct module;
>@@ -91,8 +93,10 @@ const char *kallsyms_lookup(unsigned long addr,
>
> /* Look up a kernel symbol and return it in a text buffer. */
> extern int sprint_symbol(char *buffer, unsigned long address);
>+extern int sprint_symbol_build_id(char *buffer, unsigned long address);
> extern int sprint_symbol_no_offset(char *buffer, unsigned long address);
> extern int sprint_backtrace(char *buffer, unsigned long address);
>+extern int sprint_backtrace_build_id(char *buffer, unsigned long address);
>
> int lookup_symbol_name(unsigned long addr, char *symname);
> int lookup_symbol_attrs(unsigned long addr, unsigned long *size, unsigned long *offset, char *modname, char *name);
>@@ -128,6 +132,12 @@ static inline int sprint_symbol(char *buffer, unsigned long addr)
> 	return 0;
> }
>
>+static inline int sprint_symbol_build_id(char *buffer, unsigned long address)
>+{
>+	*buffer = '\0';
>+	return 0;
>+}
>+
> static inline int sprint_symbol_no_offset(char *buffer, unsigned long addr)
> {
> 	*buffer = '\0';
>@@ -140,6 +150,12 @@ static inline int sprint_backtrace(char *buffer, unsigned long addr)
> 	return 0;
> }
>
>+static inline int sprint_backtrace_build_id(char *buffer, unsigned long addr)
>+{
>+	*buffer = '\0';
>+	return 0;
>+}
>+
> static inline int lookup_symbol_name(unsigned long addr, char *symname)
> {
> 	return -ERANGE;
>diff --git a/include/linux/module.h b/include/linux/module.h
>index 59f094fa6f74..4bf869f6c944 100644
>--- a/include/linux/module.h
>+++ b/include/linux/module.h
>@@ -11,6 +11,7 @@
>
> #include <linux/list.h>
> #include <linux/stat.h>
>+#include <linux/buildid.h>
> #include <linux/compiler.h>
> #include <linux/cache.h>
> #include <linux/kmod.h>
>@@ -367,6 +368,9 @@ struct module {
> 	/* Unique handle for this module */
> 	char name[MODULE_NAME_LEN];
>
>+	/* Module build ID */
>+	unsigned char build_id[BUILD_ID_SIZE_MAX];

Hi Stephen,

Since this field is not used when !CONFIG_STACKTRACE_BUILD_ID, I
would prefer to wrap this in an ifdef, similar to the other
CONFIG-dependent fields in struct module. This makes it explicit under
what conditions (i.e. config) the field is meant to be used.

>+
> 	/* Sysfs stuff. */
> 	struct module_kobject mkobj;
> 	struct module_attribute *modinfo_attrs;
>@@ -630,7 +634,7 @@ void *dereference_module_function_descriptor(struct module *mod, void *ptr);
> const char *module_address_lookup(unsigned long addr,
> 			    unsigned long *symbolsize,
> 			    unsigned long *offset,
>-			    char **modname,
>+			    char **modname, const unsigned char **modbuildid,
> 			    char *namebuf);
> int lookup_module_symbol_name(unsigned long addr, char *symname);
> int lookup_module_symbol_attrs(unsigned long addr, unsigned long *size, unsigned long *offset, char *modname, char *name);
>diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c
>index 8043a90aa50e..b835992e76c2 100644
>--- a/kernel/kallsyms.c
>+++ b/kernel/kallsyms.c
>@@ -273,21 +273,13 @@ int kallsyms_lookup_size_offset(unsigned long addr, unsigned long *symbolsize,
> 		get_symbol_pos(addr, symbolsize, offset);
> 		return 1;
> 	}
>-	return !!module_address_lookup(addr, symbolsize, offset, NULL, namebuf) ||
>+	return !!module_address_lookup(addr, symbolsize, offset, NULL, NULL, namebuf) ||
> 	       !!__bpf_address_lookup(addr, symbolsize, offset, namebuf);
> }
>
>-/*
>- * Lookup an address
>- * - modname is set to NULL if it's in the kernel.
>- * - We guarantee that the returned name is valid until we reschedule even if.
>- *   It resides in a module.
>- * - We also guarantee that modname will be valid until rescheduled.
>- */
>-const char *kallsyms_lookup(unsigned long addr,
>-			    unsigned long *symbolsize,
>-			    unsigned long *offset,
>-			    char **modname, char *namebuf)
>+const char *kallsyms_lookup_buildid(unsigned long addr, unsigned long *symbolsize,
>+				    unsigned long *offset, char **modname,
>+				    const unsigned char **modbuildid, char *namebuf)
> {
> 	const char *ret;
>
>@@ -303,12 +295,14 @@ const char *kallsyms_lookup(unsigned long addr,
> 				       namebuf, KSYM_NAME_LEN);
> 		if (modname)
> 			*modname = NULL;
>+		if (modbuildid)
>+			*modbuildid = NULL;
> 		return namebuf;
> 	}
>
> 	/* See if it's in a module or a BPF JITed image. */
> 	ret = module_address_lookup(addr, symbolsize, offset,
>-				    modname, namebuf);
>+				    modname, modbuildid, namebuf);
> 	if (!ret)
> 		ret = bpf_address_lookup(addr, symbolsize,
> 					 offset, modname, namebuf);
>@@ -319,6 +313,22 @@ const char *kallsyms_lookup(unsigned long addr,
> 	return ret;
> }
>
>+/*
>+ * Lookup an address
>+ * - modname is set to NULL if it's in the kernel.
>+ * - We guarantee that the returned name is valid until we reschedule even if.
>+ *   It resides in a module.
>+ * - We also guarantee that modname will be valid until rescheduled.
>+ */
>+const char *kallsyms_lookup(unsigned long addr,
>+			    unsigned long *symbolsize,
>+			    unsigned long *offset,
>+			    char **modname, char *namebuf)
>+{
>+	return kallsyms_lookup_buildid(addr, symbolsize, offset, modname,
>+				       NULL, namebuf);
>+}
>+
> int lookup_symbol_name(unsigned long addr, char *symname)
> {
> 	symname[0] = '\0';
>@@ -359,15 +369,17 @@ int lookup_symbol_attrs(unsigned long addr, unsigned long *size,
>
> /* Look up a kernel symbol and return it in a text buffer. */
> static int __sprint_symbol(char *buffer, unsigned long address,
>-			   int symbol_offset, int add_offset)
>+			   int symbol_offset, int add_offset, int add_buildid)
> {
> 	char *modname;
>+	const unsigned char *buildid;
> 	const char *name;
> 	unsigned long offset, size;
> 	int len;
>
> 	address += symbol_offset;
>-	name = kallsyms_lookup(address, &size, &offset, &modname, buffer);
>+	name = kallsyms_lookup_buildid(address, &size, &offset, &modname, &buildid,
>+				       buffer);
> 	if (!name)
> 		return sprintf(buffer, "0x%lx", address - symbol_offset);
>
>@@ -379,8 +391,14 @@ static int __sprint_symbol(char *buffer, unsigned long address,
> 	if (add_offset)
> 		len += sprintf(buffer + len, "+%#lx/%#lx", offset, size);
>
>-	if (modname)
>-		len += sprintf(buffer + len, " [%s]", modname);
>+	if (modname) {
>+		len += sprintf(buffer + len, " [%s", modname);
>+		/* build ID should match length of sprintf below */
>+		BUILD_BUG_ON(BUILD_ID_SIZE_MAX != 20);
>+		if (IS_ENABLED(CONFIG_STACKTRACE_BUILD_ID) && add_buildid && buildid)
>+			len += sprintf(buffer + len, " %20phN", buildid);
>+		len += sprintf(buffer + len, "]");
>+	}
>
> 	return len;
> }
>@@ -398,10 +416,27 @@ static int __sprint_symbol(char *buffer, unsigned long address,
>  */
> int sprint_symbol(char *buffer, unsigned long address)
> {
>-	return __sprint_symbol(buffer, address, 0, 1);
>+	return __sprint_symbol(buffer, address, 0, 1, 0);
> }
> EXPORT_SYMBOL_GPL(sprint_symbol);
>
>+/**
>+ * sprint_symbol_build_id - Look up a kernel symbol and return it in a text buffer
>+ * @buffer: buffer to be stored
>+ * @address: address to lookup
>+ *
>+ * This function looks up a kernel symbol with @address and stores its name,
>+ * offset, size, module name and module build ID to @buffer if possible. If no
>+ * symbol was found, just saves its @address as is.
>+ *
>+ * This function returns the number of bytes stored in @buffer.
>+ */
>+int sprint_symbol_build_id(char *buffer, unsigned long address)
>+{
>+	return __sprint_symbol(buffer, address, 0, 1, 1);
>+}
>+EXPORT_SYMBOL_GPL(sprint_symbol_build_id);
>+
> /**
>  * sprint_symbol_no_offset - Look up a kernel symbol and return it in a text buffer
>  * @buffer: buffer to be stored
>@@ -415,7 +450,7 @@ EXPORT_SYMBOL_GPL(sprint_symbol);
>  */
> int sprint_symbol_no_offset(char *buffer, unsigned long address)
> {
>-	return __sprint_symbol(buffer, address, 0, 0);
>+	return __sprint_symbol(buffer, address, 0, 0, 0);
> }
> EXPORT_SYMBOL_GPL(sprint_symbol_no_offset);
>
>@@ -435,7 +470,27 @@ EXPORT_SYMBOL_GPL(sprint_symbol_no_offset);
>  */
> int sprint_backtrace(char *buffer, unsigned long address)
> {
>-	return __sprint_symbol(buffer, address, -1, 1);
>+	return __sprint_symbol(buffer, address, -1, 1, 0);
>+}
>+
>+/**
>+ * sprint_backtrace_build_id - Look up a backtrace symbol and return it in a text buffer
>+ * @buffer: buffer to be stored
>+ * @address: address to lookup
>+ *
>+ * This function is for stack backtrace and does the same thing as
>+ * sprint_symbol() but with modified/decreased @address. If there is a
>+ * tail-call to the function marked "noreturn", gcc optimized out code after
>+ * the call so that the stack-saved return address could point outside of the
>+ * caller. This function ensures that kallsyms will find the original caller
>+ * by decreasing @address. This function also appends the module build ID to
>+ * the @buffer if @address is within a kernel module.
>+ *
>+ * This function returns the number of bytes stored in @buffer.
>+ */
>+int sprint_backtrace_build_id(char *buffer, unsigned long address)
>+{
>+	return __sprint_symbol(buffer, address, -1, 1, 1);
> }
>
> /* To avoid using get_symbol_offset for every symbol, we carry prefix along. */
>diff --git a/kernel/module.c b/kernel/module.c
>index 30479355ab85..6f5bc1b046a5 100644
>--- a/kernel/module.c
>+++ b/kernel/module.c
>@@ -13,6 +13,7 @@
> #include <linux/trace_events.h>
> #include <linux/init.h>
> #include <linux/kallsyms.h>
>+#include <linux/buildid.h>
> #include <linux/file.h>
> #include <linux/fs.h>
> #include <linux/sysfs.h>
>@@ -2770,6 +2771,20 @@ static void add_kallsyms(struct module *mod, const struct load_info *info)
> 	}
> 	mod->core_kallsyms.num_symtab = ndst;
> }
>+
>+static void init_build_id(struct module *mod, const struct load_info *info)
>+{
>+	const Elf_Shdr *sechdr;
>+	unsigned int i;
>+
>+	for (i = 0; i < info->hdr->e_shnum; i++) {
>+		sechdr = &info->sechdrs[i];
>+		if (!sect_empty(sechdr) && sechdr->sh_type == SHT_NOTE &&
>+		    !build_id_parse_buf((void *)sechdr->sh_addr, mod->build_id,
>+					sechdr->sh_size))
>+			break;
>+	}

If mod->build_id is not used when !CONFIG_STACKTRACE_BUILD_ID, then we
don't need to look for it. I would be fine with wrapping the function
body in an ifdef (similar to what we currently do in
del_usage_links() and do_mod_ctors()).

>+}
> #else
> static inline void layout_symtab(struct module *mod, struct load_info *info)
> {
>@@ -2778,6 +2793,10 @@ static inline void layout_symtab(struct module *mod, struct load_info *info)
> static void add_kallsyms(struct module *mod, const struct load_info *info)
> {
> }
>+
>+static void init_build_id(struct module *mod, const struct load_info *info)
>+{
>+}
> #endif /* CONFIG_KALLSYMS */
>
> static void dynamic_debug_setup(struct module *mod, struct _ddebug *debug, unsigned int num)
>@@ -4004,6 +4023,7 @@ static int load_module(struct load_info *info, const char __user *uargs,
> 		goto free_arch_cleanup;
> 	}
>
>+	init_build_id(mod, info);
> 	dynamic_debug_setup(mod, info->debug, info->num_debug);
>
> 	/* Ftrace init must be called in the MODULE_STATE_UNFORMED state */
>@@ -4235,7 +4255,7 @@ void * __weak dereference_module_function_descriptor(struct module *mod,
> const char *module_address_lookup(unsigned long addr,
> 			    unsigned long *size,
> 			    unsigned long *offset,
>-			    char **modname,
>+			    char **modname, const unsigned char **modbuildid,
> 			    char *namebuf)
> {
> 	const char *ret = NULL;
>@@ -4246,6 +4266,8 @@ const char *module_address_lookup(unsigned long addr,
> 	if (mod) {
> 		if (modname)
> 			*modname = mod->name;
>+		if (modbuildid)
>+			*modbuildid = mod->build_id;

Then maybe we can set *modbuildid = NULL in the case of
!CONFIG_STACKTRACE_BUILD_ID, similar to the kernel case in
kallsyms_lookup_buildid().


Thanks!

Jessica

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ