mirror of https://github.com/dynup/kpatch
detect and ignore WARN-only changes
WARN-only function changes are very common, and a serious PITA for patch authors. Detect and ignore them. Fixes #454.
This commit is contained in:
parent
bb6edd16f9
commit
4c7fb9119a
|
@ -649,17 +649,118 @@ out:
|
||||||
log_debug("section %s has changed\n", sec->name);
|
log_debug("section %s has changed\n", sec->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Determine if a section has changed only due to a WARN* macro call's
|
||||||
|
* embedding of the line number into an instruction operand.
|
||||||
|
*
|
||||||
|
* Warning: Hackery lies herein. It's hopefully justified by the fact that
|
||||||
|
* this issue is very common.
|
||||||
|
*
|
||||||
|
* base object:
|
||||||
|
*
|
||||||
|
* 28e: be de 10 00 00 mov $0x10de,%esi
|
||||||
|
* 293: 48 c7 c7 00 00 00 00 mov $0x0,%rdi
|
||||||
|
* 29a: e8 00 00 00 00 callq 29f <emulator_read_write_onepage+0x29f>
|
||||||
|
*
|
||||||
|
* patched object:
|
||||||
|
*
|
||||||
|
* 28e: be df 10 00 00 mov $0x10df,%esi
|
||||||
|
* 293: 48 c7 c7 00 00 00 00 mov $0x0,%rdi
|
||||||
|
* 29a: e8 00 00 00 00 callq 29f <emulator_read_write_onepage+0x29f>
|
||||||
|
*/
|
||||||
|
static int kpatch_warn_only_change(struct section *sec)
|
||||||
|
{
|
||||||
|
struct insn insn1, insn2;
|
||||||
|
unsigned long start1, start2, size, offset, length;
|
||||||
|
struct rela *rela;
|
||||||
|
int warnonly = 0, found;
|
||||||
|
|
||||||
|
if (sec->status != CHANGED ||
|
||||||
|
is_rela_section(sec) ||
|
||||||
|
!is_text_section(sec) ||
|
||||||
|
sec->sh.sh_size != sec->twin->sh.sh_size ||
|
||||||
|
!sec->rela ||
|
||||||
|
sec->rela->status != SAME)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
start1 = (unsigned long)sec->twin->data->d_buf;
|
||||||
|
start2 = (unsigned long)sec->data->d_buf;
|
||||||
|
size = sec->sh.sh_size;
|
||||||
|
for (offset = 0; offset < size; offset += length) {
|
||||||
|
insn_init(&insn1, (void *)(start1 + offset), 1);
|
||||||
|
insn_init(&insn2, (void *)(start2 + offset), 1);
|
||||||
|
insn_get_length(&insn1);
|
||||||
|
insn_get_length(&insn2);
|
||||||
|
length = insn1.length;
|
||||||
|
|
||||||
|
if (!insn1.length || !insn2.length)
|
||||||
|
ERROR("can't decode instruction in section %s at offset 0x%lx",
|
||||||
|
sec->name, offset);
|
||||||
|
|
||||||
|
if (insn1.length != insn2.length)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!memcmp((void *)start1 + offset, (void *)start2 + offset,
|
||||||
|
length))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* verify it's a mov immediate to %esi */
|
||||||
|
insn_get_opcode(&insn1);
|
||||||
|
insn_get_opcode(&insn2);
|
||||||
|
if (insn1.opcode.value != 0xbe || insn2.opcode.value != 0xbe)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* verify the next instruction is mov $0x0,%rdi */
|
||||||
|
if (*(unsigned int *)(start1 + offset + length) != 0xc7c748)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* verify the instruction after that is callq */
|
||||||
|
if (*(unsigned int *)(start1 + offset + length + 7) != 0xe8)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* verify the callq's rela is for warn_slowpath_null */
|
||||||
|
found = 0;
|
||||||
|
list_for_each_entry(rela, &sec->rela->relas, list) {
|
||||||
|
if (rela->offset == offset + length + 8 &&
|
||||||
|
!strcmp(rela->sym->name, "warn_slowpath_null")) {
|
||||||
|
found = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
warnonly = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!warnonly)
|
||||||
|
ERROR("no instruction changes detected for changed section %s", sec->name);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
void kpatch_compare_sections(struct list_head *seclist)
|
void kpatch_compare_sections(struct list_head *seclist)
|
||||||
{
|
{
|
||||||
struct section *sec;
|
struct section *sec;
|
||||||
|
|
||||||
|
/* compare all sections */
|
||||||
list_for_each_entry(sec, seclist, list) {
|
list_for_each_entry(sec, seclist, list) {
|
||||||
if (sec->twin)
|
if (sec->twin)
|
||||||
kpatch_compare_correlated_section(sec);
|
kpatch_compare_correlated_section(sec);
|
||||||
else
|
else
|
||||||
sec->status = NEW;
|
sec->status = NEW;
|
||||||
|
}
|
||||||
|
|
||||||
/* sync symbol status */
|
/* exclude WARN-only changes */
|
||||||
|
list_for_each_entry(sec, seclist, list)
|
||||||
|
if (kpatch_warn_only_change(sec)) {
|
||||||
|
log_debug("reverting WARN-only section %s status to SAME\n",
|
||||||
|
sec->name);
|
||||||
|
sec->status = SAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* sync symbol status */
|
||||||
|
list_for_each_entry(sec, seclist, list) {
|
||||||
if (is_rela_section(sec)) {
|
if (is_rela_section(sec)) {
|
||||||
if (sec->base->sym && sec->base->sym->status != CHANGED)
|
if (sec->base->sym && sec->base->sym->status != CHANGED)
|
||||||
sec->base->sym->status = sec->status;
|
sec->base->sym->status = sec->status;
|
||||||
|
|
|
@ -11,19 +11,3 @@ Index: src/arch/x86/kvm/x86.c
|
||||||
if (slot >= shared_msrs_global.nr)
|
if (slot >= shared_msrs_global.nr)
|
||||||
shared_msrs_global.nr = slot + 1;
|
shared_msrs_global.nr = slot + 1;
|
||||||
shared_msrs_global.msrs[slot] = msr;
|
shared_msrs_global.msrs[slot] = msr;
|
||||||
@@ -6307,6 +6309,7 @@ static int complete_emulated_mmio(struct
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
+#include "kpatch-macros.h"
|
|
||||||
int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
|
|
||||||
{
|
|
||||||
int r;
|
|
||||||
@@ -6352,6 +6355,7 @@ out:
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
+KPATCH_IGNORE_FUNCTION(kvm_arch_vcpu_ioctl_run);
|
|
||||||
|
|
||||||
int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
|
|
||||||
{
|
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
Index: src/arch/x86/kvm/x86.c
|
||||||
|
===================================================================
|
||||||
|
--- src.orig/arch/x86/kvm/x86.c
|
||||||
|
+++ src/arch/x86/kvm/x86.c
|
||||||
|
@@ -1,3 +1,4 @@
|
||||||
|
+
|
||||||
|
/*
|
||||||
|
* Kernel-based Virtual Machine driver for Linux
|
||||||
|
*
|
Loading…
Reference in New Issue