Modules updates for v5.3
Summary of modules changes for the 5.3 merge window: - Code fixes and cleanups - Fix bug where set_memory_x() wasn't being called when rodata=n - Fix bug where -EEXIST was being returned for going modules - Allow arches to override module_exit_section() Signed-off-by: Jessica Yu <jeyu@kernel.org> -----BEGIN PGP SIGNATURE----- iQIcBAABCgAGBQJdMET+AAoJEMBFfjjOO8FyWg4P/RFUwHUxdpouLlVjlJVx40ko WWFMjQ7zDjhWJVvqataQJS3L3yqhZEC+KrSetqKgP0NxKQ2ev4BwgGF822yorQRw Aorw/aHk9xIyfv7tUEjQgLpa7j1zv15uLx+Y4mkRSgc1uZve0MYKgMsU4db97pTk XUyronakoM9h4z7NVyV21F9dgprnytzdWwgYdjEx2aMPzF/+3MAPN6H7d8Cb8v4X 85UwPb8SB5F3U/wzYowrHmlFTlAOkroUrZRErwUOlCn8rvZefkt4NnJwShBC7YPa N0CVemw6sgy5KcDUczL7oQJ+kyYwtHN0i0EhvTMixPFKeeCI96Y+UNPZxxQANd6f 0djYqvRtfqAp7b2bRSfSiApRdxMO3rl17tY/c1MiIb4/Yk5BtofX+8edW3eMX3Xc eL5EDL69idgjx1llXmScmjbWiy7Mg61mmo6PN8T/wyIqtDQ/CXqovHdh8Ehbubuf 5cC7fQiVSRhqvg0N4w2FEr+hV+VpEjdnfxypd46ABDVhYYir7ybMLoHYwBimwKSD 70qOJWfiRjnEES0qaO3JH/nlXhQGSnPpfe7kwx0LAIyIdTTfarPjGbK/5wcNcReA f3A7R2p//G7sNg3DWYSG1cKEjgOAwMjD00SOBov82K9VQ8spwMexIo93Hj6BEbY5 5cex2njf5G2YNKDfAvoi =/sk3 -----END PGP SIGNATURE----- Merge tag 'modules-for-v5.3' of git://git.kernel.org/pub/scm/linux/kernel/git/jeyu/linux Pull module updates from Jessica Yu: "Summary of modules changes for the 5.3 merge window: - Code fixes and cleanups - Fix bug where set_memory_x() wasn't being called when rodata=n - Fix bug where -EEXIST was being returned for going modules - Allow arches to override module_exit_section()" * tag 'modules-for-v5.3' of git://git.kernel.org/pub/scm/linux/kernel/git/jeyu/linux: modules: fix compile error if don't have strict module rwx ARM: module: recognize unwind exit sections module: allow arch overrides for .exit section names modules: fix BUG when load module with rodata=n kernel/module: Fix mem leak in module_add_modinfo_attrs kernel: module: Use struct_size() helper kernel/module.c: Only return -EEXIST for modules that have finished loading
This commit is contained in:
commit
da0acd7c65
@ -55,6 +55,13 @@ void *module_alloc(unsigned long size)
|
||||
}
|
||||
#endif
|
||||
|
||||
bool module_exit_section(const char *name)
|
||||
{
|
||||
return strstarts(name, ".exit") ||
|
||||
strstarts(name, ".ARM.extab.exit") ||
|
||||
strstarts(name, ".ARM.exidx.exit");
|
||||
}
|
||||
|
||||
int
|
||||
apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
|
||||
unsigned int relindex, struct module *module)
|
||||
|
@ -29,6 +29,11 @@ void *module_alloc(unsigned long size);
|
||||
/* Free memory returned from module_alloc. */
|
||||
void module_memfree(void *module_region);
|
||||
|
||||
/* Determines if the section name is an exit section (that is only used during
|
||||
* module unloading)
|
||||
*/
|
||||
bool module_exit_section(const char *name);
|
||||
|
||||
/*
|
||||
* Apply the given relocation to the (simplified) ELF. Return -error
|
||||
* or 0.
|
||||
|
@ -1492,8 +1492,7 @@ static void add_sect_attrs(struct module *mod, const struct load_info *info)
|
||||
for (i = 0; i < info->hdr->e_shnum; i++)
|
||||
if (!sect_empty(&info->sechdrs[i]))
|
||||
nloaded++;
|
||||
size[0] = ALIGN(sizeof(*sect_attrs)
|
||||
+ nloaded * sizeof(sect_attrs->attrs[0]),
|
||||
size[0] = ALIGN(struct_size(sect_attrs, attrs, nloaded),
|
||||
sizeof(sect_attrs->grp.attrs[0]));
|
||||
size[1] = (nloaded + 1) * sizeof(sect_attrs->grp.attrs[0]);
|
||||
sect_attrs = kzalloc(size[0] + size[1], GFP_KERNEL);
|
||||
@ -1697,6 +1696,8 @@ static int add_usage_links(struct module *mod)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void module_remove_modinfo_attrs(struct module *mod, int end);
|
||||
|
||||
static int module_add_modinfo_attrs(struct module *mod)
|
||||
{
|
||||
struct module_attribute *attr;
|
||||
@ -1711,24 +1712,34 @@ static int module_add_modinfo_attrs(struct module *mod)
|
||||
return -ENOMEM;
|
||||
|
||||
temp_attr = mod->modinfo_attrs;
|
||||
for (i = 0; (attr = modinfo_attrs[i]) && !error; i++) {
|
||||
for (i = 0; (attr = modinfo_attrs[i]); i++) {
|
||||
if (!attr->test || attr->test(mod)) {
|
||||
memcpy(temp_attr, attr, sizeof(*temp_attr));
|
||||
sysfs_attr_init(&temp_attr->attr);
|
||||
error = sysfs_create_file(&mod->mkobj.kobj,
|
||||
&temp_attr->attr);
|
||||
if (error)
|
||||
goto error_out;
|
||||
++temp_attr;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error_out:
|
||||
if (i > 0)
|
||||
module_remove_modinfo_attrs(mod, --i);
|
||||
return error;
|
||||
}
|
||||
|
||||
static void module_remove_modinfo_attrs(struct module *mod)
|
||||
static void module_remove_modinfo_attrs(struct module *mod, int end)
|
||||
{
|
||||
struct module_attribute *attr;
|
||||
int i;
|
||||
|
||||
for (i = 0; (attr = &mod->modinfo_attrs[i]); i++) {
|
||||
if (end >= 0 && i > end)
|
||||
break;
|
||||
/* pick a field to test for end of list */
|
||||
if (!attr->attr.name)
|
||||
break;
|
||||
@ -1816,7 +1827,7 @@ static int mod_sysfs_setup(struct module *mod,
|
||||
return 0;
|
||||
|
||||
out_unreg_modinfo_attrs:
|
||||
module_remove_modinfo_attrs(mod);
|
||||
module_remove_modinfo_attrs(mod, -1);
|
||||
out_unreg_param:
|
||||
module_param_sysfs_remove(mod);
|
||||
out_unreg_holders:
|
||||
@ -1852,7 +1863,7 @@ static void mod_sysfs_fini(struct module *mod)
|
||||
{
|
||||
}
|
||||
|
||||
static void module_remove_modinfo_attrs(struct module *mod)
|
||||
static void module_remove_modinfo_attrs(struct module *mod, int end)
|
||||
{
|
||||
}
|
||||
|
||||
@ -1868,14 +1879,14 @@ static void init_param_lock(struct module *mod)
|
||||
static void mod_sysfs_teardown(struct module *mod)
|
||||
{
|
||||
del_usage_links(mod);
|
||||
module_remove_modinfo_attrs(mod);
|
||||
module_remove_modinfo_attrs(mod, -1);
|
||||
module_param_sysfs_remove(mod);
|
||||
kobject_put(mod->mkobj.drivers_dir);
|
||||
kobject_put(mod->holders_dir);
|
||||
mod_sysfs_fini(mod);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_STRICT_MODULE_RWX
|
||||
#ifdef CONFIG_ARCH_HAS_STRICT_MODULE_RWX
|
||||
/*
|
||||
* LKM RO/NX protection: protect module's text/ro-data
|
||||
* from modification and any data from execution.
|
||||
@ -1898,6 +1909,7 @@ static void frob_text(const struct module_layout *layout,
|
||||
layout->text_size >> PAGE_SHIFT);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_STRICT_MODULE_RWX
|
||||
static void frob_rodata(const struct module_layout *layout,
|
||||
int (*set_memory)(unsigned long start, int num_pages))
|
||||
{
|
||||
@ -1949,13 +1961,9 @@ void module_enable_ro(const struct module *mod, bool after_init)
|
||||
set_vm_flush_reset_perms(mod->core_layout.base);
|
||||
set_vm_flush_reset_perms(mod->init_layout.base);
|
||||
frob_text(&mod->core_layout, set_memory_ro);
|
||||
frob_text(&mod->core_layout, set_memory_x);
|
||||
|
||||
frob_rodata(&mod->core_layout, set_memory_ro);
|
||||
|
||||
frob_text(&mod->init_layout, set_memory_ro);
|
||||
frob_text(&mod->init_layout, set_memory_x);
|
||||
|
||||
frob_rodata(&mod->init_layout, set_memory_ro);
|
||||
|
||||
if (after_init)
|
||||
@ -2014,9 +2022,19 @@ void set_all_modules_text_ro(void)
|
||||
}
|
||||
mutex_unlock(&module_mutex);
|
||||
}
|
||||
#else
|
||||
#else /* !CONFIG_STRICT_MODULE_RWX */
|
||||
static void module_enable_nx(const struct module *mod) { }
|
||||
#endif
|
||||
#endif /* CONFIG_STRICT_MODULE_RWX */
|
||||
static void module_enable_x(const struct module *mod)
|
||||
{
|
||||
frob_text(&mod->core_layout, set_memory_x);
|
||||
frob_text(&mod->init_layout, set_memory_x);
|
||||
}
|
||||
#else /* !CONFIG_ARCH_HAS_STRICT_MODULE_RWX */
|
||||
static void module_enable_nx(const struct module *mod) { }
|
||||
static void module_enable_x(const struct module *mod) { }
|
||||
#endif /* CONFIG_ARCH_HAS_STRICT_MODULE_RWX */
|
||||
|
||||
|
||||
#ifdef CONFIG_LIVEPATCH
|
||||
/*
|
||||
@ -2723,6 +2741,11 @@ void * __weak module_alloc(unsigned long size)
|
||||
return vmalloc_exec(size);
|
||||
}
|
||||
|
||||
bool __weak module_exit_section(const char *name)
|
||||
{
|
||||
return strstarts(name, ".exit");
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DEBUG_KMEMLEAK
|
||||
static void kmemleak_load_module(const struct module *mod,
|
||||
const struct load_info *info)
|
||||
@ -2912,7 +2935,7 @@ static int rewrite_section_headers(struct load_info *info, int flags)
|
||||
|
||||
#ifndef CONFIG_MODULE_UNLOAD
|
||||
/* Don't load .exit sections */
|
||||
if (strstarts(info->secstrings+shdr->sh_name, ".exit"))
|
||||
if (module_exit_section(info->secstrings+shdr->sh_name))
|
||||
shdr->sh_flags &= ~(unsigned long)SHF_ALLOC;
|
||||
#endif
|
||||
}
|
||||
@ -3390,8 +3413,7 @@ static bool finished_loading(const char *name)
|
||||
sched_annotate_sleep();
|
||||
mutex_lock(&module_mutex);
|
||||
mod = find_module_all(name, strlen(name), true);
|
||||
ret = !mod || mod->state == MODULE_STATE_LIVE
|
||||
|| mod->state == MODULE_STATE_GOING;
|
||||
ret = !mod || mod->state == MODULE_STATE_LIVE;
|
||||
mutex_unlock(&module_mutex);
|
||||
|
||||
return ret;
|
||||
@ -3581,8 +3603,7 @@ again:
|
||||
mutex_lock(&module_mutex);
|
||||
old = find_module_all(mod->name, strlen(mod->name), true);
|
||||
if (old != NULL) {
|
||||
if (old->state == MODULE_STATE_COMING
|
||||
|| old->state == MODULE_STATE_UNFORMED) {
|
||||
if (old->state != MODULE_STATE_LIVE) {
|
||||
/* Wait in case it fails to load. */
|
||||
mutex_unlock(&module_mutex);
|
||||
err = wait_event_interruptible(module_wq,
|
||||
@ -3621,6 +3642,7 @@ static int complete_formation(struct module *mod, struct load_info *info)
|
||||
|
||||
module_enable_ro(mod, false);
|
||||
module_enable_nx(mod);
|
||||
module_enable_x(mod);
|
||||
|
||||
/* Mark state as coming so strong_try_module_get() ignores us,
|
||||
* but kallsyms etc. can see us. */
|
||||
|
Loading…
Reference in New Issue
Block a user