diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-11-25 19:43:48 -0800 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-11-25 19:43:48 -0800 | 
| commit | f838767555d40f29bc4771c5c8cc63193094b7cc (patch) | |
| tree | 50d126b8fd20a8f50e13263529805e8eaea73db3 /kernel/livepatch/core.c | |
| parent | 436b2a8039ac00f8dc6ae8f3bd2be83748f72312 (diff) | |
| parent | 0e672adc87e5ae1758b6e0571b42d743a8324327 (diff) | |
| download | blackbird-op-linux-f838767555d40f29bc4771c5c8cc63193094b7cc.tar.gz blackbird-op-linux-f838767555d40f29bc4771c5c8cc63193094b7cc.zip | |
Merge tag 'livepatching-for-5.5' of git://git.kernel.org/pub/scm/linux/kernel/git/livepatching/livepatching
Pull livepatching updates from Petr Mladek:
 - New API to track system state changes done be livepatch callbacks. It
   helps to maintain compatibility between livepatches.
 - Update Kconfig help text. ORC is another reliable unwinder.
 - Disable generic selftest timeout. Livepatch selftests have their own
   per-operation fine-grained timeouts.
* tag 'livepatching-for-5.5' of git://git.kernel.org/pub/scm/linux/kernel/git/livepatching/livepatching:
  x86/stacktrace: update kconfig help text for reliable unwinders
  livepatch: Selftests of the API for tracking system state changes
  livepatch: Documentation of the new API for tracking system state changes
  livepatch: Allow to distinguish different version of system state changes
  livepatch: Basic API to track system state changes
  livepatch: Keep replaced patches until post_patch callback is called
  selftests/livepatch: Disable the timeout
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);  	}  } | 

