From 052806fe4395af868d24fa09f63a8c1a708ea265 Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Fri, 13 Jun 2014 12:41:35 -0500 Subject: [PATCH] kmod/core: fix replace race condition In the replace case, stop calling module_put on a patch module before we're potentially done with it. This will also be needed for future module patching if we want to properly replace a patch module which only patches a future loaded module (that's a mouthful). Fixes #165. --- kmod/core/core.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/kmod/core/core.c b/kmod/core/core.c index 248146c..cbaf0ec 100644 --- a/kmod/core/core.c +++ b/kmod/core/core.c @@ -707,20 +707,29 @@ int kpatch_register(struct kpatch_module *kpmod, bool replace) * the ftrace filter, and disable the owning patch module so that it * can be removed. */ - if (!ret && replace) + if (!ret && replace) { + struct kpatch_module *kpmod2, *safe; + hash_for_each_rcu(kpatch_func_hash, i, func, node) { if (func->op != KPATCH_OP_UNPATCH) continue; hash_del_rcu(&func->node); WARN_ON(kpatch_ftrace_remove_func(func->old_addr)); - if (func->kpmod->enabled) { - func->kpmod->enabled = false; - pr_notice("unloaded patch module '%s'\n", - func->kpmod->mod->name); - module_put(func->kpmod->mod); - } } + list_for_each_entry_safe(kpmod2, safe, &kpmod_list, list) { + if (kpmod == kpmod2) + continue; + + kpmod2->enabled = false; + pr_notice("unloaded patch module '%s'\n", + kpmod2->mod->name); + module_put(kpmod2->mod); + list_del(&kpmod2->list); + } + } + + /* memory barrier between func hash and state write */ smp_wmb();