Skip to content

Commit 6571f2a

Browse files
create-diff-object: handle .rela__bug_table to avoid pulling in entire __bug_table
When building shadow-pid.patch on a debug kernel, it generates __bug_table, which contains an array of struct bug_entries. 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. The problem occurs since WARN() has been converted to a static call, which passes a reference to its bug table entry (in __bug_table) to the static call. That direct reference from a function to a special section is new, and that's causing create-diff-object to incorrectly pull in the entire __bug_table. (As mentioned by Josh) It leads to the following modpost errors with shadow-pid.patch: 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> Solution: Skip initial symbol inclusion from .rela__bug_table to prevent unwanted __bug_table propagation caused by static call WARN() relocations. These relocations are instead handled later during special section regeneration. Also recalculate addends of relocations targeting __bug_table when bug table entries move, ensuring all references remain consistent. Signed-off-by: Sumanth Korikkar <sumanthk@linux.ibm.com>
1 parent 7552b46 commit 6571f2a

1 file changed

Lines changed: 73 additions & 1 deletion

File tree

kpatch-build/create-diff-object.c

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1886,6 +1886,23 @@ static void kpatch_verify_patchability(struct kpatch_elf *kelf)
18861886
DIFF_FATAL("%d unsupported section change(s)", errs);
18871887
}
18881888

1889+
/*
1890+
* Do not perform symbol inclusion initially from .rela__bug_table.
1891+
*
1892+
* WARN() is converted to a static call which emits relocations that point
1893+
* directly into __bug_table+off. If the usual "include every symbol referenced
1894+
* by this rela section" rule is applied here, it could end up dragging in the
1895+
* entire __bug_table via propagation.
1896+
*
1897+
* .rela__bug_table relocations are processed later in
1898+
* kpatch_regenerate_special_section(), which also adjusts relocations
1899+
* targetting __bug_table.
1900+
*/
1901+
static bool kpatch_skip_symbol_inclusion_from_relasec(struct section *relasec)
1902+
{
1903+
return !strcmp(relasec->name, ".rela__bug_table");
1904+
}
1905+
18891906
static void kpatch_include_symbol(struct symbol *sym);
18901907

18911908
static void kpatch_include_section(struct section *sec)
@@ -1906,6 +1923,8 @@ static void kpatch_include_section(struct section *sec)
19061923
if (!sec->rela)
19071924
return;
19081925
sec->rela->include = 1;
1926+
if (kpatch_skip_symbol_inclusion_from_relasec(sec->rela))
1927+
return;
19091928
list_for_each_entry(rela, &sec->rela->relas, list)
19101929
kpatch_include_symbol(rela->sym);
19111930
}
@@ -2791,14 +2810,52 @@ static void kpatch_update_ex_table_addend(struct kpatch_elf *kelf,
27912810
}
27922811
}
27932812

2813+
static bool is_reloc_to_bug_table(struct rela *rela)
2814+
{
2815+
return !strcmp(rela->sym->name, "__bug_table");
2816+
}
2817+
2818+
static void recalculate_bug_table_rela_addend(struct kpatch_elf *kelf,
2819+
long old_bug_offset,
2820+
long new_bug_offset)
2821+
{
2822+
long add_offset, old_target_offset;
2823+
struct section *relasec;
2824+
struct rela *rela;
2825+
2826+
list_for_each_entry(relasec, &kelf->sections, list) {
2827+
if (!is_rela_section(relasec) ||
2828+
!relasec->include ||
2829+
!strcmp(relasec->name, ".rela__bug_table"))
2830+
continue;
2831+
list_for_each_entry(rela, &relasec->relas, list) {
2832+
if (!is_reloc_to_bug_table(rela))
2833+
continue;
2834+
old_target_offset = rela_target_offset(kelf, relasec, rela);
2835+
if (old_target_offset == old_bug_offset) {
2836+
add_offset = rela_target_offset(kelf, relasec, rela) - rela->addend;
2837+
rela->addend = new_bug_offset - add_offset;
2838+
rela->rela.r_addend = rela->addend;
2839+
log_debug("%s: adjusting rela from %s+%lx to %s+%lx\n",
2840+
relasec->name,
2841+
rela->sym->name,
2842+
old_bug_offset - add_offset,
2843+
rela->sym->name,
2844+
new_bug_offset - add_offset);
2845+
}
2846+
}
2847+
}
2848+
2849+
}
2850+
27942851
static void kpatch_regenerate_special_section(struct kpatch_elf *kelf,
27952852
struct lookup_table *lookup,
27962853
struct special_section *special,
27972854
struct section *relasec)
27982855
{
27992856
struct rela *rela, *safe;
28002857
char *src, *dest;
2801-
unsigned int group_size, src_offset, dest_offset;
2858+
unsigned int group_size, src_offset, dest_offset, new_offset;
28022859

28032860
LIST_HEAD(newrelas);
28042861

@@ -2852,6 +2909,21 @@ static void kpatch_regenerate_special_section(struct kpatch_elf *kelf,
28522909
list_del(&rela->list);
28532910
list_add_tail(&rela->list, &newrelas);
28542911

2912+
if (!strcmp(relasec->name, ".rela__bug_table")) {
2913+
new_offset = rela->offset - (src_offset - dest_offset);
2914+
/*
2915+
* When a bug table rela entry is
2916+
* reassigned to a new offset
2917+
* (rela->offset adjustment below),
2918+
* update the addends of all
2919+
* relocations targeting __bug_table so
2920+
* they continue to reference the
2921+
* updated bug entry.
2922+
*/
2923+
recalculate_bug_table_rela_addend(kelf, rela->offset,
2924+
new_offset);
2925+
}
2926+
28552927
rela->offset -= src_offset - dest_offset;
28562928
rela->rela.r_offset = rela->offset;
28572929

0 commit comments

Comments
 (0)