Skip to content

Commit

Permalink
kpatch-build: account for __pfx_-less NOP padding
Browse files Browse the repository at this point in the history
Some kernel configurations generate function NOP padding, but without
associated __pfx_<function> symbols.  For example:

  $ git describe HEAD
  v6.4-rc7-72-gdad9774deaf1

  # Initial default config turns on Indirect Branch Tracking and 16-NOP padding bytes
  $ make defconfig
  $ grep -e CONFIG_X86_KERNEL_IBT -e CONFIG_FUNCTION_PADDING_BYTES .config
  CONFIG_X86_KERNEL_IBT=y
  CONFIG_FUNCTION_PADDING_BYTES=16

  # Test .o build generates 16 bytes of NOPs but no "__pfx_" symbol
  $ make -j$(nproc) fs/proc/cmdline.o
  $ objdump -Dr -j .text fs/proc/cmdline.o  | grep -e '<.*>:' -e 'Disassembly'
  Disassembly of section .text:
  0000000000000000 <cmdline_proc_show-0x10>:
  0000000000000010 <cmdline_proc_show>:

This is because objtool operation on the object code may be delayed
under certain configurations.  As such, create-diff-object should be
prepared to encounter NOP padded functions in object files before any
__pfx_ symbols are created.

Fixes: 3e54c63 ("create-diff-object: support x86 NOP-padded functions")
Closes: #1347 ("x86 NOP padded functions without __pfx_ symbol")
Signed-off-by: Joe Lawrence <[email protected]>
  • Loading branch information
joe-lawrence committed Jul 13, 2023
1 parent f8d2534 commit 419f7c2
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 4 deletions.
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

0 comments on commit 419f7c2

Please sign in to comment.