aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/livepatch/core.c
diff options
context:
space:
mode:
authorJiri Kosina <jkosina@suse.cz>2019-03-05 09:56:59 -0500
committerJiri Kosina <jkosina@suse.cz>2019-03-05 09:56:59 -0500
commitf9d138145686b52b48ccb36557d6842076e2b9dd (patch)
tree95f5c8952a06616ddf4e7ed0288b82bfdb3aea72 /kernel/livepatch/core.c
parent7185a96981a2f8bb523dd87cad20a6b96c721ad5 (diff)
parentfbb76d579dff4a2e332566dcd1d5979ac92bc34b (diff)
Merge branch 'for-5.1/atomic-replace' into for-linus
The atomic replace allows to create cumulative patches. They are useful when you maintain many livepatches and want to remove one that is lower on the stack. In addition it is very useful when more patches touch the same function and there are dependencies between them. It's also a feature some of the distros are using already to distribute their patches.
Diffstat (limited to 'kernel/livepatch/core.c')
-rw-r--r--kernel/livepatch/core.c36
1 files changed, 11 insertions, 25 deletions
diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c
index fe1993399823..eb0ee10a1981 100644
--- a/kernel/livepatch/core.c
+++ b/kernel/livepatch/core.c
@@ -522,7 +522,7 @@ static int klp_add_nops(struct klp_patch *patch)
522 struct klp_patch *old_patch; 522 struct klp_patch *old_patch;
523 struct klp_object *old_obj; 523 struct klp_object *old_obj;
524 524
525 list_for_each_entry(old_patch, &klp_patches, list) { 525 klp_for_each_patch(old_patch) {
526 klp_for_each_object(old_patch, old_obj) { 526 klp_for_each_object(old_patch, old_obj) {
527 int err; 527 int err;
528 528
@@ -1004,7 +1004,7 @@ int klp_enable_patch(struct klp_patch *patch)
1004 1004
1005 if (!klp_have_reliable_stack()) { 1005 if (!klp_have_reliable_stack()) {
1006 pr_err("This architecture doesn't have support for the livepatch consistency model.\n"); 1006 pr_err("This architecture doesn't have support for the livepatch consistency model.\n");
1007 return -ENOSYS; 1007 return -EOPNOTSUPP;
1008 } 1008 }
1009 1009
1010 1010
@@ -1057,7 +1057,7 @@ void klp_discard_replaced_patches(struct klp_patch *new_patch)
1057{ 1057{
1058 struct klp_patch *old_patch, *tmp_patch; 1058 struct klp_patch *old_patch, *tmp_patch;
1059 1059
1060 list_for_each_entry_safe(old_patch, tmp_patch, &klp_patches, list) { 1060 klp_for_each_patch_safe(old_patch, tmp_patch) {
1061 if (old_patch == new_patch) 1061 if (old_patch == new_patch)
1062 return; 1062 return;
1063 1063
@@ -1101,7 +1101,7 @@ static void klp_cleanup_module_patches_limited(struct module *mod,
1101 struct klp_patch *patch; 1101 struct klp_patch *patch;
1102 struct klp_object *obj; 1102 struct klp_object *obj;
1103 1103
1104 list_for_each_entry(patch, &klp_patches, list) { 1104 klp_for_each_patch(patch) {
1105 if (patch == limit) 1105 if (patch == limit)
1106 break; 1106 break;
1107 1107
@@ -1109,21 +1109,14 @@ static void klp_cleanup_module_patches_limited(struct module *mod,
1109 if (!klp_is_module(obj) || strcmp(obj->name, mod->name)) 1109 if (!klp_is_module(obj) || strcmp(obj->name, mod->name))
1110 continue; 1110 continue;
1111 1111
1112 /* 1112 if (patch != klp_transition_patch)
1113 * Only unpatch the module if the patch is enabled or 1113 klp_pre_unpatch_callback(obj);
1114 * is in transition.
1115 */
1116 if (patch->enabled || patch == klp_transition_patch) {
1117
1118 if (patch != klp_transition_patch)
1119 klp_pre_unpatch_callback(obj);
1120 1114
1121 pr_notice("reverting patch '%s' on unloading module '%s'\n", 1115 pr_notice("reverting patch '%s' on unloading module '%s'\n",
1122 patch->mod->name, obj->mod->name); 1116 patch->mod->name, obj->mod->name);
1123 klp_unpatch_object(obj); 1117 klp_unpatch_object(obj);
1124 1118
1125 klp_post_unpatch_callback(obj); 1119 klp_post_unpatch_callback(obj);
1126 }
1127 1120
1128 klp_free_object_loaded(obj); 1121 klp_free_object_loaded(obj);
1129 break; 1122 break;
@@ -1148,7 +1141,7 @@ int klp_module_coming(struct module *mod)
1148 */ 1141 */
1149 mod->klp_alive = true; 1142 mod->klp_alive = true;
1150 1143
1151 list_for_each_entry(patch, &klp_patches, list) { 1144 klp_for_each_patch(patch) {
1152 klp_for_each_object(patch, obj) { 1145 klp_for_each_object(patch, obj) {
1153 if (!klp_is_module(obj) || strcmp(obj->name, mod->name)) 1146 if (!klp_is_module(obj) || strcmp(obj->name, mod->name))
1154 continue; 1147 continue;
@@ -1162,13 +1155,6 @@ int klp_module_coming(struct module *mod)
1162 goto err; 1155 goto err;
1163 } 1156 }
1164 1157
1165 /*
1166 * Only patch the module if the patch is enabled or is
1167 * in transition.
1168 */
1169 if (!patch->enabled && patch != klp_transition_patch)
1170 break;
1171
1172 pr_notice("applying patch '%s' to loading module '%s'\n", 1158 pr_notice("applying patch '%s' to loading module '%s'\n",
1173 patch->mod->name, obj->mod->name); 1159 patch->mod->name, obj->mod->name);
1174 1160