public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: "Luis R. Rodriguez" <mcgrof@kernel.org>
To: jeyu@redhat.com, rusty@rustcorp.com.au
Cc: keescook@chromium.org, tixxdz@gmail.com, mbenes@suse.cz,
	atomlin@redhat.com, pmladek@suse.com, hare@suse.com,
	james.l.morris@oracle.com, ebiederm@xmission.com,
	davem@davemloft.net, akpm@linux-foundation.org,
	torvalds@linux-foundation.org, linux-kernel@vger.kernel.org,
	"Luis R. Rodriguez" <mcgrof@kernel.org>
Subject: [PATCH 3/3] module: add debugging alias parsing support
Date: Wed, 29 Nov 2017 18:36:05 -0800	[thread overview]
Message-ID: <20171130023605.29568-4-mcgrof@kernel.org> (raw)
In-Reply-To: <20171130023605.29568-1-mcgrof@kernel.org>

Debugging modules can often lead to an alias question. We purposely
don't have alias parsing support upstream as this is all dealt with
in userpace with the assumption that in-kernel we just process aliases
and userspace Does The Right Thing (TM) about aliases.

Obviously userspace can be buggy though, and it can lie to us. We
currently have no easy way to determine this. Parsing aliases is
an example debugging facility we can use to help with these sorts
of problems.

You can debug by adding to your dynamic debug:

GRUB_CMDLINE_LINUX_DEFAULT="dyndbg=\"func module_process_aliases +p;\" "

Upon boot for example here a few entries:

module ext4 num_aliases: 5
alias[0] = fs-ext4
alias[1] = ext3
alias[2] = fs-ext3
alias[3] = ext2
alias[4] = fs-ext2

module xfs num_aliases: 1
alias[0] = fs-xfs

module floppy num_aliases: 3
alias[0] = block-major-2-*
alias[1] = acpi*:PNP0700:*
alias[2] = pnp:dPNP0700*

module ata_piix num_aliases: 89
alias[0] = pci:v00008086d00008C81sv*sd*bc*sc*i*
alias[1] = pci:v00008086d00008C80sv*sd*bc*sc*i*
alias[2] = pci:v00008086d00008C89sv*sd*bc*sc*i*
alias[3] = pci:v00008086d00008C88sv*sd*bc*sc*i*
... etc ...

Suggested-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Luis R. Rodriguez <mcgrof@kernel.org>
---
 include/linux/module.h |   4 ++
 init/Kconfig           |   7 ++++
 kernel/module.c        | 107 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 118 insertions(+)

diff --git a/include/linux/module.h b/include/linux/module.h
index 548fa09fa806..2efb0e3e39d9 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -341,6 +341,10 @@ struct module {
 	const char *srcversion;
 	struct kobject *holders_dir;
 
+#ifdef CONFIG_MODULE_DEBUG
+	unsigned int num_aliases;
+	const char **aliases;
+#endif
 	/* Exported symbols */
 	const struct kernel_symbol *syms;
 	const s32 *crcs;
diff --git a/init/Kconfig b/init/Kconfig
index 2934249fba46..f216e0da3761 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1688,6 +1688,13 @@ menuconfig MODULES
 
 if MODULES
 
+config MODULE_DEBUG
+	bool "Enable debugging information for modules"
+	default n
+	help
+	  Enables debugging of the module infrastructure. Say no unless you
+	  are debugging the module framework.
+
 config MODULE_FORCE_LOAD
 	bool "Forced module loading"
 	default n
diff --git a/kernel/module.c b/kernel/module.c
index 6d5f02e86681..c1a10ef6ae76 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -2129,6 +2129,28 @@ void __weak module_arch_freeing_init(struct module *mod)
 {
 }
 
+#ifdef CONFIG_MODULE_DEBUG
+static void free_mod_aliases(struct module *mod)
+{
+	unsigned int i;
+
+	if (!mod->num_aliases)
+		return;
+
+	for (i=0; i < mod->num_aliases; i++) {
+		kfree(mod->aliases[i]);
+		mod->aliases[i] = NULL;
+	}
+
+	kfree(mod->aliases);
+	mod->aliases = NULL;
+}
+#else
+static void free_mod_aliases(struct module *mod)
+{
+}
+#endif
+
 /* Free a module, remove from lists, etc. */
 static void free_module(struct module *mod)
 {
@@ -2174,6 +2196,7 @@ static void free_module(struct module *mod)
 	module_memfree(mod->init_layout.base);
 	kfree(mod->args);
 	percpu_modfree(mod);
+	free_mod_aliases(mod);
 
 	/* Free lock-classes; relies on the preceding sync_rcu(). */
 	lockdep_free_key_range(mod->core_layout.base, mod->core_layout.size);
@@ -2485,6 +2508,33 @@ static char *next_string(char *string, unsigned long *secsize)
 	return string;
 }
 
+#ifdef CONFIG_MODULE_DEBUG
+static int get_modinfo_tags(struct load_info *info,
+			    const char *tag,
+			    unsigned int *num_entries)
+{
+	char *p;
+	unsigned int taglen = strlen(tag);
+	Elf_Shdr *infosec = &info->sechdrs[info->index.info];
+	unsigned long size = infosec->sh_size;
+	const char *value;
+	unsigned int len, tags_size = 0;
+
+	for (p = (char *)infosec->sh_addr; p; p = next_string(p, &size)) {
+		if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=') {
+			value = p + taglen + 1;
+			len = strlen(value);
+			if (len >=0 && len <= PAGE_SIZE) {
+				(*num_entries)++;
+				tags_size+=len;
+			}
+		}
+	}
+
+	return tags_size;
+}
+#endif
+
 static const char *get_modinfo_idx(struct load_info *info, const char *tag,
 				   unsigned int tag_idx)
 {
@@ -3011,6 +3061,53 @@ static struct module *setup_load_info(struct load_info *info, int flags)
 	return mod;
 }
 
