diff options
Diffstat (limited to 'kernel/livepatch/core.c')
| -rw-r--r-- | kernel/livepatch/core.c | 44 | 
1 files changed, 34 insertions, 10 deletions
| diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c index ab4a4606d19b..c3512e7e0801 100644 --- a/kernel/livepatch/core.c +++ b/kernel/livepatch/core.c @@ -22,6 +22,7 @@  #include <asm/cacheflush.h>  #include "core.h"  #include "patch.h" +#include "state.h"  #include "transition.h"  /* @@ -632,7 +633,7 @@ static void klp_free_objects_dynamic(struct klp_patch *patch)   * The operation must be completed by calling klp_free_patch_finish()   * outside klp_mutex.   */ -void klp_free_patch_start(struct klp_patch *patch) +static void klp_free_patch_start(struct klp_patch *patch)  {  	if (!list_empty(&patch->list))  		list_del(&patch->list); @@ -677,6 +678,23 @@ static void klp_free_patch_work_fn(struct work_struct *work)  	klp_free_patch_finish(patch);  } +void klp_free_patch_async(struct klp_patch *patch) +{ +	klp_free_patch_start(patch); +	schedule_work(&patch->free_work); +} + +void klp_free_replaced_patches_async(struct klp_patch *new_patch) +{ +	struct klp_patch *old_patch, *tmp_patch; + +	klp_for_each_patch_safe(old_patch, tmp_patch) { +		if (old_patch == new_patch) +			return; +		klp_free_patch_async(old_patch); +	} +} +  static int klp_init_func(struct klp_object *obj, struct klp_func *func)  {  	if (!func->old_name) @@ -992,6 +1010,13 @@ int klp_enable_patch(struct klp_patch *patch)  	mutex_lock(&klp_mutex); +	if (!klp_is_patch_compatible(patch)) { +		pr_err("Livepatch patch (%s) is not compatible with the already installed livepatches.\n", +			patch->mod->name); +		mutex_unlock(&klp_mutex); +		return -EINVAL; +	} +  	ret = klp_init_patch_early(patch);  	if (ret) {  		mutex_unlock(&klp_mutex); @@ -1022,12 +1047,13 @@ err:  EXPORT_SYMBOL_GPL(klp_enable_patch);  /* - * This function removes replaced patches. + * This function unpatches objects from the replaced livepatches.   *   * We could be pretty aggressive here. It is called in the situation where - * these structures are no longer accessible. All functions are redirected - * by the klp_transition_patch. They use either a new code or they are in - * the original code because of the special nop function patches. + * these structures are no longer accessed from the ftrace handler. + * All functions are redirected by the klp_transition_patch. They + * use either a new code or they are in the original code because + * of the special nop function patches.   *   * The only exception is when the transition was forced. In this case,   * klp_ftrace_handler() might still see the replaced patch on the stack. @@ -1035,18 +1061,16 @@ EXPORT_SYMBOL_GPL(klp_enable_patch);   * thanks to RCU. We only have to keep the patches on the system. Also   * this is handled transparently by patch->module_put.   */ -void klp_discard_replaced_patches(struct klp_patch *new_patch) +void klp_unpatch_replaced_patches(struct klp_patch *new_patch)  { -	struct klp_patch *old_patch, *tmp_patch; +	struct klp_patch *old_patch; -	klp_for_each_patch_safe(old_patch, tmp_patch) { +	klp_for_each_patch(old_patch) {  		if (old_patch == new_patch)  			return;  		old_patch->enabled = false;  		klp_unpatch_objects(old_patch); -		klp_free_patch_start(old_patch); -		schedule_work(&old_patch->free_work);  	}  } | 

