aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/livepatch/core.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-11-15 13:21:58 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2017-11-15 13:21:58 -0500
commit0ef76878cfcf4d6b64972b283021f576a95d9216 (patch)
tree387f5bf5bff34738550686c0306e97528dc69711 /kernel/livepatch/core.c
parent9682b3dea22190a6fd449d157e3175b0e748684d (diff)
parentfc41efc1843009ebcdb4850b21f1c371ad203f4e (diff)
Merge branch 'for-linus' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/jikos/livepatching
Pull livepatching updates from Jiri Kosina: - shadow variables support, allowing livepatches to associate new "shadow" fields to existing data structures, from Joe Lawrence - pre/post patch callbacks API, allowing livepatch writers to register callbacks to be called before and after patch application, from Joe Lawrence * 'for-linus' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/jikos/livepatching: livepatch: __klp_disable_patch() should never be called for disabled patches livepatch: Correctly call klp_post_unpatch_callback() in error paths livepatch: add transition notices livepatch: move transition "complete" notice into klp_complete_transition() livepatch: add (un)patch callbacks livepatch: Small shadow variable documentation fixes livepatch: __klp_shadow_get_or_alloc() is local to shadow.c livepatch: introduce shadow variable API
Diffstat (limited to 'kernel/livepatch/core.c')
-rw-r--r--kernel/livepatch/core.c52
1 files changed, 42 insertions, 10 deletions
diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c
index bf8c8fd72589..de9e45dca70f 100644
--- a/kernel/livepatch/core.c
+++ b/kernel/livepatch/core.c
@@ -54,11 +54,6 @@ static bool klp_is_module(struct klp_object *obj)
54 return obj->name; 54 return obj->name;
55} 55}
56 56
57static bool klp_is_object_loaded(struct klp_object *obj)
58{
59 return !obj->name || obj->mod;
60}
61
62/* sets obj->mod if object is not vmlinux and module is found */ 57/* sets obj->mod if object is not vmlinux and module is found */
63static void klp_find_object_module(struct klp_object *obj) 58static void klp_find_object_module(struct klp_object *obj)
64{ 59{
@@ -285,6 +280,11 @@ static int klp_write_object_relocations(struct module *pmod,
285 280
286static int __klp_disable_patch(struct klp_patch *patch) 281static int __klp_disable_patch(struct klp_patch *patch)
287{ 282{
283 struct klp_object *obj;
284
285 if (WARN_ON(!patch->enabled))
286 return -EINVAL;
287
288 if (klp_transition_patch) 288 if (klp_transition_patch)
289 return -EBUSY; 289 return -EBUSY;
290 290
@@ -295,6 +295,10 @@ static int __klp_disable_patch(struct klp_patch *patch)
295 295
296 klp_init_transition(patch, KLP_UNPATCHED); 296 klp_init_transition(patch, KLP_UNPATCHED);
297 297
298 klp_for_each_object(patch, obj)
299 if (obj->patched)
300 klp_pre_unpatch_callback(obj);
301
298 /* 302 /*
299 * Enforce the order of the func->transition writes in 303 * Enforce the order of the func->transition writes in
300 * klp_init_transition() and the TIF_PATCH_PENDING writes in 304 * klp_init_transition() and the TIF_PATCH_PENDING writes in
@@ -388,13 +392,18 @@ static int __klp_enable_patch(struct klp_patch *patch)
388 if (!klp_is_object_loaded(obj)) 392 if (!klp_is_object_loaded(obj))
389 continue; 393 continue;
390 394
391 ret = klp_patch_object(obj); 395 ret = klp_pre_patch_callback(obj);
392 if (ret) { 396 if (ret) {
393 pr_warn("failed to enable patch '%s'\n", 397 pr_warn("pre-patch callback failed for object '%s'\n",
394 patch->mod->name); 398 klp_is_module(obj) ? obj->name : "vmlinux");
399 goto err;
400 }
395 401
396 klp_cancel_transition(); 402 ret = klp_patch_object(obj);
397 return ret; 403 if (ret) {
404 pr_warn("failed to patch object '%s'\n",
405 klp_is_module(obj) ? obj->name : "vmlinux");
406 goto err;
398 } 407 }
399 } 408 }
400 409
@@ -403,6 +412,11 @@ static int __klp_enable_patch(struct klp_patch *patch)
403 patch->enabled = true; 412 patch->enabled = true;
404 413
405 return 0; 414 return 0;
415err:
416 pr_warn("failed to enable patch '%s'\n", patch->mod->name);
417
418 klp_cancel_transition();
419 return ret;
406} 420}
407 421
408/** 422/**
@@ -854,9 +868,15 @@ static void klp_cleanup_module_patches_limited(struct module *mod,
854 * is in transition. 868 * is in transition.
855 */ 869 */
856 if (patch->enabled || patch == klp_transition_patch) { 870 if (patch->enabled || patch == klp_transition_patch) {
871
872 if (patch != klp_transition_patch)
873 klp_pre_unpatch_callback(obj);
874
857 pr_notice("reverting patch '%s' on unloading module '%s'\n", 875 pr_notice("reverting patch '%s' on unloading module '%s'\n",
858 patch->mod->name, obj->mod->name); 876 patch->mod->name, obj->mod->name);
859 klp_unpatch_object(obj); 877 klp_unpatch_object(obj);
878
879 klp_post_unpatch_callback(obj);
860 } 880 }
861 881
862 klp_free_object_loaded(obj); 882 klp_free_object_loaded(obj);
@@ -906,13 +926,25 @@ int klp_module_coming(struct module *mod)
906 pr_notice("applying patch '%s' to loading module '%s'\n", 926 pr_notice("applying patch '%s' to loading module '%s'\n",
907 patch->mod->name, obj->mod->name); 927 patch->mod->name, obj->mod->name);
908 928
929 ret = klp_pre_patch_callback(obj);
930 if (ret) {
931 pr_warn("pre-patch callback failed for object '%s'\n",
932 obj->name);
933 goto err;
934 }
935
909 ret = klp_patch_object(obj); 936 ret = klp_patch_object(obj);
910 if (ret) { 937 if (ret) {
911 pr_warn("failed to apply patch '%s' to module '%s' (%d)\n", 938 pr_warn("failed to apply patch '%s' to module '%s' (%d)\n",
912 patch->mod->name, obj->mod->name, ret); 939 patch->mod->name, obj->mod->name, ret);
940
941 klp_post_unpatch_callback(obj);
913 goto err; 942 goto err;
914 } 943 }
915 944
945 if (patch != klp_transition_patch)
946 klp_post_patch_callback(obj);
947
916 break; 948 break;
917 } 949 }
918 } 950 }