From ecb07947d5bd82c02309a4b79bc707934721ef88 Mon Sep 17 00:00:00 2001 From: Joe Lawrence Date: Mon, 30 Jun 2025 15:49:04 -0400 Subject: [PATCH 1/3] kpatch-elf: spin out create_section() from create_section_pair() All previous callers needed a corresponding .rela section, but the following patch just needs to create a .modinfo section. Split create_section_pair() into two parts: create the base section seperately, then add the relocation section for those who request it. Signed-off-by: Joe Lawrence --- kpatch-build/kpatch-elf.c | 31 +++++++++++++++++++++---------- kpatch-build/kpatch-elf.h | 2 ++ 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/kpatch-build/kpatch-elf.c b/kpatch-build/kpatch-elf.c index 8c49bcb3..56819c8d 100755 --- a/kpatch-build/kpatch-elf.c +++ b/kpatch-build/kpatch-elf.c @@ -896,19 +896,12 @@ void kpatch_create_symtab(struct kpatch_elf *kelf) symtab->sh.sh_info = nr_local; } -struct section *create_section_pair(struct kpatch_elf *kelf, char *name, - int entsize, int nr) +struct section *create_section(struct kpatch_elf *kelf, char *name, + int entsize, int nr) { - char *relaname; - struct section *sec, *relasec; + struct section *sec; int size = entsize * nr; - relaname = malloc(strlen(name) + strlen(".rela") + 1); - if (!relaname) - ERROR("malloc"); - strcpy(relaname, ".rela"); - strcat(relaname, name); - /* allocate text section resources */ ALLOC_LINK(sec, &kelf->sections); sec->name = name; @@ -931,6 +924,24 @@ struct section *create_section_pair(struct kpatch_elf *kelf, char *name, sec->sh.sh_flags = SHF_ALLOC; sec->sh.sh_size = size; + return sec; + +} + +struct section *create_section_pair(struct kpatch_elf *kelf, char *name, + int entsize, int nr) +{ + char *relaname; + struct section *sec, *relasec; + + relaname = malloc(strlen(name) + strlen(".rela") + 1); + if (!relaname) + ERROR("malloc"); + strcpy(relaname, ".rela"); + strcat(relaname, name); + + sec = create_section(kelf, name, entsize, nr); + /* allocate rela section resources */ ALLOC_LINK(relasec, &kelf->sections); relasec->name = relaname; diff --git a/kpatch-build/kpatch-elf.h b/kpatch-build/kpatch-elf.h index 6f5a52ef..72e2b66b 100644 --- a/kpatch-build/kpatch-elf.h +++ b/kpatch-build/kpatch-elf.h @@ -181,6 +181,8 @@ void print_strtab(char *buf, size_t size); void kpatch_create_shstrtab(struct kpatch_elf *kelf); void kpatch_create_strtab(struct kpatch_elf *kelf); void kpatch_create_symtab(struct kpatch_elf *kelf); +struct section *create_section(struct kpatch_elf *kelf, char *name, + int entsize, int nr); struct section *create_section_pair(struct kpatch_elf *kelf, char *name, int entsize, int nr); void kpatch_remove_and_free_section(struct kpatch_elf *kelf, char *secname); From 5c22637ecbb9376089dd4c066168fc94cc4cf7e5 Mon Sep 17 00:00:00 2001 From: Joe Lawrence Date: Mon, 30 Jun 2025 15:49:04 -0400 Subject: [PATCH 2/3] create-diff-object: extract and retain symbol namespace from .modinfo Kernel module namespace imports are saved in the .modinfo section in key-value strings. In order for a livepatch to access those symbols in those namespaces, it needs to provide the same imports else modpost refuses to process it. For example: ERROR: modpost: module livepatch-test uses symbol dma_buf_export from namespace DMA_BUF, but does not import it. We don't need the entire .modinfo section, as it carries other key-value pairs that we are not interested in. Selectively extract all of the "import_ns= --- kpatch-build/Makefile | 2 +- kpatch-build/create-diff-object.c | 78 +++++++++++++++++++++++++++++++ kpatch-build/kpatch-elf.h | 2 + 3 files changed, 81 insertions(+), 1 deletion(-) diff --git a/kpatch-build/Makefile b/kpatch-build/Makefile index 4e964b7f..afd16f20 100644 --- a/kpatch-build/Makefile +++ b/kpatch-build/Makefile @@ -1,7 +1,7 @@ include ../Makefile.inc CFLAGS += -std=gnu11 -MMD -MP -I../kmod/patch -Iinsn -Wall -Wsign-compare \ - -Wconversion -Wno-sign-conversion -g -Werror + -Wconversion -Wno-sign-conversion -g -Werror -D_GNU_SOURCE LDLIBS = -lelf TARGETS = create-diff-object create-klp-module create-kpatch-module diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c index 3ceade62..350a4591 100644 --- a/kpatch-build/create-diff-object.c +++ b/kpatch-build/create-diff-object.c @@ -1804,6 +1804,74 @@ static void kpatch_include_symbol(struct symbol *sym) kpatch_include_section(sym->sec); } +/* + * Module namespaces are saved as key value pairs in the .modinfo + * section. For modules, they are in the form "import_ns=.import_ns=". Extract just these + * namespace strings from the patched .modinfo to put back into the + * output ELF. + */ +static void kpatch_get_modinfo_namespaces(struct kpatch_elf *kelf_patched, + struct section *sec) +{ + char *data = NULL; + int data_len = 0; + const char *p, *end; + + if (!sec->data || !sec->data->d_buf) + return; + + /* + * Copy all the "import_ns=" strings into + * a temporary data array (ignore other key-values) + */ + p = sec->data->d_buf; + end = p + sec->sh.sh_size; + + while (p < end) { + const char *match; + char *new_data; + size_t match_len; + + match = memmem(p, end - p, "import_ns=", 10); + if (!match) + break; + match_len = strlen(match) + 1; + + new_data = realloc(data, data_len + match_len); + if (!new_data) + ERROR("realloc"); + data = new_data; + + memcpy(data + data_len, match, match_len); + data_len += (int) match_len; + + p = match + match_len; + } + + /* + * Update the patched elf modinfo data array with namespace + * strings for kpatch_put_modinfo_namespaces() + */ + kelf_patched->modinfo_data = data; + kelf_patched->modinfo_data_len = data_len; +} + +static void kpatch_put_modinfo_namespaces(struct kpatch_elf *kelf_patched, + struct kpatch_elf *kelf_out) +{ + struct section *sec; + + if (!kelf_patched->modinfo_data) + return; + + sec = create_section(kelf_out, ".modinfo", + kelf_patched->modinfo_data_len, 1); + memcpy(sec->data->d_buf, kelf_patched->modinfo_data, + kelf_patched->modinfo_data_len); + sec->include = 1; +} + static void kpatch_include_standard_elements(struct kpatch_elf *kelf) { struct section *sec; @@ -2870,6 +2938,15 @@ static void kpatch_mark_ignored_sections(struct kpatch_elf *kelf) !strncmp(sec->name, ".llvm.", 6)) sec->ignore = 1; + /* + * Ignore .modinfo changes, but do stash any module + * namespaces for kpatch_put_modinfo_namespaces() + */ + if (!strcmp(sec->name, ".modinfo")) { + kpatch_get_modinfo_namespaces(kelf, sec); + sec->ignore = 1; + } + if (kelf->arch == X86_64) { if (!strcmp(sec->name, ".rela__patchable_function_entries") || !strcmp(sec->name, "__patchable_function_entries")) @@ -4250,6 +4327,7 @@ int main(int argc, char *argv[]) /* this is destructive to kelf_patched */ kpatch_migrate_included_elements(kelf_patched, &kelf_out); + kpatch_put_modinfo_namespaces(kelf_patched, kelf_out); /* * Teardown kelf_patched since we shouldn't access sections or symbols diff --git a/kpatch-build/kpatch-elf.h b/kpatch-build/kpatch-elf.h index 72e2b66b..b574b019 100644 --- a/kpatch-build/kpatch-elf.h +++ b/kpatch-build/kpatch-elf.h @@ -128,6 +128,8 @@ struct kpatch_elf { int fd; bool has_pfe; bool pfe_ordered; + int modinfo_data_len; + char *modinfo_data; }; /******************* From c03786fa195f880e39894565d71159450493062d Mon Sep 17 00:00:00 2001 From: Joe Lawrence Date: Tue, 1 Jul 2025 13:28:11 -0400 Subject: [PATCH 3/3] test/unit: update for .modinfo namespaces Signed-off-by: Joe Lawrence --- test/unit/objs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/objs b/test/unit/objs index a51c80a6..956ebf60 160000 --- a/test/unit/objs +++ b/test/unit/objs @@ -1 +1 @@ -Subproject commit a51c80a60fc8ade7e7ec8ad875b2963f3a15a494 +Subproject commit 956ebf60b40cd13e66ea6d230479ea7ea109e6c9