Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3a75ad14 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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
Loading
Loading
Loading
Loading
+18 −22
Original line number Original line Diff line number Diff line
@@ -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);
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, ...)
{
{
	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, ...)
	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, ...)
			       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, ...)


	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)
+54 −31
Original line number Original line Diff line number Diff line
@@ -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,


	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)
	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,
	}
	}


	/* 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,
		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,
	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,
	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,
	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)
}
}
#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,
	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)
		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)


	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)
			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,


/* 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)
	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);
+1 −0
Original line number Original line Diff line number Diff line
@@ -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");