diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-10-12 12:21:56 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-10-12 12:21:56 -0400 |
| commit | 0de50ea7b5c9e232dcd1cc07c014509c324ff1b8 (patch) | |
| tree | 484e28bb828b15e896fa240def13662cbe886cbb /kernel | |
| parent | be7484acc6fee2878dc8d1593ba81fb1e0b3d581 (diff) | |
| parent | ef8daf8eeb5b8ab6bc356656163d19f20fb827ed (diff) | |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/livepatching
Pull livepatching fix from Jiri Kosina:
- bugfix for handling of coming modules (incorrect handling of failure)
from Joe Lawrence
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/livepatching:
livepatch: unpatch all klp_objects if klp_module_coming fails
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/livepatch/core.c | 60 |
1 files changed, 37 insertions, 23 deletions
diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c index b9628e43c78f..bf8c8fd72589 100644 --- a/kernel/livepatch/core.c +++ b/kernel/livepatch/core.c | |||
| @@ -830,6 +830,41 @@ int klp_register_patch(struct klp_patch *patch) | |||
| 830 | } | 830 | } |
| 831 | EXPORT_SYMBOL_GPL(klp_register_patch); | 831 | EXPORT_SYMBOL_GPL(klp_register_patch); |
| 832 | 832 | ||
| 833 | /* | ||
| 834 | * Remove parts of patches that touch a given kernel module. The list of | ||
| 835 | * patches processed might be limited. When limit is NULL, all patches | ||
| 836 | * will be handled. | ||
| 837 | */ | ||
| 838 | static void klp_cleanup_module_patches_limited(struct module *mod, | ||
| 839 | struct klp_patch *limit) | ||
| 840 | { | ||
| 841 | struct klp_patch *patch; | ||
| 842 | struct klp_object *obj; | ||
| 843 | |||
| 844 | list_for_each_entry(patch, &klp_patches, list) { | ||
| 845 | if (patch == limit) | ||
| 846 | break; | ||
| 847 | |||
| 848 | klp_for_each_object(patch, obj) { | ||
| 849 | if (!klp_is_module(obj) || strcmp(obj->name, mod->name)) | ||
| 850 | continue; | ||
| 851 | |||
| 852 | /* | ||
| 853 | * Only unpatch the module if the patch is enabled or | ||
| 854 | * is in transition. | ||
| 855 | */ | ||
| 856 | if (patch->enabled || patch == klp_transition_patch) { | ||
| 857 | pr_notice("reverting patch '%s' on unloading module '%s'\n", | ||
| 858 | patch->mod->name, obj->mod->name); | ||
| 859 | klp_unpatch_object(obj); | ||
| 860 | } | ||
| 861 | |||
| 862 | klp_free_object_loaded(obj); | ||
| 863 | break; | ||
| 864 | } | ||
| 865 | } | ||
| 866 | } | ||
| 867 | |||
| 833 | int klp_module_coming(struct module *mod) | 868 | int klp_module_coming(struct module *mod) |
| 834 | { | 869 | { |
| 835 | int ret; | 870 | int ret; |
| @@ -894,7 +929,7 @@ err: | |||
| 894 | pr_warn("patch '%s' failed for module '%s', refusing to load module '%s'\n", | 929 | pr_warn("patch '%s' failed for module '%s', refusing to load module '%s'\n", |
| 895 | patch->mod->name, obj->mod->name, obj->mod->name); | 930 | patch->mod->name, obj->mod->name, obj->mod->name); |
| 896 | mod->klp_alive = false; | 931 | mod->klp_alive = false; |
| 897 | klp_free_object_loaded(obj); | 932 | klp_cleanup_module_patches_limited(mod, patch); |
| 898 | mutex_unlock(&klp_mutex); | 933 | mutex_unlock(&klp_mutex); |
| 899 | 934 | ||
| 900 | return ret; | 935 | return ret; |
| @@ -902,9 +937,6 @@ err: | |||
| 902 | 937 | ||
| 903 | void klp_module_going(struct module *mod) | 938 | void klp_module_going(struct module *mod) |
| 904 | { | 939 | { |
| 905 | struct klp_patch *patch; | ||
| 906 | struct klp_object *obj; | ||
| 907 | |||
| 908 | if (WARN_ON(mod->state != MODULE_STATE_GOING && | 940 | if (WARN_ON(mod->state != MODULE_STATE_GOING && |
| 909 | mod->state != MODULE_STATE_COMING)) | 941 | mod->state != MODULE_STATE_COMING)) |
| 910 | return; | 942 | return; |
| @@ -917,25 +949,7 @@ void klp_module_going(struct module *mod) | |||
| 917 | */ | 949 | */ |
| 918 | mod->klp_alive = false; | 950 | mod->klp_alive = false; |
| 919 | 951 | ||
| 920 | list_for_each_entry(patch, &klp_patches, list) { | 952 | klp_cleanup_module_patches_limited(mod, NULL); |
| 921 | klp_for_each_object(patch, obj) { | ||
| 922 | if (!klp_is_module(obj) || strcmp(obj->name, mod->name)) | ||
| 923 | continue; | ||
| 924 | |||
| 925 | /* | ||
| 926 | * Only unpatch the module if the patch is enabled or | ||
| 927 | * is in transition. | ||
| 928 | */ | ||
| 929 | if (patch->enabled || patch == klp_transition_patch) { | ||
| 930 | pr_notice("reverting patch '%s' on unloading module '%s'\n", | ||
| 931 | patch->mod->name, obj->mod->name); | ||
| 932 | klp_unpatch_object(obj); | ||
| 933 | } | ||
| 934 | |||
| 935 | klp_free_object_loaded(obj); | ||
| 936 | break; | ||
| 937 | } | ||
| 938 | } | ||
| 939 | 953 | ||
| 940 | mutex_unlock(&klp_mutex); | 954 | mutex_unlock(&klp_mutex); |
| 941 | } | 955 | } |
