Skip to content

Commit b0f93df

Browse files
create-diff-object: Remove undefined function symbols
When building shadow-pid.patch on a debug kernel, it generates __bug_table, which contains an array of struct bug_entries. .rela__bug_table contains references to bug address, line number and column. create-diff-object identifies that .text.kernel_clone has changed and it includes .rela.text.kernel_clone rela section. Then later, it includes all symbols (in kpatch_include_symbols()) associated with it, which ends up including __bug_table and its rela section .rela__bug_table. Then, all the function symbols associated with .rela__bug_table is included irrespective of whether it's section is included or not. This leads to the following modpost errors: kernel/fork.o: changed function: kernel_clone kernel/exit.o: changed function: do_exit fs/proc/array.o: changed function: proc_pid_status make -C /root/linux M=/root/.kpatch/tmp/patch CFLAGS_MODULE='' make[1]: Entering directory '/root/linux' make[2]: Entering directory '/root/.kpatch/tmp/patch' LDS kpatch.lds CC [M] patch-hook.o LD [M] test-shadow-newpid.o MODPOST Module.symvers WARNING: modpost: missing MODULE_DESCRIPTION() in test-shadow-newpid.o ERROR: modpost: "replace_mm_exe_file" [test-shadow-newpid.ko] undefined! ERROR: modpost: "put_task_stack" [test-shadow-newpid.ko] undefined! ERROR: modpost: "release_task" [test-shadow-newpid.ko] undefined! ERROR: modpost: "set_mm_exe_file" [test-shadow-newpid.ko] undefined! Examining the /root/.kpatch/patch/ directory reveals, these symbols are never referenced in any relas. readelf -Ws output.o | grep -E 'put_task_stack|replace_mm_exe_file|release_task|set_mm_exe_file' 27: 0000000000000000 0 SECTION LOCAL DEFAULT 36 .rodata.release_task.str1.2 45: 0000000000000000 0 SECTION LOCAL DEFAULT 55 .rodata.set_mm_exe_file.str1.2 47: 0000000000000000 0 SECTION LOCAL DEFAULT 57 .rodata.replace_mm_exe_file.str1.2 234: 0000000000000000 0 FUNC GLOBAL DEFAULT UND replace_mm_exe_file 254: 0000000000000000 0 FUNC GLOBAL DEFAULT UND put_task_stack 263: 0000000000000000 0 FUNC GLOBAL DEFAULT UND release_task 269: 0000000000000000 0 FUNC GLOBAL DEFAULT UND set_mm_exe_file readelf -Wr output.o | grep -E 'put_task_stack|replace_mm_exe_file|release_task|set_mm_exe_file' <EMPTY> Hence, exclude these unreferenced symbols to avoid modpost errors. Fix: * Identify all function symbols present in __bug_table and track their symbol indices. * Exclude .rela__bug_table and .rela__mcount_loc, and for all other relocation sections, check whether any of these symbol indices are actually referenced. * If a symbol index is never referenced in any relevant relocation section and the symbol’s section is not included in the patch, exclude the symbol from being added. Note: Skipped need_klp_reloc()/kpatch_create_intermediate_sections() check for .rela__bug_table section. Reason: The function symbols that were not referenced by any sections other than .rela__bug_table were being initialized with include = 0 (via rela->sym->include = 0). As a result, kpatch_migrate_included_elements() did not migrate these function symbols into kelf_out. However, later in kpatch_create_intermediate_sections(), when parsing the .rela__bug_table relasec and evaluating each symbol in need_klp_reloc(), the code ended up using the previous rela->sym reference (which had already been torn down). Since that symbol had its include field set to 0, the dereference led to a segmentation fault. To prevent this, the .rela__bug_table section is excluded from consideration in kpatch_migrate_included_elements(). Additionally, if a function is modified, the assumption is that, it will be referenced by other relasec. Signed-off-by: Sumanth Korikkar <sumanthk@linux.ibm.com>
1 parent 7552b46 commit b0f93df

1 file changed

Lines changed: 66 additions & 2 deletions

File tree

