Commit 3a75ad14 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'modules-for-v4.13' of git://git.kernel.org/pub/scm/linux/kernel/git/jeyu/linux

Pull modules updates from Jessica Yu:
 "Summary of modules changes for the 4.13 merge window:

   - Minor code cleanups

   - Avoid accessing mod struct prior to checking module struct version,
     from Kees

   - Fix racy atomic inc/dec logic of kmod_concurrent_max in kmod, from
     Luis"

* tag 'modules-for-v4.13' of git://git.kernel.org/pub/scm/linux/kernel/git/jeyu/linux:
  module: make the modinfo name const
  kmod: reduce atomic operations on kmod_concurrent and simplify
  module: use list_for_each_entry_rcu() on find_module_all()
  kernel/module.c: suppress warning about unused nowarn variable
  module: Add module name to modinfo
  module: Pass struct load_info into symbol checks
parents 235b84fc 96b5b194
...@@ -45,8 +45,6 @@ ...@@ -45,8 +45,6 @@
#include <trace/events/module.h> #include <trace/events/module.h>
extern int max_threads;
#define CAP_BSET (void *)1 #define CAP_BSET (void *)1
#define CAP_PI (void *)2 #define CAP_PI (void *)2
...@@ -56,6 +54,20 @@ static DEFINE_SPINLOCK(umh_sysctl_lock); ...@@ -56,6 +54,20 @@ static DEFINE_SPINLOCK(umh_sysctl_lock);
static DECLARE_RWSEM(umhelper_sem); static DECLARE_RWSEM(umhelper_sem);
#ifdef CONFIG_MODULES #ifdef CONFIG_MODULES
/*
* Assuming:
*
* threads = div64_u64((u64) totalram_pages * (u64) PAGE_SIZE,
* (u64) THREAD_SIZE * 8UL);
*
* If you need less than 50 threads would mean we're dealing with systems
* smaller than 3200 pages. This assuems you are capable of having ~13M memory,
* and this would only be an be an upper limit, after which the OOM killer
* would take effect. Systems like these are very unlikely if modules are
* enabled.
*/
#define MAX_KMOD_CONCURRENT 50
static atomic_t kmod_concurrent_max = ATOMIC_INIT(MAX_KMOD_CONCURRENT);
/* /*
modprobe_path is set via /proc/sys. modprobe_path is set via /proc/sys.
...@@ -127,10 +139,7 @@ int __request_module(bool wait, const char *fmt, ...) ...@@ -127,10 +139,7 @@ int __request_module(bool wait, const char *fmt, ...)
{ {
va_list args; va_list args;
char module_name[MODULE_NAME_LEN]; char module_name[MODULE_NAME_LEN];
unsigned int max_modprobes;
int ret; int ret;
static atomic_t kmod_concurrent = ATOMIC_INIT(0);
#define MAX_KMOD_CONCURRENT 50 /* Completely arbitrary value - KAO */
static int kmod_loop_msg; static int kmod_loop_msg;
/* /*
...@@ -154,21 +163,7 @@ int __request_module(bool wait, const char *fmt, ...) ...@@ -154,21 +163,7 @@ int __request_module(bool wait, const char *fmt, ...)
if (ret) if (ret)
return ret; return ret;
/* If modprobe needs a service that is in a module, we get a recursive if (atomic_dec_if_positive(&kmod_concurrent_max) < 0) {
* loop. Limit the number of running kmod threads to max_threads/2 or
* MAX_KMOD_CONCURRENT, whichever is the smaller. A cleaner method
* would be to run the parents of this process, counting how many times
* kmod was invoked. That would mean accessing the internals of the
* process tables to get the command line, proc_pid_cmdline is static
* and it is not worth changing the proc code just to handle this case.
* KAO.
*
* "trace the ppid" is simple, but will fail if someone's
* parent exits. I think this is as good as it gets. --RR
*/
max_modprobes = min(max_threads/2, MAX_KMOD_CONCURRENT);
atomic_inc(&kmod_concurrent);
if (atomic_read(&kmod_concurrent) > max_modprobes) {
/* We may be blaming an innocent here, but unlikely */ /* We may be blaming an innocent here, but unlikely */
if (kmod_loop_msg < 5) { if (kmod_loop_msg < 5) {
printk(KERN_ERR printk(KERN_ERR
...@@ -176,7 +171,6 @@ int __request_module(bool wait, const char *fmt, ...) ...@@ -176,7 +171,6 @@ int __request_module(bool wait, const char *fmt, ...)
module_name); module_name);
kmod_loop_msg++; kmod_loop_msg++;
} }
atomic_dec(&kmod_concurrent);
return -ENOMEM; return -ENOMEM;
} }
...@@ -184,10 +178,12 @@ int __request_module(bool wait, const char *fmt, ...) ...@@ -184,10 +178,12 @@ int __request_module(bool wait, const char *fmt, ...)
ret = call_modprobe(module_name, wait ? UMH_WAIT_PROC : UMH_WAIT_EXEC); ret = call_modprobe(module_name, wait ? UMH_WAIT_PROC : UMH_WAIT_EXEC);
atomic_dec(&kmod_concurrent); atomic_inc(&kmod_concurrent_max);
return ret; return ret;
} }
EXPORT_SYMBOL(__request_module); EXPORT_SYMBOL(__request_module);
#endif /* CONFIG_MODULES */ #endif /* CONFIG_MODULES */
static void call_usermodehelper_freeinfo(struct subprocess_info *info) static void call_usermodehelper_freeinfo(struct subprocess_info *info)
......
...@@ -300,6 +300,7 @@ int unregister_module_notifier(struct notifier_block *nb) ...@@ -300,6 +300,7 @@ int unregister_module_notifier(struct notifier_block *nb)
EXPORT_SYMBOL(unregister_module_notifier); EXPORT_SYMBOL(unregister_module_notifier);
struct load_info { struct load_info {
const char *name;
Elf_Ehdr *hdr; Elf_Ehdr *hdr;
unsigned long len; unsigned long len;
Elf_Shdr *sechdrs; Elf_Shdr *sechdrs;
...@@ -600,7 +601,7 @@ static struct module *find_module_all(const char *name, size_t len, ...@@ -600,7 +601,7 @@ static struct module *find_module_all(const char *name, size_t len,
module_assert_mutex_or_preempt(); module_assert_mutex_or_preempt();
list_for_each_entry(mod, &modules, list) { list_for_each_entry_rcu(mod, &modules, list) {
if (!even_unformed && mod->state == MODULE_STATE_UNFORMED) if (!even_unformed && mod->state == MODULE_STATE_UNFORMED)
continue; continue;
if (strlen(mod->name) == len && !memcmp(mod->name, name, len)) if (strlen(mod->name) == len && !memcmp(mod->name, name, len))
...@@ -1273,12 +1274,13 @@ static u32 resolve_rel_crc(const s32 *crc) ...@@ -1273,12 +1274,13 @@ static u32 resolve_rel_crc(const s32 *crc)
return *(u32 *)((void *)crc + *crc); return *(u32 *)((void *)crc + *crc);
} }
static int check_version(Elf_Shdr *sechdrs, static int check_version(const struct load_info *info,
unsigned int versindex,
const char *symname, const char *symname,
struct module *mod, struct module *mod,
const s32 *crc) const s32 *crc)
{ {
Elf_Shdr *sechdrs = info->sechdrs;
unsigned int versindex = info->index.vers;
unsigned int i, num_versions; unsigned int i, num_versions;
struct modversion_info *versions; struct modversion_info *versions;
...@@ -1312,17 +1314,16 @@ static int check_version(Elf_Shdr *sechdrs, ...@@ -1312,17 +1314,16 @@ static int check_version(Elf_Shdr *sechdrs,
} }
/* Broken toolchain. Warn once, then let it go.. */ /* Broken toolchain. Warn once, then let it go.. */
pr_warn_once("%s: no symbol version for %s\n", mod->name, symname); pr_warn_once("%s: no symbol version for %s\n", info->name, symname);
return 1; return 1;
bad_version: bad_version:
pr_warn("%s: disagrees about version of symbol %s\n", pr_warn("%s: disagrees about version of symbol %s\n",
mod->name, symname); info->name, symname);
return 0; return 0;
} }
static inline int check_modstruct_version(Elf_Shdr *sechdrs, static inline int check_modstruct_version(const struct load_info *info,
unsigned int versindex,
struct module *mod) struct module *mod)
{ {
const s32 *crc; const s32 *crc;
...@@ -1338,8 +1339,8 @@ static inline int check_modstruct_version(Elf_Shdr *sechdrs, ...@@ -1338,8 +1339,8 @@ static inline int check_modstruct_version(Elf_Shdr *sechdrs,
BUG(); BUG();
} }
preempt_enable(); preempt_enable();
return check_version(sechdrs, versindex, return check_version(info, VMLINUX_SYMBOL_STR(module_layout),
VMLINUX_SYMBOL_STR(module_layout), mod, crc); mod, crc);
} }
/* First part is kernel version, which we ignore if module has crcs. */ /* First part is kernel version, which we ignore if module has crcs. */
...@@ -1353,8 +1354,7 @@ static inline int same_magic(const char *amagic, const char *bmagic, ...@@ -1353,8 +1354,7 @@ static inline int same_magic(const char *amagic, const char *bmagic,
return strcmp(amagic, bmagic) == 0; return strcmp(amagic, bmagic) == 0;
} }
#else #else
static inline int check_version(Elf_Shdr *sechdrs, static inline int check_version(const struct load_info *info,
unsigned int versindex,
const char *symname, const char *symname,
struct module *mod, struct module *mod,
const s32 *crc) const s32 *crc)
...@@ -1362,8 +1362,7 @@ static inline int check_version(Elf_Shdr *sechdrs, ...@@ -1362,8 +1362,7 @@ static inline int check_version(Elf_Shdr *sechdrs,
return 1; return 1;
} }
static inline int check_modstruct_version(Elf_Shdr *sechdrs, static inline int check_modstruct_version(const struct load_info *info,
unsigned int versindex,
struct module *mod) struct module *mod)
{ {
return 1; return 1;
...@@ -1399,7 +1398,7 @@ static const struct kernel_symbol *resolve_symbol(struct module *mod, ...@@ -1399,7 +1398,7 @@ static const struct kernel_symbol *resolve_symbol(struct module *mod,
if (!sym) if (!sym)
goto unlock; goto unlock;
if (!check_version(info->sechdrs, info->index.vers, name, mod, crc)) { if (!check_version(info, name, mod, crc)) {
sym = ERR_PTR(-EINVAL); sym = ERR_PTR(-EINVAL);
goto getname; goto getname;
} }
...@@ -1662,31 +1661,36 @@ static inline void remove_notes_attrs(struct module *mod) ...@@ -1662,31 +1661,36 @@ static inline void remove_notes_attrs(struct module *mod)
} }
#endif /* CONFIG_KALLSYMS */ #endif /* CONFIG_KALLSYMS */
static void add_usage_links(struct module *mod) static void del_usage_links(struct module *mod)
{ {
#ifdef CONFIG_MODULE_UNLOAD #ifdef CONFIG_MODULE_UNLOAD
struct module_use *use; struct module_use *use;
int nowarn;
mutex_lock(&module_mutex); mutex_lock(&module_mutex);
list_for_each_entry(use, &mod->target_list, target_list) { list_for_each_entry(use, &mod->target_list, target_list)
nowarn = sysfs_create_link(use->target->holders_dir, sysfs_remove_link(use->target->holders_dir, mod->name);
&mod->mkobj.kobj, mod->name);
}
mutex_unlock(&module_mutex); mutex_unlock(&module_mutex);
#endif #endif
} }
static void del_usage_links(struct module *mod) static int add_usage_links(struct module *mod)
{ {
int ret = 0;
#ifdef CONFIG_MODULE_UNLOAD #ifdef CONFIG_MODULE_UNLOAD
struct module_use *use; struct module_use *use;
mutex_lock(&module_mutex); mutex_lock(&module_mutex);
list_for_each_entry(use, &mod->target_list, target_list) list_for_each_entry(use, &mod->target_list, target_list) {
sysfs_remove_link(use->target->holders_dir, mod->name); ret = sysfs_create_link(use->target->holders_dir,
&mod->mkobj.kobj, mod->name);
if (ret)
break;
}
mutex_unlock(&module_mutex); mutex_unlock(&module_mutex);
if (ret)
del_usage_links(mod);
#endif #endif
return ret;
} }
static int module_add_modinfo_attrs(struct module *mod) static int module_add_modinfo_attrs(struct module *mod)
...@@ -1797,13 +1801,18 @@ static int mod_sysfs_setup(struct module *mod, ...@@ -1797,13 +1801,18 @@ static int mod_sysfs_setup(struct module *mod,
if (err) if (err)
goto out_unreg_param; goto out_unreg_param;
add_usage_links(mod); err = add_usage_links(mod);
if (err)
goto out_unreg_modinfo_attrs;
add_sect_attrs(mod, info); add_sect_attrs(mod, info);
add_notes_attrs(mod, info); add_notes_attrs(mod, info);
kobject_uevent(&mod->mkobj.kobj, KOBJ_ADD); kobject_uevent(&mod->mkobj.kobj, KOBJ_ADD);
return 0; return 0;
out_unreg_modinfo_attrs:
module_remove_modinfo_attrs(mod);
out_unreg_param: out_unreg_param:
module_param_sysfs_remove(mod); module_param_sysfs_remove(mod);
out_unreg_holders: out_unreg_holders:
...@@ -2910,9 +2919,15 @@ static int rewrite_section_headers(struct load_info *info, int flags) ...@@ -2910,9 +2919,15 @@ static int rewrite_section_headers(struct load_info *info, int flags)
info->index.vers = 0; /* Pretend no __versions section! */ info->index.vers = 0; /* Pretend no __versions section! */
else else
info->index.vers = find_sec(info, "__versions"); info->index.vers = find_sec(info, "__versions");
info->sechdrs[info->index.vers].sh_flags &= ~(unsigned long)SHF_ALLOC;
info->index.info = find_sec(info, ".modinfo"); info->index.info = find_sec(info, ".modinfo");
if (!info->index.info)
info->name = "(missing .modinfo section)";
else
info->name = get_modinfo(info, "name");
info->sechdrs[info->index.info].sh_flags &= ~(unsigned long)SHF_ALLOC; info->sechdrs[info->index.info].sh_flags &= ~(unsigned long)SHF_ALLOC;
info->sechdrs[info->index.vers].sh_flags &= ~(unsigned long)SHF_ALLOC;
return 0; return 0;
} }
...@@ -2952,21 +2967,29 @@ static struct module *setup_load_info(struct load_info *info, int flags) ...@@ -2952,21 +2967,29 @@ static struct module *setup_load_info(struct load_info *info, int flags)
info->index.mod = find_sec(info, ".gnu.linkonce.this_module"); info->index.mod = find_sec(info, ".gnu.linkonce.this_module");
if (!info->index.mod) { if (!info->index.mod) {
pr_warn("No module found in object\n"); pr_warn("%s: No module found in object\n",
info->name ?: "(missing .modinfo name field)");
return ERR_PTR(-ENOEXEC); return ERR_PTR(-ENOEXEC);
} }
/* This is temporary: point mod into copy of data. */ /* This is temporary: point mod into copy of data. */
mod = (void *)info->sechdrs[info->index.mod].sh_addr; mod = (void *)info->sechdrs[info->index.mod].sh_addr;
/*
* If we didn't load the .modinfo 'name' field, fall back to
* on-disk struct mod 'name' field.
*/
if (!info->name)
info->name = mod->name;
if (info->index.sym == 0) { if (info->index.sym == 0) {
pr_warn("%s: module has no symbols (stripped?)\n", mod->name); pr_warn("%s: module has no symbols (stripped?)\n", info->name);
return ERR_PTR(-ENOEXEC); return ERR_PTR(-ENOEXEC);
} }
info->index.pcpu = find_pcpusec(info); info->index.pcpu = find_pcpusec(info);
/* Check module struct version now, before we try to use module. */ /* Check module struct version now, before we try to use module. */
if (!check_modstruct_version(info->sechdrs, info->index.vers, mod)) if (!check_modstruct_version(info, mod))
return ERR_PTR(-ENOEXEC); return ERR_PTR(-ENOEXEC);
return mod; return mod;
...@@ -2987,7 +3010,7 @@ static int check_modinfo(struct module *mod, struct load_info *info, int flags) ...@@ -2987,7 +3010,7 @@ static int check_modinfo(struct module *mod, struct load_info *info, int flags)
return err; return err;
} else if (!same_magic(modmagic, vermagic, info->index.vers)) { } else if (!same_magic(modmagic, vermagic, info->index.vers)) {
pr_err("%s: version magic '%s' should be '%s'\n", pr_err("%s: version magic '%s' should be '%s'\n",
mod->name, modmagic, vermagic); info->name, modmagic, vermagic);
return -ENOEXEC; return -ENOEXEC;
} }
...@@ -3237,7 +3260,7 @@ int __weak module_frob_arch_sections(Elf_Ehdr *hdr, ...@@ -3237,7 +3260,7 @@ int __weak module_frob_arch_sections(Elf_Ehdr *hdr,
/* module_blacklist is a comma-separated list of module names */ /* module_blacklist is a comma-separated list of module names */
static char *module_blacklist; static char *module_blacklist;
static bool blacklisted(char *module_name) static bool blacklisted(const char *module_name)
{ {
const char *p; const char *p;
size_t len; size_t len;
...@@ -3267,7 +3290,7 @@ static struct module *layout_and_allocate(struct load_info *info, int flags) ...@@ -3267,7 +3290,7 @@ static struct module *layout_and_allocate(struct load_info *info, int flags)
if (IS_ERR(mod)) if (IS_ERR(mod))
return mod; return mod;
if (blacklisted(mod->name)) if (blacklisted(info->name))
return ERR_PTR(-EPERM); return ERR_PTR(-EPERM);
err = check_modinfo(mod, info, flags); err = check_modinfo(mod, info, flags);
......
...@@ -2126,6 +2126,7 @@ static void add_header(struct buffer *b, struct module *mod) ...@@ -2126,6 +2126,7 @@ static void add_header(struct buffer *b, struct module *mod)
buf_printf(b, "#include <linux/compiler.h>\n"); buf_printf(b, "#include <linux/compiler.h>\n");
buf_printf(b, "\n"); buf_printf(b, "\n");
buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\n"); buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\n");
buf_printf(b, "MODULE_INFO(name, KBUILD_MODNAME);\n");
buf_printf(b, "\n"); buf_printf(b, "\n");
buf_printf(b, "__visible struct module __this_module\n"); buf_printf(b, "__visible struct module __this_module\n");
buf_printf(b, "__attribute__((section(\".gnu.linkonce.this_module\"))) = {\n"); buf_printf(b, "__attribute__((section(\".gnu.linkonce.this_module\"))) = {\n");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment