diff --git a/kmod/core/core.c b/kmod/core/core.c index cb6c18c..edb5029 100644 --- a/kmod/core/core.c +++ b/kmod/core/core.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include "kpatch.h" @@ -650,6 +651,19 @@ static int kpatch_write_relocations(struct kpatch_module *kpmod, return -EINVAL; } + /* + * Skip it if the instruction to be relocated has been + * changed already (paravirt or alternatives may do this). + */ + if (memchr_inv((void *)loc, 0, size)) { + pr_notice("Skipped dynrela for %s (0x%lx <- 0x%lx): the instruction has been changed already.\n", + dynrela->name, dynrela->dest, dynrela->src); + pr_notice_once( +"This is not necessarily a bug but it may indicate in some cases " +"that the binary patch does not handle paravirt operations, alternatives or the like properly.\n"); + continue; + } + #ifdef CONFIG_DEBUG_SET_MODULE_RONX #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0) if (loc < core + kpmod->mod->core_layout.ro_size)