kpatch-build/create-diff-object.c

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2462,6 +2462,69 @@ static int fixup_group_size(struct kpatch_elf *kelf, int offset)
24622462
return (int)(rela->addend - offset);
24632463
}
24642464

2465+
/*
2466+
* Exclude function symbols absent from any rela sections (except
2467+
* .rela__bug_table) to eliminate undefined symbols modpost errors.
2468+
*/
2469+
static void kpatch_exclude_unreferenced_symbols(struct kpatch_elf *kelf)
2470+
{
2471+
struct section *sec, *relasec;
2472+
unsigned int i = 0, count = 0;
2473+
unsigned int *symindex;
2474+
struct symbol *sym;
2475+
struct rela *rela;
2476+
bool found;
2477+
2478+
relasec = find_section_by_name(&kelf->sections, ".rela__bug_table");
2479+
if (!relasec)
2480+
return;
2481+
list_for_each_entry(rela, &relasec->relas, list) {
2482+
if (rela->sym->type == STT_FUNC && rela->sym->sec &&
2483+
!rela->sym->sec->include)
2484+
count++;
2485+
}
2486+
symindex = (unsigned int *)malloc(sizeof(unsigned int) * count);
2487+
if (!symindex)
2488+
ERROR("malloc");
2489+
list_for_each_entry(rela, &relasec->relas, list) {
2490+
if (rela->sym->type == STT_FUNC && rela->sym->sec &&
2491+
!rela->sym->sec->include)
2492+
symindex[i++] = rela->sym->index;
2493+
}
2494+
for (i = 0; i < count; i++) {
2495+
found = false;
2496+
list_for_each_entry(sec, &kelf->sections, list) {
2497+
if (!is_rela_section(sec) ||
2498+
is_debug_section(sec))
2499+
continue;
2500+
if (!strcmp(sec->name, relasec->name) ||
2501+
!strcmp(sec->name, ".rela__mcount_loc") ||
2502+
!sec->include)
2503+
continue;
2504+
list_for_each_entry(rela, &sec->relas, list) {
2505+
if (symindex[i] == rela->sym->index) {
2506+
found = true;
2507+
break;
2508+
}
2509+
}
2510+
}
2511+
if (!found) {
2512+
/*
2513+
* Function symbol is present in only __bug_table.
2514+
* i.e. function symbol was included earlier, but its
2515+
* associated section is not included and not
2516+
* referenced in any relas. Exclude the function symbol
2517+
* to eliminate UND symbols modpost errors.
2518+
*/
2519+
sym = find_symbol_by_index(&kelf->symbols, symindex[i]);
2520+
if (!sym)
2521+
ERROR("could not find function symbol\n");
2522+
sym->include = 0;
2523+
}
2524+
}
2525+
free(symindex);
2526+
}
2527+
24652528
static bool jump_table_group_filter(struct lookup_table *lookup,
24662529
struct section *relasec,
24672530
unsigned int group_offset,
@@ -3684,10 +3747,10 @@ static void kpatch_create_intermediate_sections(struct kpatch_elf *kelf,
36843747
list_for_each_entry(relasec, &kelf->sections, list) {
36853748
if (!is_rela_section(relasec))
36863749
continue;
3687-
if (!strcmp(relasec->name, ".rela.kpatch.funcs"))
3750+
if (!strcmp(relasec->name, ".rela.kpatch.funcs") ||
3751+
!strcmp(relasec->name, ".rela__bug_table"))
36883752
continue;
36893753
list_for_each_entry(rela, &relasec->relas, list) {
3690-
36913754
/* upper bound on number of kpatch relas and symbols */
36923755
nr++;
36933756

@@ -4499,6 +4562,7 @@ int main(int argc, char *argv[])
44994562
kpatch_include_force_elements(kelf_patched);
45004563
new_globals_exist = kpatch_include_new_globals(kelf_patched);
45014564
kpatch_include_debug_sections(kelf_patched);
4565+
kpatch_exclude_unreferenced_symbols(kelf_patched);
45024566

45034567
kpatch_process_special_sections(kelf_patched, lookup);
45044568

0 commit comments

Comments
 (0)