+#ifdef CONFIG_MODULE_DEBUG
+static int module_process_aliases(struct module *mod, struct load_info *info)
+{
+	unsigned int size, i, num_entries = 0;
+	const char *alias;
+
+	size = get_modinfo_tags(info, "alias", &num_entries);
+	if (WARN_ON(!size))
+		return 0;
+
+	mod->aliases = kzalloc(num_entries * sizeof(char *), GFP_KERNEL);
+	if (!mod->aliases)
+		return -ENOMEM;
+
+	pr_debug("module %s num_aliases: %u\n", mod->name, num_entries);
+
+	for (i=0; i < num_entries; i++) {
+		alias = get_modinfo_idx(info, "alias", i);
+		pr_debug("alias[%u] = %s\n", i, alias);
+		mod->aliases[i] = kasprintf(GFP_KERNEL, "%s", alias);
+		if (!mod->aliases[i])
+			goto err_free;
+	}
+
+	mod->num_aliases = num_entries;
+
+	return 0;
+
+err_free:
+	while (i!=0) {
+		i--;
+		kfree(mod->aliases[i]);
+		mod->aliases[i] = NULL;
+	}
+
+	kfree(mod->aliases);
+	mod->aliases = NULL;
+
+	return -ENOMEM;
+}
+#else
+static int module_process_aliases(struct module *mod, struct load_info *info)
+{
+	return 0;
+}
+#endif
+
 static int check_modinfo(struct module *mod, struct load_info *info, int flags)
 {
 	const char *modmagic = get_modinfo(info, "vermagic");
@@ -3043,6 +3140,12 @@ static int check_modinfo(struct module *mod, struct load_info *info, int flags)
 			"is unknown, you have been warned.\n", mod->name);
 	}
 
+	if (get_modinfo(info, "alias")) {
+		err = module_process_aliases(mod, info);
+		if (err)
+			goto err_out_skip_alloc;
+	}
+
 	err = check_modinfo_livepatch(mod, info);
 	if (err)
 		goto err_out;
@@ -3052,6 +3155,8 @@ static int check_modinfo(struct module *mod, struct load_info *info, int flags)
 
 	return 0;
 err_out:
+	free_mod_aliases(mod);
+err_out_skip_alloc:
 	return err;
 }
 
@@ -3353,6 +3458,7 @@ static struct module *layout_and_allocate(struct load_info *info, int flags)
 	kmemleak_load_module(mod, info);
 	return mod;
 err_out:
+	free_mod_aliases(mod);
 	return ERR_PTR(err);
 }
 
@@ -3824,6 +3930,7 @@ static int load_module(struct load_info *info, const char __user *uargs,
 	synchronize_sched();
 	mutex_unlock(&module_mutex);
  free_module:
+	free_mod_aliases(mod);
 	/*
 	 * Ftrace needs to clean up what it initialized.
 	 * This does nothing if ftrace_module_init() wasn't called,
-- 
2.15.0

  parent reply	other threads:[~2017-11-30  2:36 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-11-30  2:36 [PATCH 0/3] module: process aliasing when debugging Luis R. Rodriguez
2017-11-30  2:36 ` [PATCH 1/3] module: use goto errors on check_modinfo() and layout_and_allocate() Luis R. Rodriguez
2017-11-30  2:36 ` [PATCH 2/3] module: add helper get_modinfo_idx() Luis R. Rodriguez
2017-11-30  2:36 ` Luis R. Rodriguez [this message]
2017-11-30 13:17   ` module: add debugging alias parsing support Jessica Yu
2017-11-30 18:39     ` Luis R. Rodriguez
2017-12-04  9:01       ` Djalal Harouni
2017-12-04 13:58         ` Jessica Yu
2017-12-04 14:17           ` Djalal Harouni
2017-12-07 19:51         ` Luis R. Rodriguez
2018-03-10 14:09 ` [PATCH 0/3] module: process aliasing when debugging Luis R. Rodriguez

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20171130023605.29568-4-mcgrof@kernel.org \
    --to=mcgrof@kernel.org \
    --cc=akpm@linux-foundation.org \
    --cc=atomlin@redhat.com \
    --cc=davem@davemloft.net \
    --cc=ebiederm@xmission.com \
    --cc=hare@suse.com \
    --cc=james.l.morris@oracle.com \
    --cc=jeyu@redhat.com \
    --cc=keescook@chromium.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mbenes@suse.cz \
    --cc=pmladek@suse.com \
    --cc=rusty@rustcorp.com.au \
    --cc=tixxdz@gmail.com \
    --cc=torvalds@linux-foundation.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox