From 8dac9d0871e120d67ca0f35997cb068b935153c4 Mon Sep 17 00:00:00 2001 From: Evgenii Shatokhin Date: Mon, 28 Mar 2016 12:11:59 +0300 Subject: [PATCH] kmod/core: Skip relocations of already altered instructions When a patch module is loaded, the kernel facilities like alternatives and paravirt may alter some of its instructions. This happens before Kpatch core module is notified and tries to apply dynrelas to it. If an instruction to apply a dynrela to has already been changed by these facilities, an incorrect instruction might be written as a result. The core module now detects such conditions and does not apply dynrela to the changed instructions. Suggested by Josh Poimboeuf in the discussion of https://github.com/dynup/kpatch/issues/580. Changes in v.2: * Used pr_notice to give more emphasis to the messages. * Added an explanation message. Signed-off-by: Evgenii Shatokhin --- kmod/core/core.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) 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)