kmod/core: Check all patched functions only if replacement is in progress

kpatch_verify_activeness_safety() calls kpatch_backtrace_address_verify()
for each address in the call traces of the processes.

Among other things, kpatch_backtrace_address_verify() searches the whole
set of functions for the ones being replaced (func->op == KPATCH_OP_UNPATCH).
This is a waste of time when the patch is loaded or unloaded rather than
replaced. Let us do the searching only if patch replacement is in
progress.

Signed-off-by: Evgenii Shatokhin <eshatokhin@virtuozzo.com>
This commit is contained in:
Evgenii Shatokhin 2019-07-01 18:06:12 +03:00
parent 3bd131612d
commit f447c6f40e

View File

@ -212,7 +212,8 @@ static inline int kpatch_compare_addresses(unsigned long stack_addr,
}
static int kpatch_backtrace_address_verify(struct kpatch_module *kpmod,
unsigned long address)
unsigned long address,
bool replace)
{
struct kpatch_func *func;
int i;
@ -247,8 +248,11 @@ static int kpatch_backtrace_address_verify(struct kpatch_module *kpmod,
} while_for_each_linked_func();
/* in the replace case, need to check the func hash as well */
hash_for_each_rcu(kpatch_func_hash, i, func, node) {
if (func->op == KPATCH_OP_UNPATCH && !func->force) {
if (replace) {
hash_for_each_rcu(kpatch_func_hash, i, func, node) {
if (func->op != KPATCH_OP_UNPATCH || func->force)
continue;
ret = kpatch_compare_addresses(address,
func->new_addr,
func->new_size,
@ -267,7 +271,8 @@ static int kpatch_backtrace_address_verify(struct kpatch_module *kpmod,
*
* This function is called from stop_machine() context.
*/
static int kpatch_verify_activeness_safety(struct kpatch_module *kpmod)
static int kpatch_verify_activeness_safety(struct kpatch_module *kpmod,
bool replace)
{
struct task_struct *g, *t;
int i;
@ -289,7 +294,8 @@ static int kpatch_verify_activeness_safety(struct kpatch_module *kpmod)
if (trace.entries[i] == ULONG_MAX)
break;
ret = kpatch_backtrace_address_verify(kpmod,
trace.entries[i]);
trace.entries[i],
replace);
if (ret)
goto out;
}
@ -365,7 +371,7 @@ static int kpatch_apply_patch(void *data)
kpmod = args->kpmod;
ret = kpatch_verify_activeness_safety(kpmod);
ret = kpatch_verify_activeness_safety(kpmod, args->replace);
if (ret) {
kpatch_state_finish(KPATCH_STATE_FAILURE);
return ret;
@ -440,7 +446,7 @@ static int kpatch_remove_patch(void *data)
struct kpatch_object *object;
int ret;
ret = kpatch_verify_activeness_safety(kpmod);
ret = kpatch_verify_activeness_safety(kpmod, false);
if (ret) {
kpatch_state_finish(KPATCH_STATE_FAILURE);
return ret;