Modules updates for v4.10
Summary of modules changes for the 4.10 merge window: * The rodata= cmdline parameter has been extended to additionally apply to module mappings * Fix a hard to hit race between module loader error/clean up handling and ftrace registration * Some code cleanups, notably panic.c and modules code use a unified taint_flags table now. This is much cleaner than duplicating the taint flag code in modules.c Signed-off-by: Jessica Yu <jeyu@redhat.com> -----BEGIN PGP SIGNATURE----- iQIcBAABCgAGBQJYUf6/AAoJEMBFfjjOO8Fy5NoP+gOIus26yWWGymI495jVnX7n wCga5JgwOL0SLBIPmiDVI7K+jz4eoQZb94eJcwkWDuw2/IvOdF1kB8ha1EOBRMSg nb9HfIDlWiAPKkyUxe+k6XDb+BMPN3FUSYmBAKD3utsQkD1JWBLY8Id4e234y8Fo sb3a6rLJbvIEXANrMeU7zO4/y1bVxQAeQPQbVPwlid5s76RKYH6JdGXoo6FKK0uE Z3I8uQjqjmJ5U4vpjjWl0w+Qa7hIm/x05GpirtNxN6ztxjR+98c/4uRIry8oOX+I KqRXDOnJ1l/rCwhp+pGLwPfCoDds+V3bknyOwYoxK3hqVVUAd8H0qd1JQ8XClwyJ jnE0+EQpTt9brOO1Oq2XC+EDjpiuyYm3u91TFwE2VFmP98daBZsX6qY7bm03/GQq ZLRthWPILNX9glGj4nbHQgdAKmRvYDO3SzWjFZNA75Mr2hbRKLJoWNvfgupDgjsF giawxV/OcWXvEX92fzkwoUszpfWwoDhGsbimG2SCKYB87vNniG7wrgdjp5aWHhOL qCUpUhCvE9/dO7kPRinqk5tnpAUGY2jMZ0QgVbpToF6FiHJJSyDjWHR9n0Bl1QTX uAEZB/Hoav9frZ+MQC/1Yzhq5ejDbEm1ByjolJgbjl6YHBlQceL6NQpFmyEkrn7c Tx+Q/PvG7/gfxFGMirf1 =bhCS -----END PGP SIGNATURE----- Merge tag 'modules-for-v4.10' 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.10 merge window: - The rodata= cmdline parameter has been extended to additionally apply to module mappings - Fix a hard to hit race between module loader error/clean up handling and ftrace registration - Some code cleanups, notably panic.c and modules code use a unified taint_flags table now. This is much cleaner than duplicating the taint flag code in modules.c" * tag 'modules-for-v4.10' of git://git.kernel.org/pub/scm/linux/kernel/git/jeyu/linux: module: fix DEBUG_SET_MODULE_RONX typo module: extend 'rodata=off' boot cmdline parameter to module mappings module: Fix a comment above strong_try_module_get() module: When modifying a module's text ignore modules which are going away too module: Ensure a module's state is set accordingly during module coming cleanup code module: remove trailing whitespace taint/module: Clean up global and module taint flags handling modpost: free allocated memory
This commit is contained in:
commit
4d98ead183
@ -126,6 +126,9 @@ void prepare_namespace(void);
|
|||||||
void __init load_default_modules(void);
|
void __init load_default_modules(void);
|
||||||
int __init init_rootfs(void);
|
int __init init_rootfs(void);
|
||||||
|
|
||||||
|
#if defined(CONFIG_DEBUG_RODATA) || defined(CONFIG_DEBUG_SET_MODULE_RONX)
|
||||||
|
extern bool rodata_enabled;
|
||||||
|
#endif
|
||||||
#ifdef CONFIG_DEBUG_RODATA
|
#ifdef CONFIG_DEBUG_RODATA
|
||||||
void mark_rodata_ro(void);
|
void mark_rodata_ro(void);
|
||||||
#endif
|
#endif
|
||||||
|
@ -511,6 +511,15 @@ extern enum system_states {
|
|||||||
#define TAINT_UNSIGNED_MODULE 13
|
#define TAINT_UNSIGNED_MODULE 13
|
||||||
#define TAINT_SOFTLOCKUP 14
|
#define TAINT_SOFTLOCKUP 14
|
||||||
#define TAINT_LIVEPATCH 15
|
#define TAINT_LIVEPATCH 15
|
||||||
|
#define TAINT_FLAGS_COUNT 16
|
||||||
|
|
||||||
|
struct taint_flag {
|
||||||
|
char true; /* character printed when tainted */
|
||||||
|
char false; /* character printed when not tainted */
|
||||||
|
bool module; /* also show as a per-module taint flag */
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const struct taint_flag taint_flags[TAINT_FLAGS_COUNT];
|
||||||
|
|
||||||
extern const char hex_asc[];
|
extern const char hex_asc[];
|
||||||
#define hex_asc_lo(x) hex_asc[((x) & 0x0f)]
|
#define hex_asc_lo(x) hex_asc[((x) & 0x0f)]
|
||||||
|
@ -399,7 +399,7 @@ struct module {
|
|||||||
/* Arch-specific module values */
|
/* Arch-specific module values */
|
||||||
struct mod_arch_specific arch;
|
struct mod_arch_specific arch;
|
||||||
|
|
||||||
unsigned int taints; /* same bits as kernel:tainted */
|
unsigned long taints; /* same bits as kernel:taint_flags */
|
||||||
|
|
||||||
#ifdef CONFIG_GENERIC_BUG
|
#ifdef CONFIG_GENERIC_BUG
|
||||||
/* Support for BUG */
|
/* Support for BUG */
|
||||||
@ -412,7 +412,7 @@ struct module {
|
|||||||
/* Protected by RCU and/or module_mutex: use rcu_dereference() */
|
/* Protected by RCU and/or module_mutex: use rcu_dereference() */
|
||||||
struct mod_kallsyms *kallsyms;
|
struct mod_kallsyms *kallsyms;
|
||||||
struct mod_kallsyms core_kallsyms;
|
struct mod_kallsyms core_kallsyms;
|
||||||
|
|
||||||
/* Section attributes */
|
/* Section attributes */
|
||||||
struct module_sect_attrs *sect_attrs;
|
struct module_sect_attrs *sect_attrs;
|
||||||
|
|
||||||
|
@ -81,6 +81,7 @@
|
|||||||
#include <linux/integrity.h>
|
#include <linux/integrity.h>
|
||||||
#include <linux/proc_ns.h>
|
#include <linux/proc_ns.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
|
#include <linux/cache.h>
|
||||||
|
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
#include <asm/bugs.h>
|
#include <asm/bugs.h>
|
||||||
@ -925,14 +926,16 @@ static int try_to_run_init_process(const char *init_filename)
|
|||||||
|
|
||||||
static noinline void __init kernel_init_freeable(void);
|
static noinline void __init kernel_init_freeable(void);
|
||||||
|
|
||||||
#ifdef CONFIG_DEBUG_RODATA
|
#if defined(CONFIG_DEBUG_RODATA) || defined(CONFIG_DEBUG_SET_MODULE_RONX)
|
||||||
static bool rodata_enabled = true;
|
bool rodata_enabled __ro_after_init = true;
|
||||||
static int __init set_debug_rodata(char *str)
|
static int __init set_debug_rodata(char *str)
|
||||||
{
|
{
|
||||||
return strtobool(str, &rodata_enabled);
|
return strtobool(str, &rodata_enabled);
|
||||||
}
|
}
|
||||||
__setup("rodata=", set_debug_rodata);
|
__setup("rodata=", set_debug_rodata);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_DEBUG_RODATA
|
||||||
static void mark_readonly(void)
|
static void mark_readonly(void)
|
||||||
{
|
{
|
||||||
if (rodata_enabled)
|
if (rodata_enabled)
|
||||||
|
@ -313,8 +313,11 @@ struct load_info {
|
|||||||
} index;
|
} index;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* We require a truly strong try_module_get(): 0 means failure due to
|
/*
|
||||||
ongoing or failed initialization etc. */
|
* We require a truly strong try_module_get(): 0 means success.
|
||||||
|
* Otherwise an error is returned due to ongoing or failed
|
||||||
|
* initialization etc.
|
||||||
|
*/
|
||||||
static inline int strong_try_module_get(struct module *mod)
|
static inline int strong_try_module_get(struct module *mod)
|
||||||
{
|
{
|
||||||
BUG_ON(mod && mod->state == MODULE_STATE_UNFORMED);
|
BUG_ON(mod && mod->state == MODULE_STATE_UNFORMED);
|
||||||
@ -330,7 +333,7 @@ static inline void add_taint_module(struct module *mod, unsigned flag,
|
|||||||
enum lockdep_ok lockdep_ok)
|
enum lockdep_ok lockdep_ok)
|
||||||
{
|
{
|
||||||
add_taint(flag, lockdep_ok);
|
add_taint(flag, lockdep_ok);
|
||||||
mod->taints |= (1U << flag);
|
set_bit(flag, &mod->taints);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1138,24 +1141,13 @@ static inline int module_unload_init(struct module *mod)
|
|||||||
static size_t module_flags_taint(struct module *mod, char *buf)
|
static size_t module_flags_taint(struct module *mod, char *buf)
|
||||||
{
|
{
|
||||||
size_t l = 0;
|
size_t l = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < TAINT_FLAGS_COUNT; i++) {
|
||||||
|
if (taint_flags[i].module && test_bit(i, &mod->taints))
|
||||||
|
buf[l++] = taint_flags[i].true;
|
||||||
|
}
|
||||||
|
|
||||||
if (mod->taints & (1 << TAINT_PROPRIETARY_MODULE))
|
|
||||||
buf[l++] = 'P';
|
|
||||||
if (mod->taints & (1 << TAINT_OOT_MODULE))
|
|
||||||
buf[l++] = 'O';
|
|
||||||
if (mod->taints & (1 << TAINT_FORCED_MODULE))
|
|
||||||
buf[l++] = 'F';
|
|
||||||
if (mod->taints & (1 << TAINT_CRAP))
|
|
||||||
buf[l++] = 'C';
|
|
||||||
if (mod->taints & (1 << TAINT_UNSIGNED_MODULE))
|
|
||||||
buf[l++] = 'E';
|
|
||||||
if (mod->taints & (1 << TAINT_LIVEPATCH))
|
|
||||||
buf[l++] = 'K';
|
|
||||||
/*
|
|
||||||
* TAINT_FORCED_RMMOD: could be added.
|
|
||||||
* TAINT_CPU_OUT_OF_SPEC, TAINT_MACHINE_CHECK, TAINT_BAD_PAGE don't
|
|
||||||
* apply to modules.
|
|
||||||
*/
|
|
||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1911,6 +1903,9 @@ static void frob_writable_data(const struct module_layout *layout,
|
|||||||
/* livepatching wants to disable read-only so it can frob module. */
|
/* livepatching wants to disable read-only so it can frob module. */
|
||||||
void module_disable_ro(const struct module *mod)
|
void module_disable_ro(const struct module *mod)
|
||||||
{
|
{
|
||||||
|
if (!rodata_enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
frob_text(&mod->core_layout, set_memory_rw);
|
frob_text(&mod->core_layout, set_memory_rw);
|
||||||
frob_rodata(&mod->core_layout, set_memory_rw);
|
frob_rodata(&mod->core_layout, set_memory_rw);
|
||||||
frob_ro_after_init(&mod->core_layout, set_memory_rw);
|
frob_ro_after_init(&mod->core_layout, set_memory_rw);
|
||||||
@ -1920,6 +1915,9 @@ void module_disable_ro(const struct module *mod)
|
|||||||
|
|
||||||
void module_enable_ro(const struct module *mod, bool after_init)
|
void module_enable_ro(const struct module *mod, bool after_init)
|
||||||
{
|
{
|
||||||
|
if (!rodata_enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
frob_text(&mod->core_layout, set_memory_ro);
|
frob_text(&mod->core_layout, set_memory_ro);
|
||||||
frob_rodata(&mod->core_layout, set_memory_ro);
|
frob_rodata(&mod->core_layout, set_memory_ro);
|
||||||
frob_text(&mod->init_layout, set_memory_ro);
|
frob_text(&mod->init_layout, set_memory_ro);
|
||||||
@ -1952,6 +1950,9 @@ void set_all_modules_text_rw(void)
|
|||||||
{
|
{
|
||||||
struct module *mod;
|
struct module *mod;
|
||||||
|
|
||||||
|
if (!rodata_enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
mutex_lock(&module_mutex);
|
mutex_lock(&module_mutex);
|
||||||
list_for_each_entry_rcu(mod, &modules, list) {
|
list_for_each_entry_rcu(mod, &modules, list) {
|
||||||
if (mod->state == MODULE_STATE_UNFORMED)
|
if (mod->state == MODULE_STATE_UNFORMED)
|
||||||
@ -1968,9 +1969,18 @@ void set_all_modules_text_ro(void)
|
|||||||
{
|
{
|
||||||
struct module *mod;
|
struct module *mod;
|
||||||
|
|
||||||
|
if (!rodata_enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
mutex_lock(&module_mutex);
|
mutex_lock(&module_mutex);
|
||||||
list_for_each_entry_rcu(mod, &modules, list) {
|
list_for_each_entry_rcu(mod, &modules, list) {
|
||||||
if (mod->state == MODULE_STATE_UNFORMED)
|
/*
|
||||||
|
* Ignore going modules since it's possible that ro
|
||||||
|
* protection has already been disabled, otherwise we'll
|
||||||
|
* run into protection faults at module deallocation.
|
||||||
|
*/
|
||||||
|
if (mod->state == MODULE_STATE_UNFORMED ||
|
||||||
|
mod->state == MODULE_STATE_GOING)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
frob_text(&mod->core_layout, set_memory_ro);
|
frob_text(&mod->core_layout, set_memory_ro);
|
||||||
@ -1981,10 +1991,12 @@ void set_all_modules_text_ro(void)
|
|||||||
|
|
||||||
static void disable_ro_nx(const struct module_layout *layout)
|
static void disable_ro_nx(const struct module_layout *layout)
|
||||||
{
|
{
|
||||||
frob_text(layout, set_memory_rw);
|
if (rodata_enabled) {
|
||||||
frob_rodata(layout, set_memory_rw);
|
frob_text(layout, set_memory_rw);
|
||||||
|
frob_rodata(layout, set_memory_rw);
|
||||||
|
frob_ro_after_init(layout, set_memory_rw);
|
||||||
|
}
|
||||||
frob_rodata(layout, set_memory_x);
|
frob_rodata(layout, set_memory_x);
|
||||||
frob_ro_after_init(layout, set_memory_rw);
|
|
||||||
frob_ro_after_init(layout, set_memory_x);
|
frob_ro_after_init(layout, set_memory_x);
|
||||||
frob_writable_data(layout, set_memory_x);
|
frob_writable_data(layout, set_memory_x);
|
||||||
}
|
}
|
||||||
@ -3709,6 +3721,7 @@ static int load_module(struct load_info *info, const char __user *uargs,
|
|||||||
sysfs_cleanup:
|
sysfs_cleanup:
|
||||||
mod_sysfs_teardown(mod);
|
mod_sysfs_teardown(mod);
|
||||||
coming_cleanup:
|
coming_cleanup:
|
||||||
|
mod->state = MODULE_STATE_GOING;
|
||||||
blocking_notifier_call_chain(&module_notify_list,
|
blocking_notifier_call_chain(&module_notify_list,
|
||||||
MODULE_STATE_GOING, mod);
|
MODULE_STATE_GOING, mod);
|
||||||
klp_module_going(mod);
|
klp_module_going(mod);
|
||||||
@ -4042,6 +4055,10 @@ int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *,
|
|||||||
}
|
}
|
||||||
#endif /* CONFIG_KALLSYMS */
|
#endif /* CONFIG_KALLSYMS */
|
||||||
|
|
||||||
|
/* Maximum number of characters written by module_flags() */
|
||||||
|
#define MODULE_FLAGS_BUF_SIZE (TAINT_FLAGS_COUNT + 4)
|
||||||
|
|
||||||
|
/* Keep in sync with MODULE_FLAGS_BUF_SIZE !!! */
|
||||||
static char *module_flags(struct module *mod, char *buf)
|
static char *module_flags(struct module *mod, char *buf)
|
||||||
{
|
{
|
||||||
int bx = 0;
|
int bx = 0;
|
||||||
@ -4086,7 +4103,7 @@ static void m_stop(struct seq_file *m, void *p)
|
|||||||
static int m_show(struct seq_file *m, void *p)
|
static int m_show(struct seq_file *m, void *p)
|
||||||
{
|
{
|
||||||
struct module *mod = list_entry(p, struct module, list);
|
struct module *mod = list_entry(p, struct module, list);
|
||||||
char buf[8];
|
char buf[MODULE_FLAGS_BUF_SIZE];
|
||||||
|
|
||||||
/* We always ignore unformed modules. */
|
/* We always ignore unformed modules. */
|
||||||
if (mod->state == MODULE_STATE_UNFORMED)
|
if (mod->state == MODULE_STATE_UNFORMED)
|
||||||
@ -4257,7 +4274,7 @@ EXPORT_SYMBOL_GPL(__module_text_address);
|
|||||||
void print_modules(void)
|
void print_modules(void)
|
||||||
{
|
{
|
||||||
struct module *mod;
|
struct module *mod;
|
||||||
char buf[8];
|
char buf[MODULE_FLAGS_BUF_SIZE];
|
||||||
|
|
||||||
printk(KERN_DEFAULT "Modules linked in:");
|
printk(KERN_DEFAULT "Modules linked in:");
|
||||||
/* Most callers should already have preempt disabled, but make sure */
|
/* Most callers should already have preempt disabled, but make sure */
|
||||||
|
@ -298,30 +298,27 @@ void panic(const char *fmt, ...)
|
|||||||
|
|
||||||
EXPORT_SYMBOL(panic);
|
EXPORT_SYMBOL(panic);
|
||||||
|
|
||||||
|
/*
|
||||||
struct tnt {
|
* TAINT_FORCED_RMMOD could be a per-module flag but the module
|
||||||
u8 bit;
|
* is being removed anyway.
|
||||||
char true;
|
*/
|
||||||
char false;
|
const struct taint_flag taint_flags[TAINT_FLAGS_COUNT] = {
|
||||||
};
|
{ 'P', 'G', true }, /* TAINT_PROPRIETARY_MODULE */
|
||||||
|
{ 'F', ' ', true }, /* TAINT_FORCED_MODULE */
|
||||||
static const struct tnt tnts[] = {
|
{ 'S', ' ', false }, /* TAINT_CPU_OUT_OF_SPEC */
|
||||||
{ TAINT_PROPRIETARY_MODULE, 'P', 'G' },
|
{ 'R', ' ', false }, /* TAINT_FORCED_RMMOD */
|
||||||
{ TAINT_FORCED_MODULE, 'F', ' ' },
|
{ 'M', ' ', false }, /* TAINT_MACHINE_CHECK */
|
||||||
{ TAINT_CPU_OUT_OF_SPEC, 'S', ' ' },
|
{ 'B', ' ', false }, /* TAINT_BAD_PAGE */
|
||||||
{ TAINT_FORCED_RMMOD, 'R', ' ' },
|
{ 'U', ' ', false }, /* TAINT_USER */
|
||||||
{ TAINT_MACHINE_CHECK, 'M', ' ' },
|
{ 'D', ' ', false }, /* TAINT_DIE */
|
||||||
{ TAINT_BAD_PAGE, 'B', ' ' },
|
{ 'A', ' ', false }, /* TAINT_OVERRIDDEN_ACPI_TABLE */
|
||||||
{ TAINT_USER, 'U', ' ' },
|
{ 'W', ' ', false }, /* TAINT_WARN */
|
||||||
{ TAINT_DIE, 'D', ' ' },
|
{ 'C', ' ', true }, /* TAINT_CRAP */
|
||||||
{ TAINT_OVERRIDDEN_ACPI_TABLE, 'A', ' ' },
|
{ 'I', ' ', false }, /* TAINT_FIRMWARE_WORKAROUND */
|
||||||
{ TAINT_WARN, 'W', ' ' },
|
{ 'O', ' ', true }, /* TAINT_OOT_MODULE */
|
||||||
{ TAINT_CRAP, 'C', ' ' },
|
{ 'E', ' ', true }, /* TAINT_UNSIGNED_MODULE */
|
||||||
{ TAINT_FIRMWARE_WORKAROUND, 'I', ' ' },
|
{ 'L', ' ', false }, /* TAINT_SOFTLOCKUP */
|
||||||
{ TAINT_OOT_MODULE, 'O', ' ' },
|
{ 'K', ' ', true }, /* TAINT_LIVEPATCH */
|
||||||
{ TAINT_UNSIGNED_MODULE, 'E', ' ' },
|
|
||||||
{ TAINT_SOFTLOCKUP, 'L', ' ' },
|
|
||||||
{ TAINT_LIVEPATCH, 'K', ' ' },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -348,16 +345,16 @@ static const struct tnt tnts[] = {
|
|||||||
*/
|
*/
|
||||||
const char *print_tainted(void)
|
const char *print_tainted(void)
|
||||||
{
|
{
|
||||||
static char buf[ARRAY_SIZE(tnts) + sizeof("Tainted: ")];
|
static char buf[TAINT_FLAGS_COUNT + sizeof("Tainted: ")];
|
||||||
|
|
||||||
if (tainted_mask) {
|
if (tainted_mask) {
|
||||||
char *s;
|
char *s;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
s = buf + sprintf(buf, "Tainted: ");
|
s = buf + sprintf(buf, "Tainted: ");
|
||||||
for (i = 0; i < ARRAY_SIZE(tnts); i++) {
|
for (i = 0; i < TAINT_FLAGS_COUNT; i++) {
|
||||||
const struct tnt *t = &tnts[i];
|
const struct taint_flag *t = &taint_flags[i];
|
||||||
*s++ = test_bit(t->bit, &tainted_mask) ?
|
*s++ = test_bit(i, &tainted_mask) ?
|
||||||
t->true : t->false;
|
t->true : t->false;
|
||||||
}
|
}
|
||||||
*s = 0;
|
*s = 0;
|
||||||
|
@ -2371,6 +2371,7 @@ static void write_dump(const char *fname)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
write_if_changed(&buf, fname);
|
write_if_changed(&buf, fname);
|
||||||
|
free(buf.p);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ext_sym_list {
|
struct ext_sym_list {
|
||||||
@ -2496,6 +2497,7 @@ int main(int argc, char **argv)
|
|||||||
"Set CONFIG_SECTION_MISMATCH_WARN_ONLY=y to allow them.\n");
|
"Set CONFIG_SECTION_MISMATCH_WARN_ONLY=y to allow them.\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
free(buf.p);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user