aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/module.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/module.c')
-rw-r--r--kernel/module.c55
1 files changed, 42 insertions, 13 deletions
diff --git a/kernel/module.c b/kernel/module.c
index 1f85fd5c89d3..ed4ec9c30bd2 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -2989,10 +2989,31 @@ static void do_mod_ctors(struct module *mod)
2989#endif 2989#endif
2990} 2990}
2991 2991
2992/* For freeing module_init on success, in case kallsyms traversing */
2993struct mod_initfree {
2994 struct rcu_head rcu;
2995 void *module_init;
2996};
2997
2998static void do_free_init(struct rcu_head *head)
2999{
3000 struct mod_initfree *m = container_of(head, struct mod_initfree, rcu);
3001 module_memfree(m->module_init);
3002 kfree(m);
3003}
3004
2992/* This is where the real work happens */ 3005/* This is where the real work happens */
2993static int do_init_module(struct module *mod) 3006static int do_init_module(struct module *mod)
2994{ 3007{
2995 int ret = 0; 3008 int ret = 0;
3009 struct mod_initfree *freeinit;
3010
3011 freeinit = kmalloc(sizeof(*freeinit), GFP_KERNEL);
3012 if (!freeinit) {
3013 ret = -ENOMEM;
3014 goto fail;
3015 }
3016 freeinit->module_init = mod->module_init;
2996 3017
2997 /* 3018 /*
2998 * We want to find out whether @mod uses async during init. Clear 3019 * We want to find out whether @mod uses async during init. Clear
@@ -3005,18 +3026,7 @@ static int do_init_module(struct module *mod)
3005 if (mod->init != NULL) 3026 if (mod->init != NULL)
3006 ret = do_one_initcall(mod->init); 3027 ret = do_one_initcall(mod->init);
3007 if (ret < 0) { 3028 if (ret < 0) {
3008 /* 3029 goto fail_free_freeinit;
3009 * Init routine failed: abort. Try to protect us from
3010 * buggy refcounters.
3011 */
3012 mod->state = MODULE_STATE_GOING;
3013 synchronize_sched();
3014 module_put(mod);
3015 blocking_notifier_call_chain(&module_notify_list,
3016 MODULE_STATE_GOING, mod);
3017 free_module(mod);
3018 wake_up_all(&module_wq);
3019 return ret;
3020 } 3030 }
3021 if (ret > 0) { 3031 if (ret > 0) {
3022 pr_warn("%s: '%s'->init suspiciously returned %d, it should " 3032 pr_warn("%s: '%s'->init suspiciously returned %d, it should "
@@ -3062,15 +3072,34 @@ static int do_init_module(struct module *mod)
3062#endif 3072#endif
3063 unset_module_init_ro_nx(mod); 3073 unset_module_init_ro_nx(mod);
3064 module_arch_freeing_init(mod); 3074 module_arch_freeing_init(mod);
3065 module_memfree(mod->module_init);
3066 mod->module_init = NULL; 3075 mod->module_init = NULL;
3067 mod->init_size = 0; 3076 mod->init_size = 0;
3068 mod->init_ro_size = 0; 3077 mod->init_ro_size = 0;
3069 mod->init_text_size = 0; 3078 mod->init_text_size = 0;
3079 /*
3080 * We want to free module_init, but be aware that kallsyms may be
3081 * walking this with preempt disabled. In all the failure paths,
3082 * we call synchronize_rcu/synchronize_sched, but we don't want
3083 * to slow down the success path, so use actual RCU here.
3084 */
3085 call_rcu(&freeinit->rcu, do_free_init);
3070 mutex_unlock(&module_mutex); 3086 mutex_unlock(&module_mutex);
3071 wake_up_all(&module_wq); 3087 wake_up_all(&module_wq);
3072 3088
3073 return 0; 3089 return 0;
3090
3091fail_free_freeinit:
3092 kfree(freeinit);
3093fail:
3094 /* Try to protect us from buggy refcounters. */
3095 mod->state = MODULE_STATE_GOING;
3096 synchronize_sched();
3097 module_put(mod);
3098 blocking_notifier_call_chain(&module_notify_list,
3099 MODULE_STATE_GOING, mod);
3100 free_module(mod);
3101 wake_up_all(&module_wq);
3102 return ret;
3074} 3103}
3075 3104
3076static int may_init_module(void) 3105static int may_init_module(void)