[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20171130023605.29568-4-mcgrof@kernel.org>
Date: Wed, 29 Nov 2017 18:36:05 -0800
From: "Luis R. Rodriguez" <mcgrof@...nel.org>
To: jeyu@...hat.com, rusty@...tcorp.com.au
Cc: keescook@...omium.org, tixxdz@...il.com, mbenes@...e.cz,
atomlin@...hat.com, pmladek@...e.com, hare@...e.com,
james.l.morris@...cle.com, ebiederm@...ssion.com,
davem@...emloft.net, akpm@...ux-foundation.org,
torvalds@...ux-foundation.org, linux-kernel@...r.kernel.org,
"Luis R. Rodriguez" <mcgrof@...nel.org>
Subject: [PATCH 3/3] module: add debugging alias parsing support
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@...ux-foundation.org>
Signed-off-by: Luis R. Rodriguez <mcgrof@...nel.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
Powered by blists - more mailing lists