Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

kpatch-build: account for __pfx_-less NOP padding #1350

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 52 additions & 2 deletions kpatch-build/create-diff-object.c
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,54 @@ static struct rela *toc_rela(const struct rela *rela)
(unsigned int)rela->addend);
}

/*
* Some x86 kernels have NOP function padding, see upstream commit
* bea75b33895f ("x86/Kconfig: Introduce function padding").
* Check for any amount of NOPs between the beginning of a function's
* section and its offset value within that section.
*/
static bool insn_is_nop_pad(struct kpatch_elf *kelf, void *addr, void *end,
unsigned long *insn_len)
{
unsigned char *insn = addr;

switch(kelf->arch) {

case X86_64:
if (insn[0] == 0x90) {
*insn_len = 1;
return true;
}
break;

case PPC64:
case S390:
/* kernel feature not present on these arches */
return false;

default:
ERROR("unsupported arch");
}

return false;
}

bool is_function_nop_padded(struct kpatch_elf *kelf, struct symbol *sym)
{
unsigned long offset, insn_len;
void *end = sym->sec->data->d_buf + sym->sym.st_value;

if (sym->type != STT_FUNC)
return false;

for (offset = 0; offset < sym->sym.st_value; offset += insn_len) {
if (!insn_is_nop_pad(kelf, sym->sec->data->d_buf + offset, end, &insn_len))
return false;
}

return true;
}

/*
* When compiling with -ffunction-sections and -fdata-sections, almost every
* symbol gets its own dedicated section. We call such symbols "bundled"
Expand All @@ -236,19 +284,21 @@ static struct rela *toc_rela(const struct rela *rela)
static void kpatch_bundle_symbols(struct kpatch_elf *kelf)
{
struct symbol *sym;
unsigned int expected_offset;
Elf64_Addr expected_offset;

list_for_each_entry(sym, &kelf->symbols, list) {
if (is_bundleable(sym)) {
if (sym->pfx)
expected_offset = 16;
else if (is_gcc6_localentry_bundled_sym(kelf, sym))
expected_offset = 8;
else if (is_function_nop_padded(kelf, sym))
expected_offset = sym->sym.st_value;
else
expected_offset = 0;

if (sym->sym.st_value != expected_offset) {
ERROR("symbol %s at offset %lu within section %s, expected %u",
ERROR("symbol %s at offset %lu within section %s, expected %lu",
sym->name, sym->sym.st_value,
sym->sec->name, expected_offset);
}
Expand Down
4 changes: 2 additions & 2 deletions kpatch-build/kpatch-elf.c
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,7 @@ static void kpatch_create_section_list(struct kpatch_elf *kelf)

/*
* Some x86 kernels have NOP function padding [1] for which objtool [2]
* adds ELF function symbols with prefix "__pfx_" to indicate the start
* may add ELF function symbols with prefix "__pfx_" to indicate the start
* of a function, inclusive of NOP-padding. Find the prefix symbols and
* link them to their corresponding function symbols at an expected
* offset.
Expand Down Expand Up @@ -438,7 +438,7 @@ static void kpatch_create_section_list(struct kpatch_elf *kelf)
* 0000000000000000 0 SECTION LOCAL DEFAULT 99 .text.unlikely.__mmdrop
* 0000000000000000 48 FUNC LOCAL DEFAULT 99 __mmdrop.cold
*
* (kpatch-build generated tmp.ko, multple functions in one section, no __pfx_ symbols)
* (kpatch-build generated tmp.ko, multiple functions in one section, no __pfx_ symbols)
* 0000000000000000 0 SECTION LOCAL DEFAULT 10 .text.unlikely.callback_info.isra.0
* 0000000000000010 65 FUNC LOCAL DEFAULT 10 callback_info.isra.0
* 0000000000000061 54 FUNC LOCAL DEFAULT 10 callback_info.isra.0
Expand Down