diff options
Diffstat (limited to 'kernel/livepatch')
| -rw-r--r-- | kernel/livepatch/core.c | 60 | ||||
| -rw-r--r-- | kernel/livepatch/core.h | 1 | ||||
| -rw-r--r-- | kernel/livepatch/patch.h | 1 | ||||
| -rw-r--r-- | kernel/livepatch/transition.h | 1 | 
4 files changed, 40 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)  }  EXPORT_SYMBOL_GPL(klp_register_patch); +/* + * Remove parts of patches that touch a given kernel module. The list of + * patches processed might be limited. When limit is NULL, all patches + * will be handled. + */ +static void klp_cleanup_module_patches_limited(struct module *mod, +					       struct klp_patch *limit) +{ +	struct klp_patch *patch; +	struct klp_object *obj; + +	list_for_each_entry(patch, &klp_patches, list) { +		if (patch == limit) +			break; + +		klp_for_each_object(patch, obj) { +			if (!klp_is_module(obj) || strcmp(obj->name, mod->name)) +				continue; + +			/* +			 * Only unpatch the module if the patch is enabled or +			 * is in transition. +			 */ +			if (patch->enabled || patch == klp_transition_patch) { +				pr_notice("reverting patch '%s' on unloading module '%s'\n", +					  patch->mod->name, obj->mod->name); +				klp_unpatch_object(obj); +			} + +			klp_free_object_loaded(obj); +			break; +		} +	} +} +  int klp_module_coming(struct module *mod)  {  	int ret; @@ -894,7 +929,7 @@ err:  	pr_warn("patch '%s' failed for module '%s', refusing to load module '%s'\n",  		patch->mod->name, obj->mod->name, obj->mod->name);  	mod->klp_alive = false; -	klp_free_object_loaded(obj); +	klp_cleanup_module_patches_limited(mod, patch);  	mutex_unlock(&klp_mutex);  	return ret; @@ -902,9 +937,6 @@ err:  void klp_module_going(struct module *mod)  { -	struct klp_patch *patch; -	struct klp_object *obj; -  	if (WARN_ON(mod->state != MODULE_STATE_GOING &&  		    mod->state != MODULE_STATE_COMING))  		return; @@ -917,25 +949,7 @@ void klp_module_going(struct module *mod)  	 */  	mod->klp_alive = false; -	list_for_each_entry(patch, &klp_patches, list) { -		klp_for_each_object(patch, obj) { -			if (!klp_is_module(obj) || strcmp(obj->name, mod->name)) -				continue; - -			/* -			 * Only unpatch the module if the patch is enabled or -			 * is in transition. -			 */ -			if (patch->enabled || patch == klp_transition_patch) { -				pr_notice("reverting patch '%s' on unloading module '%s'\n", -					  patch->mod->name, obj->mod->name); -				klp_unpatch_object(obj); -			} - -			klp_free_object_loaded(obj); -			break; -		} -	} +	klp_cleanup_module_patches_limited(mod, NULL);  	mutex_unlock(&klp_mutex);  } diff --git a/kernel/livepatch/core.h b/kernel/livepatch/core.h index c74f24c47837..a351601d7f76 100644 --- a/kernel/livepatch/core.h +++ b/kernel/livepatch/core.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */  #ifndef _LIVEPATCH_CORE_H  #define _LIVEPATCH_CORE_H diff --git a/kernel/livepatch/patch.h b/kernel/livepatch/patch.h index 0db227170c36..e72d8250d04b 100644 --- a/kernel/livepatch/patch.h +++ b/kernel/livepatch/patch.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */  #ifndef _LIVEPATCH_PATCH_H  #define _LIVEPATCH_PATCH_H diff --git a/kernel/livepatch/transition.h b/kernel/livepatch/transition.h index ce09b326546c..0f6e27c481f9 100644 --- a/kernel/livepatch/transition.h +++ b/kernel/livepatch/transition.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */  #ifndef _LIVEPATCH_TRANSITION_H  #define _LIVEPATCH_TRANSITION_H |