aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/livepatch
diff options
context:
space:
mode:
authorMinfei Huang <mnfhuang@gmail.com>2015-05-14 22:22:48 -0400
committerJiri Kosina <jkosina@suse.cz>2015-05-18 05:08:44 -0400
commit36e505c16e610403c110bab76a95cbfa0436a928 (patch)
tree8fcf5d4dc272250b01926d5d4cb690ee563a60f9 /kernel/livepatch
parente76ff06a959336fae64b53c36ec60940ca6ef04f (diff)
livepatch: Prevent patch inconsistencies if the coming module notifier fails
The previous patches can be applied, once the corresponding module is loaded. In general, the patch will do relocation (if necessary) and obtain/verify function address before we start to enable patch. There are three different situations in which the coming module notifier can fail: 1) relocations are not applied for some reason. In this case kallsyms for module symbol is not called at all. The patch is not applied to the module. If the user disable and enable patch again, there is possible bug in klp_enable_func. If the user specified func->old_addr for some function in the module (and he shouldn't do that, but nevertheless) our warning would not catch it, ftrace will reject to register the handler because of wrong address or will register the handler for wrong address. 2) relocations are applied successfully, but kallsyms lookup fails. In this case func->old_addr can be correct for all previous lookups, 0 for current failed one, and "unspecified" for the rest. If we undergo the same scenario as in 1, the behaviour differs for three cases, but the patch is not enabled anyway. 3) the object is initialized, but klp_enable_object fails in the notifier due to possible ftrace error. Since it is improbable that ftrace would heal itself in the future, we would get those errors everytime the patch is enabled. In order to fix above situations, we can make obj->mod to NULL, if the coming modified notifier fails. Signed-off-by: Minfei Huang <mnfhuang@gmail.com> Acked-by: Josh Poimboeuf <jpoimboe@redhat.com> Reviewed-by: Miroslav Benes <mbenes@suse.cz> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'kernel/livepatch')
-rw-r--r--kernel/livepatch/core.c29
1 files changed, 18 insertions, 11 deletions
diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c
index c5e631cd151b..c03c04637ec6 100644
--- a/kernel/livepatch/core.c
+++ b/kernel/livepatch/core.c
@@ -883,7 +883,7 @@ int klp_register_patch(struct klp_patch *patch)
883} 883}
884EXPORT_SYMBOL_GPL(klp_register_patch); 884EXPORT_SYMBOL_GPL(klp_register_patch);
885 885
886static void klp_module_notify_coming(struct klp_patch *patch, 886static int klp_module_notify_coming(struct klp_patch *patch,
887 struct klp_object *obj) 887 struct klp_object *obj)
888{ 888{
889 struct module *pmod = patch->mod; 889 struct module *pmod = patch->mod;
@@ -891,22 +891,23 @@ static void klp_module_notify_coming(struct klp_patch *patch,
891 int ret; 891 int ret;
892 892
893 ret = klp_init_object_loaded(patch, obj); 893 ret = klp_init_object_loaded(patch, obj);
894 if (ret) 894 if (ret) {
895 goto err; 895 pr_warn("failed to initialize patch '%s' for module '%s' (%d)\n",
896 pmod->name, mod->name, ret);
897 return ret;
898 }
896 899
897 if (patch->state == KLP_DISABLED) 900 if (patch->state == KLP_DISABLED)
898 return; 901 return 0;
899 902
900 pr_notice("applying patch '%s' to loading module '%s'\n", 903 pr_notice("applying patch '%s' to loading module '%s'\n",
901 pmod->name, mod->name); 904 pmod->name, mod->name);
902 905
903 ret = klp_enable_object(obj); 906 ret = klp_enable_object(obj);
904 if (!ret) 907 if (ret)
905 return; 908 pr_warn("failed to apply patch '%s' to module '%s' (%d)\n",
906 909 pmod->name, mod->name, ret);
907err: 910 return ret;
908 pr_warn("failed to apply patch '%s' to module '%s' (%d)\n",
909 pmod->name, mod->name, ret);
910} 911}
911 912
912static void klp_module_notify_going(struct klp_patch *patch, 913static void klp_module_notify_going(struct klp_patch *patch,
@@ -930,6 +931,7 @@ disabled:
930static int klp_module_notify(struct notifier_block *nb, unsigned long action, 931static int klp_module_notify(struct notifier_block *nb, unsigned long action,
931 void *data) 932 void *data)
932{ 933{
934 int ret;
933 struct module *mod = data; 935 struct module *mod = data;
934 struct klp_patch *patch; 936 struct klp_patch *patch;
935 struct klp_object *obj; 937 struct klp_object *obj;
@@ -955,7 +957,12 @@ static int klp_module_notify(struct notifier_block *nb, unsigned long action,
955 957
956 if (action == MODULE_STATE_COMING) { 958 if (action == MODULE_STATE_COMING) {
957 obj->mod = mod; 959 obj->mod = mod;
958 klp_module_notify_coming(patch, obj); 960 ret = klp_module_notify_coming(patch, obj);
961 if (ret) {
962 obj->mod = NULL;
963 pr_warn("patch '%s' is in an inconsistent state!\n",
964 patch->mod->name);
965 }
959 } else /* MODULE_STATE_GOING */ 966 } else /* MODULE_STATE_GOING */
960 klp_module_notify_going(patch, obj); 967 klp_module_notify_going(patch, obj);
961 968