diff options
Diffstat (limited to 'kernel/module.c')
-rw-r--r-- | kernel/module.c | 55 |
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 */ | ||
2993 | struct mod_initfree { | ||
2994 | struct rcu_head rcu; | ||
2995 | void *module_init; | ||
2996 | }; | ||
2997 | |||
2998 | static 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 */ |
2993 | static int do_init_module(struct module *mod) | 3006 | static 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 | |||
3091 | fail_free_freeinit: | ||
3092 | kfree(freeinit); | ||
3093 | fail: | ||
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 | ||
3076 | static int may_init_module(void) | 3105 | static int may_init_module(void) |