diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-11-15 13:21:58 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-11-15 13:21:58 -0500 |
commit | 0ef76878cfcf4d6b64972b283021f576a95d9216 (patch) | |
tree | 387f5bf5bff34738550686c0306e97528dc69711 /kernel/livepatch/core.c | |
parent | 9682b3dea22190a6fd449d157e3175b0e748684d (diff) | |
parent | fc41efc1843009ebcdb4850b21f1c371ad203f4e (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.c | 52 |
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 | ||
57 | static 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 */ |
63 | static void klp_find_object_module(struct klp_object *obj) | 58 | static 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 | ||
286 | static int __klp_disable_patch(struct klp_patch *patch) | 281 | static 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; |
415 | err: | ||
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 | } |