]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
livepatch: Fix having __klp_objects relics in non-livepatch modules
authorPetr Pavlu <petr.pavlu@suse.com>
Fri, 23 Jan 2026 10:26:56 +0000 (11:26 +0100)
committerJosh Poimboeuf <jpoimboe@kernel.org>
Thu, 5 Feb 2026 16:00:44 +0000 (08:00 -0800)
The linker script scripts/module.lds.S specifies that all input
__klp_objects sections should be consolidated into an output section of
the same name, and start/stop symbols should be created to enable
scripts/livepatch/init.c to locate this data.

This start/stop pattern is not ideal for modules because the symbols are
created even if no __klp_objects input sections are present.
Consequently, a dummy __klp_objects section also appears in the
resulting module. This unnecessarily pollutes non-livepatch modules.

Instead, since modules are relocatable files, the usual method for
locating consolidated data in a module is to read its section table.
This approach avoids the aforementioned problem.

The klp_modinfo already stores a copy of the entire section table with
the final addresses. Introduce a helper function that
scripts/livepatch/init.c can call to obtain the location of the
__klp_objects section from this data.

Fixes: dd590d4d57eb ("objtool/klp: Introduce klp diff subcommand for diffing object files")
Signed-off-by: Petr Pavlu <petr.pavlu@suse.com>
Acked-by: Joe Lawrence <joe.lawrence@redhat.com>
Acked-by: Miroslav Benes <mbenes@suse.cz>
Reviewed-by: Aaron Tomlin <atomlin@atomlin.com>
Link: https://patch.msgid.link/20260123102825.3521961-2-petr.pavlu@suse.com
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
include/linux/livepatch.h
kernel/livepatch/core.c
scripts/livepatch/init.c
scripts/module.lds.S

index 772919e8096aaf84221ead2a4df3295ffeaaa159..ba9e3988c07c315c31ae68a685c7fca73f05e26c 100644 (file)
@@ -175,6 +175,9 @@ int klp_enable_patch(struct klp_patch *);
 int klp_module_coming(struct module *mod);
 void klp_module_going(struct module *mod);
 
+void *klp_find_section_by_name(const struct module *mod, const char *name,
+                              size_t *sec_size);
+
 void klp_copy_process(struct task_struct *child);
 void klp_update_patch_state(struct task_struct *task);
 
index 9917756dae46c87a4f1826d2e292a2b231611dd0..1acbad2dbfdf54642f6d3a5cdb220cdf0683e7ca 100644 (file)
@@ -1356,6 +1356,25 @@ void klp_module_going(struct module *mod)
        mutex_unlock(&klp_mutex);
 }
 
+void *klp_find_section_by_name(const struct module *mod, const char *name,
+                              size_t *sec_size)
+{
+       struct klp_modinfo *info = mod->klp_info;
+
+       for (int i = 1; i < info->hdr.e_shnum; i++) {
+               Elf_Shdr *shdr = &info->sechdrs[i];
+
+               if (!strcmp(info->secstrings + shdr->sh_name, name)) {
+                       *sec_size = shdr->sh_size;
+                       return (void *)shdr->sh_addr;
+               }
+       }
+
+       *sec_size = 0;
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(klp_find_section_by_name);
+
 static int __init klp_init(void)
 {
        klp_root_kobj = kobject_create_and_add("livepatch", kernel_kobj);
index 2274d8f5a4826cf16840eb145eb7432039760133..9e315fc857bd82f04b3cc6d1529f9e897e211168 100644 (file)
@@ -9,19 +9,19 @@
 #include <linux/slab.h>
 #include <linux/livepatch.h>
 
-extern struct klp_object_ext __start_klp_objects[];
-extern struct klp_object_ext __stop_klp_objects[];
-
 static struct klp_patch *patch;
 
 static int __init livepatch_mod_init(void)
 {
+       struct klp_object_ext *obj_exts;
+       size_t obj_exts_sec_size;
        struct klp_object *objs;
        unsigned int nr_objs;
        int ret;
 
-       nr_objs = __stop_klp_objects - __start_klp_objects;
-
+       obj_exts = klp_find_section_by_name(THIS_MODULE, "__klp_objects",
+                                           &obj_exts_sec_size);
+       nr_objs = obj_exts_sec_size / sizeof(*obj_exts);
        if (!nr_objs) {
                pr_err("nothing to patch!\n");
                ret = -EINVAL;
@@ -41,7 +41,7 @@ static int __init livepatch_mod_init(void)
        }
 
        for (int i = 0; i < nr_objs; i++) {
-               struct klp_object_ext *obj_ext = __start_klp_objects + i;
+               struct klp_object_ext *obj_ext = obj_exts + i;
                struct klp_func_ext *funcs_ext = obj_ext->funcs;
                unsigned int nr_funcs = obj_ext->nr_funcs;
                struct klp_func *funcs = objs[i].funcs;
@@ -90,12 +90,10 @@ err:
 
 static void __exit livepatch_mod_exit(void)
 {
-       unsigned int nr_objs;
-
-       nr_objs = __stop_klp_objects - __start_klp_objects;
+       struct klp_object *obj;
 
-       for (int i = 0; i < nr_objs; i++)
-               kfree(patch->objs[i].funcs);
+       klp_for_each_object_static(patch, obj)
+               kfree(obj->funcs);
 
        kfree(patch->objs);
        kfree(patch);
index 3037d5e5527c07569d9d88ac0a6441bb1ad113b3..383d19beffb4918501dcbb110ae5e9a47792c173 100644 (file)
@@ -35,12 +35,7 @@ SECTIONS {
        __patchable_function_entries : { *(__patchable_function_entries) }
 
        __klp_funcs             0: ALIGN(8) { KEEP(*(__klp_funcs)) }
-
-       __klp_objects           0: ALIGN(8) {
-               __start_klp_objects = .;
-               KEEP(*(__klp_objects))
-               __stop_klp_objects = .;
-       }
+       __klp_objects           0: ALIGN(8) { KEEP(*(__klp_objects)) }
 
 #ifdef CONFIG_ARCH_USES_CFI_TRAPS
        __kcfi_traps            : { KEEP(*(.kcfi_traps)) }