* Re: [PATCH v3 0/2] Improve handling of the __klp_{objects,funcs} sections in modules
From: Josh Poimboeuf @ 2026-01-23 17:50 UTC (permalink / raw)
To: Petr Pavlu
Cc: Jiri Kosina, Miroslav Benes, Petr Mladek, Joe Lawrence,
Luis Chamberlain, Daniel Gomez, Sami Tolvanen, Aaron Tomlin,
Peter Zijlstra, live-patching, linux-modules, linux-kernel
In-Reply-To: <20260123102825.3521961-1-petr.pavlu@suse.com>
On Fri, Jan 23, 2026 at 11:26:55AM +0100, Petr Pavlu wrote:
> Changes since v2 [1]:
> - Generalize the helper function that locates __klp_objects in a module
> to allow it to find any data in other sections as well.
>
> Changes since v1 [2]:
> - Generalize the helper function that locates __klp_objects in a module
> to allow it to find objects in other sections as well.
>
> [1] https://lore.kernel.org/linux-modules/20260121082842.3050453-1-petr.pavlu@suse.com/
> [2] https://lore.kernel.org/linux-modules/20260114123056.2045816-1-petr.pavlu@suse.com/
>
> Petr Pavlu (2):
> livepatch: Fix having __klp_objects relics in non-livepatch modules
> livepatch: Free klp_{object,func}_ext data after initialization
Thanks!
Acked-by: Josh Poimboeuf <jpoimboe@kernel.org>
--
Josh
^ permalink raw reply
* [PATCH v3 2/2] livepatch: Free klp_{object,func}_ext data after initialization
From: Petr Pavlu @ 2026-01-23 10:26 UTC (permalink / raw)
To: Josh Poimboeuf, Jiri Kosina, Miroslav Benes, Petr Mladek,
Joe Lawrence
Cc: Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
Aaron Tomlin, Peter Zijlstra, live-patching, linux-modules,
linux-kernel
In-Reply-To: <20260123102825.3521961-1-petr.pavlu@suse.com>
The klp_object_ext and klp_func_ext data, which are stored in the
__klp_objects and __klp_funcs sections, respectively, are not needed
after they are used to create the actual klp_object and klp_func
instances. This operation is implemented by the init function in
scripts/livepatch/init.c.
Prefix the two sections with ".init" so they are freed after the module
is initializated.
Signed-off-by: Petr Pavlu <petr.pavlu@suse.com>
Acked-by: Joe Lawrence <joe.lawrence@redhat.com>
---
scripts/livepatch/init.c | 2 +-
scripts/module.lds.S | 4 ++--
tools/objtool/check.c | 2 +-
tools/objtool/include/objtool/klp.h | 10 +++++-----
tools/objtool/klp-diff.c | 2 +-
5 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/scripts/livepatch/init.c b/scripts/livepatch/init.c
index 9e315fc857bd..638c95cffe76 100644
--- a/scripts/livepatch/init.c
+++ b/scripts/livepatch/init.c
@@ -19,7 +19,7 @@ static int __init livepatch_mod_init(void)
unsigned int nr_objs;
int ret;
- obj_exts = klp_find_section_by_name(THIS_MODULE, "__klp_objects",
+ obj_exts = klp_find_section_by_name(THIS_MODULE, ".init.klp_objects",
&obj_exts_sec_size);
nr_objs = obj_exts_sec_size / sizeof(*obj_exts);
if (!nr_objs) {
diff --git a/scripts/module.lds.S b/scripts/module.lds.S
index 383d19beffb4..054ef99e8288 100644
--- a/scripts/module.lds.S
+++ b/scripts/module.lds.S
@@ -34,8 +34,8 @@ SECTIONS {
__patchable_function_entries : { *(__patchable_function_entries) }
- __klp_funcs 0: ALIGN(8) { KEEP(*(__klp_funcs)) }
- __klp_objects 0: ALIGN(8) { KEEP(*(__klp_objects)) }
+ .init.klp_funcs 0 : ALIGN(8) { KEEP(*(.init.klp_funcs)) }
+ .init.klp_objects 0 : ALIGN(8) { KEEP(*(.init.klp_objects)) }
#ifdef CONFIG_ARCH_USES_CFI_TRAPS
__kcfi_traps : { KEEP(*(.kcfi_traps)) }
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 3f7999317f4d..933868ee3beb 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -4761,7 +4761,7 @@ static int validate_ibt(struct objtool_file *file)
!strcmp(sec->name, "__bug_table") ||
!strcmp(sec->name, "__ex_table") ||
!strcmp(sec->name, "__jump_table") ||
- !strcmp(sec->name, "__klp_funcs") ||
+ !strcmp(sec->name, ".init.klp_funcs") ||
!strcmp(sec->name, "__mcount_loc") ||
!strcmp(sec->name, ".llvm.call-graph-profile") ||
!strcmp(sec->name, ".llvm_bb_addr_map") ||
diff --git a/tools/objtool/include/objtool/klp.h b/tools/objtool/include/objtool/klp.h
index ad830a7ce55b..e32e5e8bc631 100644
--- a/tools/objtool/include/objtool/klp.h
+++ b/tools/objtool/include/objtool/klp.h
@@ -6,12 +6,12 @@
#define SHN_LIVEPATCH 0xff20
/*
- * __klp_objects and __klp_funcs are created by klp diff and used by the patch
- * module init code to build the klp_patch, klp_object and klp_func structs
- * needed by the livepatch API.
+ * .init.klp_objects and .init.klp_funcs are created by klp diff and used by the
+ * patch module init code to build the klp_patch, klp_object and klp_func
+ * structs needed by the livepatch API.
*/
-#define KLP_OBJECTS_SEC "__klp_objects"
-#define KLP_FUNCS_SEC "__klp_funcs"
+#define KLP_OBJECTS_SEC ".init.klp_objects"
+#define KLP_FUNCS_SEC ".init.klp_funcs"
/*
* __klp_relocs is an intermediate section which are created by klp diff and
diff --git a/tools/objtool/klp-diff.c b/tools/objtool/klp-diff.c
index 4d1f9e9977eb..fd64d5e3c3b6 100644
--- a/tools/objtool/klp-diff.c
+++ b/tools/objtool/klp-diff.c
@@ -1439,7 +1439,7 @@ static int clone_special_sections(struct elfs *e)
}
/*
- * Create __klp_objects and __klp_funcs sections which are intermediate
+ * Create .init.klp_objects and .init.klp_funcs sections which are intermediate
* sections provided as input to the patch module's init code for building the
* klp_patch, klp_object and klp_func structs for the livepatch API.
*/
--
2.52.0
^ permalink raw reply related
* [PATCH v3 1/2] livepatch: Fix having __klp_objects relics in non-livepatch modules
From: Petr Pavlu @ 2026-01-23 10:26 UTC (permalink / raw)
To: Josh Poimboeuf, Jiri Kosina, Miroslav Benes, Petr Mladek,
Joe Lawrence
Cc: Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
Aaron Tomlin, Peter Zijlstra, live-patching, linux-modules,
linux-kernel
In-Reply-To: <20260123102825.3521961-1-petr.pavlu@suse.com>
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.
Signed-off-by: Petr Pavlu <petr.pavlu@suse.com>
Acked-by: Joe Lawrence <joe.lawrence@redhat.com>
---
include/linux/livepatch.h | 3 +++
kernel/livepatch/core.c | 19 +++++++++++++++++++
scripts/livepatch/init.c | 20 +++++++++-----------
scripts/module.lds.S | 7 +------
4 files changed, 32 insertions(+), 17 deletions(-)
diff --git a/include/linux/livepatch.h b/include/linux/livepatch.h
index 772919e8096a..ba9e3988c07c 100644
--- a/include/linux/livepatch.h
+++ b/include/linux/livepatch.h
@@ -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);
diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c
index 9917756dae46..1acbad2dbfdf 100644
--- a/kernel/livepatch/core.c
+++ b/kernel/livepatch/core.c
@@ -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);
diff --git a/scripts/livepatch/init.c b/scripts/livepatch/init.c
index 2274d8f5a482..9e315fc857bd 100644
--- a/scripts/livepatch/init.c
+++ b/scripts/livepatch/init.c
@@ -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 @@ static int __init livepatch_mod_init(void)
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);
diff --git a/scripts/module.lds.S b/scripts/module.lds.S
index 3037d5e5527c..383d19beffb4 100644
--- a/scripts/module.lds.S
+++ b/scripts/module.lds.S
@@ -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)) }
--
2.52.0
^ permalink raw reply related
* [PATCH v3 0/2] Improve handling of the __klp_{objects,funcs} sections in modules
From: Petr Pavlu @ 2026-01-23 10:26 UTC (permalink / raw)
To: Josh Poimboeuf, Jiri Kosina, Miroslav Benes, Petr Mladek,
Joe Lawrence
Cc: Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
Aaron Tomlin, Peter Zijlstra, live-patching, linux-modules,
linux-kernel
Changes since v2 [1]:
- Generalize the helper function that locates __klp_objects in a module
to allow it to find any data in other sections as well.
Changes since v1 [2]:
- Generalize the helper function that locates __klp_objects in a module
to allow it to find objects in other sections as well.
[1] https://lore.kernel.org/linux-modules/20260121082842.3050453-1-petr.pavlu@suse.com/
[2] https://lore.kernel.org/linux-modules/20260114123056.2045816-1-petr.pavlu@suse.com/
Petr Pavlu (2):
livepatch: Fix having __klp_objects relics in non-livepatch modules
livepatch: Free klp_{object,func}_ext data after initialization
include/linux/livepatch.h | 3 +++
kernel/livepatch/core.c | 19 +++++++++++++++++++
scripts/livepatch/init.c | 20 +++++++++-----------
scripts/module.lds.S | 9 ++-------
tools/objtool/check.c | 2 +-
tools/objtool/include/objtool/klp.h | 10 +++++-----
tools/objtool/klp-diff.c | 2 +-
7 files changed, 40 insertions(+), 25 deletions(-)
base-commit: 0f61b1860cc3f52aef9036d7235ed1f017632193
--
2.52.0
^ permalink raw reply
* Re: [PATCH v2 1/2] livepatch: Fix having __klp_objects relics in non-livepatch modules
From: Petr Pavlu @ 2026-01-22 8:34 UTC (permalink / raw)
To: Josh Poimboeuf
Cc: Jiri Kosina, Miroslav Benes, Petr Mladek, Joe Lawrence,
Luis Chamberlain, Daniel Gomez, Sami Tolvanen, Aaron Tomlin,
Peter Zijlstra, live-patching, linux-modules, linux-kernel
In-Reply-To: <okmrns5zlxqkwrou5rspq3zyakuv4gwwe4do7yovjbeaa5eajh@fud5amphpycu>
On 1/21/26 10:04 PM, Josh Poimboeuf wrote:
> On Wed, Jan 21, 2026 at 09:28:16AM +0100, Petr Pavlu wrote:
>> +void *klp_locate_section_objs(const struct module *mod, const char *name,
>> + size_t object_size, unsigned int *nr_objs)
>> +{
>> + 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))
>> + continue;
>> +
>> + *nr_objs = shdr->sh_size / object_size;
>> + return (void *)shdr->sh_addr;
>> + }
>> +
>> + *nr_objs = 0;
>> + return NULL;
>> +}
>> +EXPORT_SYMBOL_GPL(klp_locate_section_objs);
>
> How about we make it even more generic with something like
>
> void *klp_find_section_by_name(const struct module *mod, const char *name,
> size_t *sec_size);
>
> ?
>
> I think that would help the code read more clearly.
Ok, I'll update it.
--
Thanks,
Petr
^ permalink raw reply
* Re: [PATCH v2 1/2] livepatch: Fix having __klp_objects relics in non-livepatch modules
From: Josh Poimboeuf @ 2026-01-21 21:04 UTC (permalink / raw)
To: Petr Pavlu
Cc: Jiri Kosina, Miroslav Benes, Petr Mladek, Joe Lawrence,
Luis Chamberlain, Daniel Gomez, Sami Tolvanen, Aaron Tomlin,
Peter Zijlstra, live-patching, linux-modules, linux-kernel
In-Reply-To: <20260121082842.3050453-2-petr.pavlu@suse.com>
On Wed, Jan 21, 2026 at 09:28:16AM +0100, Petr Pavlu wrote:
> +void *klp_locate_section_objs(const struct module *mod, const char *name,
> + size_t object_size, unsigned int *nr_objs)
> +{
> + 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))
> + continue;
> +
> + *nr_objs = shdr->sh_size / object_size;
> + return (void *)shdr->sh_addr;
> + }
> +
> + *nr_objs = 0;
> + return NULL;
> +}
> +EXPORT_SYMBOL_GPL(klp_locate_section_objs);
How about we make it even more generic with something like
void *klp_find_section_by_name(const struct module *mod, const char *name,
size_t *sec_size);
?
I think that would help the code read more clearly.
--
Josh
^ permalink raw reply
* [PATCH v2 2/2] livepatch: Free klp_{object,func}_ext data after initialization
From: Petr Pavlu @ 2026-01-21 8:28 UTC (permalink / raw)
To: Josh Poimboeuf, Jiri Kosina, Miroslav Benes, Petr Mladek,
Joe Lawrence
Cc: Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
Aaron Tomlin, Peter Zijlstra, live-patching, linux-modules,
linux-kernel
In-Reply-To: <20260121082842.3050453-1-petr.pavlu@suse.com>
The klp_object_ext and klp_func_ext data, which are stored in the
__klp_objects and __klp_funcs sections, respectively, are not needed
after they are used to create the actual klp_object and klp_func
instances. This operation is implemented by the init function in
scripts/livepatch/init.c.
Prefix the two sections with ".init" so they are freed after the module
is initializated.
Signed-off-by: Petr Pavlu <petr.pavlu@suse.com>
Acked-by: Joe Lawrence <joe.lawrence@redhat.com>
---
scripts/livepatch/init.c | 2 +-
scripts/module.lds.S | 4 ++--
tools/objtool/check.c | 2 +-
tools/objtool/include/objtool/klp.h | 10 +++++-----
tools/objtool/klp-diff.c | 2 +-
5 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/scripts/livepatch/init.c b/scripts/livepatch/init.c
index a02252e1de03..3e658db5dfe8 100644
--- a/scripts/livepatch/init.c
+++ b/scripts/livepatch/init.c
@@ -18,7 +18,7 @@ static int __init livepatch_mod_init(void)
unsigned int nr_objs;
int ret;
- obj_exts = klp_locate_section_objs(THIS_MODULE, "__klp_objects",
+ obj_exts = klp_locate_section_objs(THIS_MODULE, ".init.klp_objects",
sizeof(*obj_exts), &nr_objs);
if (!nr_objs) {
pr_err("nothing to patch!\n");
diff --git a/scripts/module.lds.S b/scripts/module.lds.S
index 383d19beffb4..054ef99e8288 100644
--- a/scripts/module.lds.S
+++ b/scripts/module.lds.S
@@ -34,8 +34,8 @@ SECTIONS {
__patchable_function_entries : { *(__patchable_function_entries) }
- __klp_funcs 0: ALIGN(8) { KEEP(*(__klp_funcs)) }
- __klp_objects 0: ALIGN(8) { KEEP(*(__klp_objects)) }
+ .init.klp_funcs 0 : ALIGN(8) { KEEP(*(.init.klp_funcs)) }
+ .init.klp_objects 0 : ALIGN(8) { KEEP(*(.init.klp_objects)) }
#ifdef CONFIG_ARCH_USES_CFI_TRAPS
__kcfi_traps : { KEEP(*(.kcfi_traps)) }
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 3f7999317f4d..933868ee3beb 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -4761,7 +4761,7 @@ static int validate_ibt(struct objtool_file *file)
!strcmp(sec->name, "__bug_table") ||
!strcmp(sec->name, "__ex_table") ||
!strcmp(sec->name, "__jump_table") ||
- !strcmp(sec->name, "__klp_funcs") ||
+ !strcmp(sec->name, ".init.klp_funcs") ||
!strcmp(sec->name, "__mcount_loc") ||
!strcmp(sec->name, ".llvm.call-graph-profile") ||
!strcmp(sec->name, ".llvm_bb_addr_map") ||
diff --git a/tools/objtool/include/objtool/klp.h b/tools/objtool/include/objtool/klp.h
index ad830a7ce55b..e32e5e8bc631 100644
--- a/tools/objtool/include/objtool/klp.h
+++ b/tools/objtool/include/objtool/klp.h
@@ -6,12 +6,12 @@
#define SHN_LIVEPATCH 0xff20
/*
- * __klp_objects and __klp_funcs are created by klp diff and used by the patch
- * module init code to build the klp_patch, klp_object and klp_func structs
- * needed by the livepatch API.
+ * .init.klp_objects and .init.klp_funcs are created by klp diff and used by the
+ * patch module init code to build the klp_patch, klp_object and klp_func
+ * structs needed by the livepatch API.
*/
-#define KLP_OBJECTS_SEC "__klp_objects"
-#define KLP_FUNCS_SEC "__klp_funcs"
+#define KLP_OBJECTS_SEC ".init.klp_objects"
+#define KLP_FUNCS_SEC ".init.klp_funcs"
/*
* __klp_relocs is an intermediate section which are created by klp diff and
diff --git a/tools/objtool/klp-diff.c b/tools/objtool/klp-diff.c
index 4d1f9e9977eb..fd64d5e3c3b6 100644
--- a/tools/objtool/klp-diff.c
+++ b/tools/objtool/klp-diff.c
@@ -1439,7 +1439,7 @@ static int clone_special_sections(struct elfs *e)
}
/*
- * Create __klp_objects and __klp_funcs sections which are intermediate
+ * Create .init.klp_objects and .init.klp_funcs sections which are intermediate
* sections provided as input to the patch module's init code for building the
* klp_patch, klp_object and klp_func structs for the livepatch API.
*/
--
2.52.0
^ permalink raw reply related
* [PATCH v2 1/2] livepatch: Fix having __klp_objects relics in non-livepatch modules
From: Petr Pavlu @ 2026-01-21 8:28 UTC (permalink / raw)
To: Josh Poimboeuf, Jiri Kosina, Miroslav Benes, Petr Mladek,
Joe Lawrence
Cc: Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
Aaron Tomlin, Peter Zijlstra, live-patching, linux-modules,
linux-kernel
In-Reply-To: <20260121082842.3050453-1-petr.pavlu@suse.com>
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.
Signed-off-by: Petr Pavlu <petr.pavlu@suse.com>
Acked-by: Joe Lawrence <joe.lawrence@redhat.com>
---
include/linux/livepatch.h | 3 +++
kernel/livepatch/core.c | 20 ++++++++++++++++++++
scripts/livepatch/init.c | 18 +++++++-----------
scripts/module.lds.S | 7 +------
4 files changed, 31 insertions(+), 17 deletions(-)
diff --git a/include/linux/livepatch.h b/include/linux/livepatch.h
index 772919e8096a..0a663e5911f4 100644
--- a/include/linux/livepatch.h
+++ b/include/linux/livepatch.h
@@ -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_locate_section_objs(const struct module *mod, const char *name,
+ size_t object_size, unsigned int *nr_objs);
+
void klp_copy_process(struct task_struct *child);
void klp_update_patch_state(struct task_struct *task);
diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c
index 9917756dae46..85925abfca0f 100644
--- a/kernel/livepatch/core.c
+++ b/kernel/livepatch/core.c
@@ -1356,6 +1356,26 @@ void klp_module_going(struct module *mod)
mutex_unlock(&klp_mutex);
}
+void *klp_locate_section_objs(const struct module *mod, const char *name,
+ size_t object_size, unsigned int *nr_objs)
+{
+ 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))
+ continue;
+
+ *nr_objs = shdr->sh_size / object_size;
+ return (void *)shdr->sh_addr;
+ }
+
+ *nr_objs = 0;
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(klp_locate_section_objs);
+
static int __init klp_init(void)
{
klp_root_kobj = kobject_create_and_add("livepatch", kernel_kobj);
diff --git a/scripts/livepatch/init.c b/scripts/livepatch/init.c
index 2274d8f5a482..a02252e1de03 100644
--- a/scripts/livepatch/init.c
+++ b/scripts/livepatch/init.c
@@ -9,19 +9,17 @@
#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;
struct klp_object *objs;
unsigned int nr_objs;
int ret;
- nr_objs = __stop_klp_objects - __start_klp_objects;
-
+ obj_exts = klp_locate_section_objs(THIS_MODULE, "__klp_objects",
+ sizeof(*obj_exts), &nr_objs);
if (!nr_objs) {
pr_err("nothing to patch!\n");
ret = -EINVAL;
@@ -41,7 +39,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 +88,10 @@ static int __init livepatch_mod_init(void)
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);
diff --git a/scripts/module.lds.S b/scripts/module.lds.S
index 3037d5e5527c..383d19beffb4 100644
--- a/scripts/module.lds.S
+++ b/scripts/module.lds.S
@@ -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)) }
--
2.52.0
^ permalink raw reply related
* [PATCH v2 0/2] Improve handling of the __klp_{objects,funcs} sections in modules
From: Petr Pavlu @ 2026-01-21 8:28 UTC (permalink / raw)
To: Josh Poimboeuf, Jiri Kosina, Miroslav Benes, Petr Mladek,
Joe Lawrence
Cc: Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
Aaron Tomlin, Peter Zijlstra, live-patching, linux-modules,
linux-kernel
Changes since v1 [1]:
- Generalize the helper function that locates __klp_objects in a module
to allow it to find objects in other sections as well.
[1] https://lore.kernel.org/linux-modules/20260114123056.2045816-1-petr.pavlu@suse.com/
Petr Pavlu (2):
livepatch: Fix having __klp_objects relics in non-livepatch modules
livepatch: Free klp_{object,func}_ext data after initialization
include/linux/livepatch.h | 3 +++
kernel/livepatch/core.c | 20 ++++++++++++++++++++
scripts/livepatch/init.c | 18 +++++++-----------
scripts/module.lds.S | 9 ++-------
tools/objtool/check.c | 2 +-
tools/objtool/include/objtool/klp.h | 10 +++++-----
tools/objtool/klp-diff.c | 2 +-
7 files changed, 39 insertions(+), 25 deletions(-)
base-commit: 0f61b1860cc3f52aef9036d7235ed1f017632193
--
2.52.0
^ permalink raw reply
* Re: [PATCH 1/2] livepatch: Fix having __klp_objects relics in non-livepatch modules
From: Petr Pavlu @ 2026-01-20 17:48 UTC (permalink / raw)
To: Joe Lawrence
Cc: Josh Poimboeuf, Jiri Kosina, Miroslav Benes, Petr Mladek,
Luis Chamberlain, Daniel Gomez, Sami Tolvanen, Aaron Tomlin,
Peter Zijlstra, live-patching, linux-modules, linux-kernel
In-Reply-To: <aW6uCQNXj0Y7IGnz@redhat.com>
On 1/19/26 11:19 PM, Joe Lawrence wrote:
> On Wed, Jan 14, 2026 at 01:29:53PM +0100, Petr Pavlu wrote:
>> 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.
>>
>> Signed-off-by: Petr Pavlu <petr.pavlu@suse.com>
>> ---
>> include/linux/livepatch.h | 3 +++
>> kernel/livepatch/core.c | 20 ++++++++++++++++++++
>> scripts/livepatch/init.c | 17 ++++++-----------
>> scripts/module.lds.S | 7 +------
>> 4 files changed, 30 insertions(+), 17 deletions(-)
>>
>> diff --git a/include/linux/livepatch.h b/include/linux/livepatch.h
>> index 772919e8096a..ca90adbe89ed 100644
>> --- a/include/linux/livepatch.h
>> +++ b/include/linux/livepatch.h
>> @@ -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);
>>
>> +struct klp_object_ext *klp_build_locate_init_objects(const struct module *mod,
>> + unsigned int *nr_objs);
>> +
>> void klp_copy_process(struct task_struct *child);
>> void klp_update_patch_state(struct task_struct *task);
>>
>> diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c
>> index 9917756dae46..4e0ac47b3623 100644
>> --- a/kernel/livepatch/core.c
>> +++ b/kernel/livepatch/core.c
>> @@ -1356,6 +1356,26 @@ void klp_module_going(struct module *mod)
>> mutex_unlock(&klp_mutex);
>> }
>>
>> +struct klp_object_ext *klp_build_locate_init_objects(const struct module *mod,
>> + unsigned int *nr_objs)
>> +{
>> + 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, "__klp_objects"))
>> + continue;
>> +
>
> Since this function is doing a string comparision to find the ELF
> section, would it make sense to open up the API by allowing to caller to
> specify the sh_name? That would give scripts/livepatch/init.c future
> flexibility in finding similarly crafted data structures. Disregard if
> there is already a pattern of doing it this way :)
Makes sense. I'll change the function signature to:
void *klp_locate_section_objs(const struct module *mod, const char *name, size_t object_size, unsigned int *nr_objs);
--
Thanks,
Petr
^ permalink raw reply
* Re: [PATCH 2/2] livepatch: Free klp_{object,func}_ext data after initialization
From: Joe Lawrence @ 2026-01-19 22:22 UTC (permalink / raw)
To: Petr Pavlu
Cc: Josh Poimboeuf, Jiri Kosina, Miroslav Benes, Petr Mladek,
Luis Chamberlain, Daniel Gomez, Sami Tolvanen, Aaron Tomlin,
Peter Zijlstra, live-patching, linux-modules, linux-kernel
In-Reply-To: <20260114123056.2045816-3-petr.pavlu@suse.com>
On Wed, Jan 14, 2026 at 01:29:54PM +0100, Petr Pavlu wrote:
> The klp_object_ext and klp_func_ext data, which are stored in the
> __klp_objects and __klp_funcs sections, respectively, are not needed
> after they are used to create the actual klp_object and klp_func
> instances. This operation is implemented by the init function in
> scripts/livepatch/init.c.
>
> Prefix the two sections with ".init" so they are freed after the module
> is initializated.
>
> Signed-off-by: Petr Pavlu <petr.pavlu@suse.com>
> ---
> kernel/livepatch/core.c | 3 ++-
> scripts/module.lds.S | 4 ++--
> tools/objtool/check.c | 2 +-
> tools/objtool/include/objtool/klp.h | 10 +++++-----
> tools/objtool/klp-diff.c | 2 +-
> 5 files changed, 11 insertions(+), 10 deletions(-)
>
> diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c
> index 4e0ac47b3623..3621a7c1b737 100644
> --- a/kernel/livepatch/core.c
> +++ b/kernel/livepatch/core.c
> @@ -1364,7 +1364,8 @@ struct klp_object_ext *klp_build_locate_init_objects(const struct module *mod,
> for (int i = 1; i < info->hdr.e_shnum; i++) {
> Elf_Shdr *shdr = &info->sechdrs[i];
>
> - if (strcmp(info->secstrings + shdr->sh_name, "__klp_objects"))
> + if (strcmp(info->secstrings + shdr->sh_name,
> + ".init.klp_objects"))
> continue;
>
> *nr_objs = shdr->sh_size / sizeof(struct klp_object_ext);
> diff --git a/scripts/module.lds.S b/scripts/module.lds.S
> index 383d19beffb4..054ef99e8288 100644
> --- a/scripts/module.lds.S
> +++ b/scripts/module.lds.S
> @@ -34,8 +34,8 @@ SECTIONS {
>
> __patchable_function_entries : { *(__patchable_function_entries) }
>
> - __klp_funcs 0: ALIGN(8) { KEEP(*(__klp_funcs)) }
> - __klp_objects 0: ALIGN(8) { KEEP(*(__klp_objects)) }
> + .init.klp_funcs 0 : ALIGN(8) { KEEP(*(.init.klp_funcs)) }
> + .init.klp_objects 0 : ALIGN(8) { KEEP(*(.init.klp_objects)) }
>
> #ifdef CONFIG_ARCH_USES_CFI_TRAPS
> __kcfi_traps : { KEEP(*(.kcfi_traps)) }
> diff --git a/tools/objtool/check.c b/tools/objtool/check.c
> index 3f7999317f4d..933868ee3beb 100644
> --- a/tools/objtool/check.c
> +++ b/tools/objtool/check.c
> @@ -4761,7 +4761,7 @@ static int validate_ibt(struct objtool_file *file)
> !strcmp(sec->name, "__bug_table") ||
> !strcmp(sec->name, "__ex_table") ||
> !strcmp(sec->name, "__jump_table") ||
> - !strcmp(sec->name, "__klp_funcs") ||
> + !strcmp(sec->name, ".init.klp_funcs") ||
> !strcmp(sec->name, "__mcount_loc") ||
> !strcmp(sec->name, ".llvm.call-graph-profile") ||
> !strcmp(sec->name, ".llvm_bb_addr_map") ||
> diff --git a/tools/objtool/include/objtool/klp.h b/tools/objtool/include/objtool/klp.h
> index ad830a7ce55b..e32e5e8bc631 100644
> --- a/tools/objtool/include/objtool/klp.h
> +++ b/tools/objtool/include/objtool/klp.h
> @@ -6,12 +6,12 @@
> #define SHN_LIVEPATCH 0xff20
>
> /*
> - * __klp_objects and __klp_funcs are created by klp diff and used by the patch
> - * module init code to build the klp_patch, klp_object and klp_func structs
> - * needed by the livepatch API.
> + * .init.klp_objects and .init.klp_funcs are created by klp diff and used by the
> + * patch module init code to build the klp_patch, klp_object and klp_func
> + * structs needed by the livepatch API.
> */
> -#define KLP_OBJECTS_SEC "__klp_objects"
> -#define KLP_FUNCS_SEC "__klp_funcs"
> +#define KLP_OBJECTS_SEC ".init.klp_objects"
> +#define KLP_FUNCS_SEC ".init.klp_funcs"
>
> /*
> * __klp_relocs is an intermediate section which are created by klp diff and
> diff --git a/tools/objtool/klp-diff.c b/tools/objtool/klp-diff.c
> index 4d1f9e9977eb..fd64d5e3c3b6 100644
> --- a/tools/objtool/klp-diff.c
> +++ b/tools/objtool/klp-diff.c
> @@ -1439,7 +1439,7 @@ static int clone_special_sections(struct elfs *e)
> }
>
> /*
> - * Create __klp_objects and __klp_funcs sections which are intermediate
> + * Create .init.klp_objects and .init.klp_funcs sections which are intermediate
> * sections provided as input to the patch module's init code for building the
> * klp_patch, klp_object and klp_func structs for the livepatch API.
> */
> --
> 2.52.0
>
Acked-by: Joe Lawrence <joe.lawrence@redhat.com>
--
Joe
^ permalink raw reply
* Re: [PATCH 1/2] livepatch: Fix having __klp_objects relics in non-livepatch modules
From: Joe Lawrence @ 2026-01-19 22:19 UTC (permalink / raw)
To: Petr Pavlu
Cc: Josh Poimboeuf, Jiri Kosina, Miroslav Benes, Petr Mladek,
Luis Chamberlain, Daniel Gomez, Sami Tolvanen, Aaron Tomlin,
Peter Zijlstra, live-patching, linux-modules, linux-kernel
In-Reply-To: <20260114123056.2045816-2-petr.pavlu@suse.com>
On Wed, Jan 14, 2026 at 01:29:53PM +0100, Petr Pavlu wrote:
> 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.
>
> Signed-off-by: Petr Pavlu <petr.pavlu@suse.com>
> ---
> include/linux/livepatch.h | 3 +++
> kernel/livepatch/core.c | 20 ++++++++++++++++++++
> scripts/livepatch/init.c | 17 ++++++-----------
> scripts/module.lds.S | 7 +------
> 4 files changed, 30 insertions(+), 17 deletions(-)
>
> diff --git a/include/linux/livepatch.h b/include/linux/livepatch.h
> index 772919e8096a..ca90adbe89ed 100644
> --- a/include/linux/livepatch.h
> +++ b/include/linux/livepatch.h
> @@ -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);
>
> +struct klp_object_ext *klp_build_locate_init_objects(const struct module *mod,
> + unsigned int *nr_objs);
> +
> void klp_copy_process(struct task_struct *child);
> void klp_update_patch_state(struct task_struct *task);
>
> diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c
> index 9917756dae46..4e0ac47b3623 100644
> --- a/kernel/livepatch/core.c
> +++ b/kernel/livepatch/core.c
> @@ -1356,6 +1356,26 @@ void klp_module_going(struct module *mod)
> mutex_unlock(&klp_mutex);
> }
>
> +struct klp_object_ext *klp_build_locate_init_objects(const struct module *mod,
> + unsigned int *nr_objs)
> +{
> + 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, "__klp_objects"))
> + continue;
> +
Since this function is doing a string comparision to find the ELF
section, would it make sense to open up the API by allowing to caller to
specify the sh_name? That would give scripts/livepatch/init.c future
flexibility in finding similarly crafted data structures. Disregard if
there is already a pattern of doing it this way :)
> + *nr_objs = shdr->sh_size / sizeof(struct klp_object_ext);
> + return (struct klp_object_ext *)shdr->sh_addr;
> + }
> +
> + *nr_objs = 0;
> + return NULL;
> +}
> +EXPORT_SYMBOL_GPL(klp_build_locate_init_objects);
> +
> static int __init klp_init(void)
> {
> klp_root_kobj = kobject_create_and_add("livepatch", kernel_kobj);
> diff --git a/scripts/livepatch/init.c b/scripts/livepatch/init.c
> index 2274d8f5a482..23e037d6de19 100644
> --- a/scripts/livepatch/init.c
> +++ b/scripts/livepatch/init.c
> @@ -9,19 +9,16 @@
> #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;
> struct klp_object *objs;
> unsigned int nr_objs;
> int ret;
>
> - nr_objs = __stop_klp_objects - __start_klp_objects;
> -
> + obj_exts = klp_build_locate_init_objects(THIS_MODULE, &nr_objs);
> if (!nr_objs) {
> pr_err("nothing to patch!\n");
> ret = -EINVAL;
> @@ -41,7 +38,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 +87,10 @@ static int __init livepatch_mod_init(void)
>
> 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);
> diff --git a/scripts/module.lds.S b/scripts/module.lds.S
> index 3037d5e5527c..383d19beffb4 100644
> --- a/scripts/module.lds.S
> +++ b/scripts/module.lds.S
> @@ -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)) }
> --
> 2.52.0
>
Acked-by: Joe Lawrence <joe.lawrence@redhat.com>
--
Joe
^ permalink raw reply
* [PATCH 2/2] livepatch: Free klp_{object,func}_ext data after initialization
From: Petr Pavlu @ 2026-01-14 12:29 UTC (permalink / raw)
To: Josh Poimboeuf, Jiri Kosina, Miroslav Benes, Petr Mladek,
Joe Lawrence
Cc: Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
Aaron Tomlin, Peter Zijlstra, live-patching, linux-modules,
linux-kernel
In-Reply-To: <20260114123056.2045816-1-petr.pavlu@suse.com>
The klp_object_ext and klp_func_ext data, which are stored in the
__klp_objects and __klp_funcs sections, respectively, are not needed
after they are used to create the actual klp_object and klp_func
instances. This operation is implemented by the init function in
scripts/livepatch/init.c.
Prefix the two sections with ".init" so they are freed after the module
is initializated.
Signed-off-by: Petr Pavlu <petr.pavlu@suse.com>
---
kernel/livepatch/core.c | 3 ++-
scripts/module.lds.S | 4 ++--
tools/objtool/check.c | 2 +-
tools/objtool/include/objtool/klp.h | 10 +++++-----
tools/objtool/klp-diff.c | 2 +-
5 files changed, 11 insertions(+), 10 deletions(-)
diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c
index 4e0ac47b3623..3621a7c1b737 100644
--- a/kernel/livepatch/core.c
+++ b/kernel/livepatch/core.c
@@ -1364,7 +1364,8 @@ struct klp_object_ext *klp_build_locate_init_objects(const struct module *mod,
for (int i = 1; i < info->hdr.e_shnum; i++) {
Elf_Shdr *shdr = &info->sechdrs[i];
- if (strcmp(info->secstrings + shdr->sh_name, "__klp_objects"))
+ if (strcmp(info->secstrings + shdr->sh_name,
+ ".init.klp_objects"))
continue;
*nr_objs = shdr->sh_size / sizeof(struct klp_object_ext);
diff --git a/scripts/module.lds.S b/scripts/module.lds.S
index 383d19beffb4..054ef99e8288 100644
--- a/scripts/module.lds.S
+++ b/scripts/module.lds.S
@@ -34,8 +34,8 @@ SECTIONS {
__patchable_function_entries : { *(__patchable_function_entries) }
- __klp_funcs 0: ALIGN(8) { KEEP(*(__klp_funcs)) }
- __klp_objects 0: ALIGN(8) { KEEP(*(__klp_objects)) }
+ .init.klp_funcs 0 : ALIGN(8) { KEEP(*(.init.klp_funcs)) }
+ .init.klp_objects 0 : ALIGN(8) { KEEP(*(.init.klp_objects)) }
#ifdef CONFIG_ARCH_USES_CFI_TRAPS
__kcfi_traps : { KEEP(*(.kcfi_traps)) }
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 3f7999317f4d..933868ee3beb 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -4761,7 +4761,7 @@ static int validate_ibt(struct objtool_file *file)
!strcmp(sec->name, "__bug_table") ||
!strcmp(sec->name, "__ex_table") ||
!strcmp(sec->name, "__jump_table") ||
- !strcmp(sec->name, "__klp_funcs") ||
+ !strcmp(sec->name, ".init.klp_funcs") ||
!strcmp(sec->name, "__mcount_loc") ||
!strcmp(sec->name, ".llvm.call-graph-profile") ||
!strcmp(sec->name, ".llvm_bb_addr_map") ||
diff --git a/tools/objtool/include/objtool/klp.h b/tools/objtool/include/objtool/klp.h
index ad830a7ce55b..e32e5e8bc631 100644
--- a/tools/objtool/include/objtool/klp.h
+++ b/tools/objtool/include/objtool/klp.h
@@ -6,12 +6,12 @@
#define SHN_LIVEPATCH 0xff20
/*
- * __klp_objects and __klp_funcs are created by klp diff and used by the patch
- * module init code to build the klp_patch, klp_object and klp_func structs
- * needed by the livepatch API.
+ * .init.klp_objects and .init.klp_funcs are created by klp diff and used by the
+ * patch module init code to build the klp_patch, klp_object and klp_func
+ * structs needed by the livepatch API.
*/
-#define KLP_OBJECTS_SEC "__klp_objects"
-#define KLP_FUNCS_SEC "__klp_funcs"
+#define KLP_OBJECTS_SEC ".init.klp_objects"
+#define KLP_FUNCS_SEC ".init.klp_funcs"
/*
* __klp_relocs is an intermediate section which are created by klp diff and
diff --git a/tools/objtool/klp-diff.c b/tools/objtool/klp-diff.c
index 4d1f9e9977eb..fd64d5e3c3b6 100644
--- a/tools/objtool/klp-diff.c
+++ b/tools/objtool/klp-diff.c
@@ -1439,7 +1439,7 @@ static int clone_special_sections(struct elfs *e)
}
/*
- * Create __klp_objects and __klp_funcs sections which are intermediate
+ * Create .init.klp_objects and .init.klp_funcs sections which are intermediate
* sections provided as input to the patch module's init code for building the
* klp_patch, klp_object and klp_func structs for the livepatch API.
*/
--
2.52.0
^ permalink raw reply related
* [PATCH 1/2] livepatch: Fix having __klp_objects relics in non-livepatch modules
From: Petr Pavlu @ 2026-01-14 12:29 UTC (permalink / raw)
To: Josh Poimboeuf, Jiri Kosina, Miroslav Benes, Petr Mladek,
Joe Lawrence
Cc: Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
Aaron Tomlin, Peter Zijlstra, live-patching, linux-modules,
linux-kernel
In-Reply-To: <20260114123056.2045816-1-petr.pavlu@suse.com>
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.
Signed-off-by: Petr Pavlu <petr.pavlu@suse.com>
---
include/linux/livepatch.h | 3 +++
kernel/livepatch/core.c | 20 ++++++++++++++++++++
scripts/livepatch/init.c | 17 ++++++-----------
scripts/module.lds.S | 7 +------
4 files changed, 30 insertions(+), 17 deletions(-)
diff --git a/include/linux/livepatch.h b/include/linux/livepatch.h
index 772919e8096a..ca90adbe89ed 100644
--- a/include/linux/livepatch.h
+++ b/include/linux/livepatch.h
@@ -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);
+struct klp_object_ext *klp_build_locate_init_objects(const struct module *mod,
+ unsigned int *nr_objs);
+
void klp_copy_process(struct task_struct *child);
void klp_update_patch_state(struct task_struct *task);
diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c
index 9917756dae46..4e0ac47b3623 100644
--- a/kernel/livepatch/core.c
+++ b/kernel/livepatch/core.c
@@ -1356,6 +1356,26 @@ void klp_module_going(struct module *mod)
mutex_unlock(&klp_mutex);
}
+struct klp_object_ext *klp_build_locate_init_objects(const struct module *mod,
+ unsigned int *nr_objs)
+{
+ 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, "__klp_objects"))
+ continue;
+
+ *nr_objs = shdr->sh_size / sizeof(struct klp_object_ext);
+ return (struct klp_object_ext *)shdr->sh_addr;
+ }
+
+ *nr_objs = 0;
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(klp_build_locate_init_objects);
+
static int __init klp_init(void)
{
klp_root_kobj = kobject_create_and_add("livepatch", kernel_kobj);
diff --git a/scripts/livepatch/init.c b/scripts/livepatch/init.c
index 2274d8f5a482..23e037d6de19 100644
--- a/scripts/livepatch/init.c
+++ b/scripts/livepatch/init.c
@@ -9,19 +9,16 @@
#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;
struct klp_object *objs;
unsigned int nr_objs;
int ret;
- nr_objs = __stop_klp_objects - __start_klp_objects;
-
+ obj_exts = klp_build_locate_init_objects(THIS_MODULE, &nr_objs);
if (!nr_objs) {
pr_err("nothing to patch!\n");
ret = -EINVAL;
@@ -41,7 +38,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 +87,10 @@ static int __init livepatch_mod_init(void)
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);
diff --git a/scripts/module.lds.S b/scripts/module.lds.S
index 3037d5e5527c..383d19beffb4 100644
--- a/scripts/module.lds.S
+++ b/scripts/module.lds.S
@@ -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)) }
--
2.52.0
^ permalink raw reply related
* [PATCH 0/2] Improve handling of the __klp_{objects,funcs} sections in modules
From: Petr Pavlu @ 2026-01-14 12:29 UTC (permalink / raw)
To: Josh Poimboeuf, Jiri Kosina, Miroslav Benes, Petr Mladek,
Joe Lawrence
Cc: Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
Aaron Tomlin, Peter Zijlstra, live-patching, linux-modules,
linux-kernel
Petr Pavlu (2):
livepatch: Fix having __klp_objects relics in non-livepatch modules
livepatch: Free klp_{object,func}_ext data after initialization
include/linux/livepatch.h | 3 +++
kernel/livepatch/core.c | 21 +++++++++++++++++++++
scripts/livepatch/init.c | 17 ++++++-----------
scripts/module.lds.S | 9 ++-------
tools/objtool/check.c | 2 +-
tools/objtool/include/objtool/klp.h | 10 +++++-----
tools/objtool/klp-diff.c | 2 +-
7 files changed, 39 insertions(+), 25 deletions(-)
base-commit: f0b9d8eb98dfee8d00419aa07543bdc2c1a44fb1
--
2.52.0
^ permalink raw reply
* Re: [PATCH] powerpc64/bpf: support direct_call on livepatch function
From: Naveen N Rao @ 2026-01-09 13:48 UTC (permalink / raw)
To: Hari Bathini
Cc: Madhavan Srinivasan, linuxppc-dev, Christophe Leroy,
Michael Ellerman, Nicholas Piggin, bpf, Alexei Starovoitov,
Daniel Borkmann, Andrii Nakryiko, Song Liu, Jiri Olsa,
Viktor Malik, live-patching, Josh Poimboeuf, Joe Lawrence,
Jiri Kosina, linux-trace-kernel, Steven Rostedt, Masami Hiramatsu,
Mark Rutland, Shung-Hsi Yu
In-Reply-To: <e34ddd05-d926-4eb4-b861-4bf8fd5635bb@linux.ibm.com>
On Mon, Dec 08, 2025 at 10:05:44PM +0530, Hari Bathini wrote:
> >
> > One of the other thoughts I had was if we could stuff the function
> > address into the ftrace OOL stub. I had considered this back when I
> > implemented the OOL stubs, but didn't do it due to the extra memory
> > requirement. However, given the dance we're having to do, I'm now
> > thinking that may make sense and can simplify the code. If we can also
> > hook into livepatch, then we should be able to update the function
> > address in the stub to point to the new address and the trampoline
> > should then "just work" since it already saves/restores the TOC [We may
> > additionally have to update the function IP in _R12, but that would be a
> > minor change overall]
> >
> > We will still need a way to restore livepatch TOC if the BPF trampoline
> > doesn't itself call into the function, but we may be able to handle that
> > if we change the return address to jump to a stub that restores the TOC
> > from the livepatch stack.
>
> Sounds doable. Looking into a couple of other things at the moment
> though. Will try out this suggestion and get back post that.
> Having said that, your thoughts on whether the current approach
> is a viable option if bpf_get_func_ip() can be fixed somehow?
Oh, that's fine -- feel free to go with whatever approach you think
works best.
- Naveen
^ permalink raw reply
* Re: [PATCH v4 02/63] vmlinux.lds: Unify TEXT_MAIN, DATA_MAIN, and related macros
From: Carlos Llamas @ 2026-01-08 21:59 UTC (permalink / raw)
To: Will Deacon
Cc: Ard Biesheuvel, Josh Poimboeuf, x86, linux-kernel, Petr Mladek,
Miroslav Benes, Joe Lawrence, live-patching, Song Liu, laokz,
Jiri Kosina, Marcos Paulo de Souza, Weinan Liu, Fazla Mehrab,
Chen Zhongjin, Puranjay Mohan, Dylan Hatch, Peter Zijlstra,
Heiko Carstens, Vasily Gorbik, Alexander Gordeev, Sami Tolvanen,
kernel-team
In-Reply-To: <aV2QyUv3-8SLV6Z8@willie-the-truck>
On Tue, Jan 06, 2026 at 10:46:33PM +0000, Will Deacon wrote:
> On Sat, Dec 20, 2025 at 04:25:50PM +0000, Carlos Llamas wrote:
> > On Wed, Sep 17, 2025 at 09:03:10AM -0700, Josh Poimboeuf wrote:
> > > TEXT_MAIN, DATA_MAIN and friends are defined differently depending on
> > > whether certain config options enable -ffunction-sections and/or
> > > -fdata-sections.
> > >
> > > There's no technical reason for that beyond voodoo coding. Keeping the
> > > separate implementations adds unnecessary complexity, fragments the
> > > logic, and increases the risk of subtle bugs.
> > >
> > > Unify the macros by using the same input section patterns across all
> > > configs.
> > >
> > > This is a prerequisite for the upcoming livepatch klp-build tooling
> > > which will manually enable -ffunction-sections and -fdata-sections via
> > > KCFLAGS.
> > >
> > > Cc: Heiko Carstens <hca@linux.ibm.com>
> > > Cc: Vasily Gorbik <gor@linux.ibm.com>
> > > Cc: Alexander Gordeev <agordeev@linux.ibm.com>
> > > Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
> > > ---
> > > include/asm-generic/vmlinux.lds.h | 40 ++++++++++---------------------
> > > scripts/module.lds.S | 12 ++++------
> > > 2 files changed, 17 insertions(+), 35 deletions(-)
>
> [...]
>
> > I'm seeing some KP when trying to load modules after this change. I
> > believe there is some sort of incompatibility with the SCS (Shadow Call
> > Stack) code in arm64? The panic is always on __pi_scs_handle_fde_frame:
> >
> > init: Loading module [...]/drivers/net/wireless/virtual/mac80211_hwsim.ko
> > Unable to handle kernel paging request at virtual address ffffffe6468f0ffc
> > [...]
>
> nit: please don't trim the useful stuff when reporting a crash!
>
> > pc : __pi_scs_handle_fde_frame+0xd8/0x15c
> > lr : __pi_$x+0x74/0x138
> > sp : ffffffc08005bb10
> > x29: ffffffc08005bb10 x28: ffffffc081873010 x27: 0000000000000000
> > x26: 0000000000000007 x25: 0000000000000000 x24: 0000000000000000
> > x23: 0000000000000001 x22: ffffffe649794fa0 x21: ffffffe6469190b4
> > x20: 000000000000182c x19: 0000000000000001 x18: ffffffc080053000
> > x17: 000000000000002d x16: ffffffe6469190c5 x15: ffffffe6468f1000
> > x14: 000000000000003e x13: ffffffe6469190c6 x12: 00000000d50323bf
> > x11: 00000000d503233f x10: ffffffe649119cb8 x9 : ffffffe6468f1000
> > x8 : 0000000000000100 x7 : 00656d6172665f68 x6 : 0000000000000001
> > x5 : 6372610000000000 x4 : 0000008000000000 x3 : 0000000000000000
> > x2 : ffffffe647e528f4 x1 : 0000000000000001 x0 : 0000000000000004
> > Call trace:
> > __pi_scs_handle_fde_frame+0xd8/0x15c (P)
> > module_finalize+0xfc/0x164
> > post_relocation+0xbc/0xd8
> > load_module+0xfd4/0x11a8
> > __arm64_sys_finit_module+0x23c/0x328
> > invoke_syscall+0x58/0xe4
> > el0_svc_common+0x80/0xdc
> > do_el0_svc+0x1c/0x28
> > el0_svc+0x54/0x1c4
> > el0t_64_sync_handler+0x68/0xdc
> > el0t_64_sync+0x1c4/0x1c8
> > Code: 54fffd4c 1400001f 3707ff63 aa0903ef (b85fcdf0)
>
> Hmm, looks like a translation fault from the load buried here:
>
> u32 insn = le32_to_cpup((void *)loc);
>
> in scs_patch_loc(), called from the 'DW_CFA_negate_ra_state' case in
> scs_handle_fde_frame(). So presumably 'loc' is bogus.
>
> Since you replied to this patch, does reverting it fix the problem for
> you?
Yes, but it is only coincidental. The real issue seems to be with our
toolchain. I'll start looking there instead. Sorry for the noise.
--
Carlos Llamas
^ permalink raw reply
* Re: [PATCH v4 02/63] vmlinux.lds: Unify TEXT_MAIN, DATA_MAIN, and related macros
From: Will Deacon @ 2026-01-06 22:46 UTC (permalink / raw)
To: Carlos Llamas, Ard Biesheuvel
Cc: Josh Poimboeuf, x86, linux-kernel, Petr Mladek, Miroslav Benes,
Joe Lawrence, live-patching, Song Liu, laokz, Jiri Kosina,
Marcos Paulo de Souza, Weinan Liu, Fazla Mehrab, Chen Zhongjin,
Puranjay Mohan, Dylan Hatch, Peter Zijlstra, Heiko Carstens,
Vasily Gorbik, Alexander Gordeev, Sami Tolvanen, kernel-team
In-Reply-To: <aUbODsjSuIBBLyo_@google.com>
On Sat, Dec 20, 2025 at 04:25:50PM +0000, Carlos Llamas wrote:
> On Wed, Sep 17, 2025 at 09:03:10AM -0700, Josh Poimboeuf wrote:
> > TEXT_MAIN, DATA_MAIN and friends are defined differently depending on
> > whether certain config options enable -ffunction-sections and/or
> > -fdata-sections.
> >
> > There's no technical reason for that beyond voodoo coding. Keeping the
> > separate implementations adds unnecessary complexity, fragments the
> > logic, and increases the risk of subtle bugs.
> >
> > Unify the macros by using the same input section patterns across all
> > configs.
> >
> > This is a prerequisite for the upcoming livepatch klp-build tooling
> > which will manually enable -ffunction-sections and -fdata-sections via
> > KCFLAGS.
> >
> > Cc: Heiko Carstens <hca@linux.ibm.com>
> > Cc: Vasily Gorbik <gor@linux.ibm.com>
> > Cc: Alexander Gordeev <agordeev@linux.ibm.com>
> > Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
> > ---
> > include/asm-generic/vmlinux.lds.h | 40 ++++++++++---------------------
> > scripts/module.lds.S | 12 ++++------
> > 2 files changed, 17 insertions(+), 35 deletions(-)
[...]
> I'm seeing some KP when trying to load modules after this change. I
> believe there is some sort of incompatibility with the SCS (Shadow Call
> Stack) code in arm64? The panic is always on __pi_scs_handle_fde_frame:
>
> init: Loading module [...]/drivers/net/wireless/virtual/mac80211_hwsim.ko
> Unable to handle kernel paging request at virtual address ffffffe6468f0ffc
> [...]
nit: please don't trim the useful stuff when reporting a crash!
> pc : __pi_scs_handle_fde_frame+0xd8/0x15c
> lr : __pi_$x+0x74/0x138
> sp : ffffffc08005bb10
> x29: ffffffc08005bb10 x28: ffffffc081873010 x27: 0000000000000000
> x26: 0000000000000007 x25: 0000000000000000 x24: 0000000000000000
> x23: 0000000000000001 x22: ffffffe649794fa0 x21: ffffffe6469190b4
> x20: 000000000000182c x19: 0000000000000001 x18: ffffffc080053000
> x17: 000000000000002d x16: ffffffe6469190c5 x15: ffffffe6468f1000
> x14: 000000000000003e x13: ffffffe6469190c6 x12: 00000000d50323bf
> x11: 00000000d503233f x10: ffffffe649119cb8 x9 : ffffffe6468f1000
> x8 : 0000000000000100 x7 : 00656d6172665f68 x6 : 0000000000000001
> x5 : 6372610000000000 x4 : 0000008000000000 x3 : 0000000000000000
> x2 : ffffffe647e528f4 x1 : 0000000000000001 x0 : 0000000000000004
> Call trace:
> __pi_scs_handle_fde_frame+0xd8/0x15c (P)
> module_finalize+0xfc/0x164
> post_relocation+0xbc/0xd8
> load_module+0xfd4/0x11a8
> __arm64_sys_finit_module+0x23c/0x328
> invoke_syscall+0x58/0xe4
> el0_svc_common+0x80/0xdc
> do_el0_svc+0x1c/0x28
> el0_svc+0x54/0x1c4
> el0t_64_sync_handler+0x68/0xdc
> el0t_64_sync+0x1c4/0x1c8
> Code: 54fffd4c 1400001f 3707ff63 aa0903ef (b85fcdf0)
Hmm, looks like a translation fault from the load buried here:
u32 insn = le32_to_cpup((void *)loc);
in scs_patch_loc(), called from the 'DW_CFA_negate_ra_state' case in
scs_handle_fde_frame(). So presumably 'loc' is bogus.
Since you replied to this patch, does reverting it fix the problem for
you?
> This is not a problem if I disable UNWIND_PATCH_PAC_INTO_SCS but I have
> no idea why.
Well, that avoids compiling the code that's crashing :p
> Looking around it seems like this might related:
>
> $ cat arch/arm64/include/asm/module.lds.h
> SECTIONS {
> [...]
> #ifdef CONFIG_UNWIND_TABLES
> /*
> * Currently, we only use unwind info at module load time, so we can
> * put it into the .init allocation.
> */
> .init.eh_frame : { *(.eh_frame) }
> #endif
This patch doesn't seem to change that though?
Ard, do you have any ideas here? I wonder whether the addition of
support for 64-bit offsets in 60de7a647fc5 ("arm64/scs: Deal with 64-bit
relative offsets in FDE frames") has introduced padding/alignment
requirements into 'struct eh_frame' and we end up off-by-4 for 'loc' or
something like that? The faulting address looks like an underflow.
Will
^ permalink raw reply
* Re: [PATCH v4 02/63] vmlinux.lds: Unify TEXT_MAIN, DATA_MAIN, and related macros
From: Carlos Llamas @ 2025-12-20 16:25 UTC (permalink / raw)
To: Josh Poimboeuf
Cc: x86, linux-kernel, Petr Mladek, Miroslav Benes, Joe Lawrence,
live-patching, Song Liu, laokz, Jiri Kosina,
Marcos Paulo de Souza, Weinan Liu, Fazla Mehrab, Chen Zhongjin,
Puranjay Mohan, Dylan Hatch, Peter Zijlstra, Heiko Carstens,
Vasily Gorbik, Alexander Gordeev, Ard Biesheuvel, Sami Tolvanen,
Will Deacon, kernel-team
In-Reply-To: <97d8b7710a8f5389e323d0933dec68888fec5f1f.1758067942.git.jpoimboe@kernel.org>
On Wed, Sep 17, 2025 at 09:03:10AM -0700, Josh Poimboeuf wrote:
> TEXT_MAIN, DATA_MAIN and friends are defined differently depending on
> whether certain config options enable -ffunction-sections and/or
> -fdata-sections.
>
> There's no technical reason for that beyond voodoo coding. Keeping the
> separate implementations adds unnecessary complexity, fragments the
> logic, and increases the risk of subtle bugs.
>
> Unify the macros by using the same input section patterns across all
> configs.
>
> This is a prerequisite for the upcoming livepatch klp-build tooling
> which will manually enable -ffunction-sections and -fdata-sections via
> KCFLAGS.
>
> Cc: Heiko Carstens <hca@linux.ibm.com>
> Cc: Vasily Gorbik <gor@linux.ibm.com>
> Cc: Alexander Gordeev <agordeev@linux.ibm.com>
> Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
> ---
> include/asm-generic/vmlinux.lds.h | 40 ++++++++++---------------------
> scripts/module.lds.S | 12 ++++------
> 2 files changed, 17 insertions(+), 35 deletions(-)
>
> diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
> index ae2d2359b79e9..6b2311fa41393 100644
> --- a/include/asm-generic/vmlinux.lds.h
> +++ b/include/asm-generic/vmlinux.lds.h
> @@ -87,39 +87,24 @@
> #define ALIGN_FUNCTION() . = ALIGN(CONFIG_FUNCTION_ALIGNMENT)
>
> /*
> - * LD_DEAD_CODE_DATA_ELIMINATION option enables -fdata-sections, which
> - * generates .data.identifier sections, which need to be pulled in with
> - * .data. We don't want to pull in .data..other sections, which Linux
> - * has defined. Same for text and bss.
> + * Support -ffunction-sections by matching .text and .text.*,
> + * but exclude '.text..*'.
> *
> - * With LTO_CLANG, the linker also splits sections by default, so we need
> - * these macros to combine the sections during the final link.
> - *
> - * With AUTOFDO_CLANG and PROPELLER_CLANG, by default, the linker splits
> - * text sections and regroups functions into subsections.
> - *
> - * RODATA_MAIN is not used because existing code already defines .rodata.x
> - * sections to be brought in with rodata.
> + * Special .text.* sections that are typically grouped separately, such as
> + * .text.unlikely or .text.hot, must be matched explicitly before using
> + * TEXT_MAIN.
> */
> -#if defined(CONFIG_LD_DEAD_CODE_DATA_ELIMINATION) || defined(CONFIG_LTO_CLANG) || \
> -defined(CONFIG_AUTOFDO_CLANG) || defined(CONFIG_PROPELLER_CLANG)
> #define TEXT_MAIN .text .text.[0-9a-zA-Z_]*
> -#else
> -#define TEXT_MAIN .text
> -#endif
> -#if defined(CONFIG_LD_DEAD_CODE_DATA_ELIMINATION) || defined(CONFIG_LTO_CLANG)
> +
> +/*
> + * Support -fdata-sections by matching .data, .data.*, and others,
> + * but exclude '.data..*'.
> + */
> #define DATA_MAIN .data .data.[0-9a-zA-Z_]* .data.rel.* .data..L* .data..compoundliteral* .data.$__unnamed_* .data.$L*
> #define SDATA_MAIN .sdata .sdata.[0-9a-zA-Z_]*
> #define RODATA_MAIN .rodata .rodata.[0-9a-zA-Z_]* .rodata..L*
> #define BSS_MAIN .bss .bss.[0-9a-zA-Z_]* .bss..L* .bss..compoundliteral*
> #define SBSS_MAIN .sbss .sbss.[0-9a-zA-Z_]*
> -#else
> -#define DATA_MAIN .data .data.rel .data.rel.local
> -#define SDATA_MAIN .sdata
> -#define RODATA_MAIN .rodata
> -#define BSS_MAIN .bss
> -#define SBSS_MAIN .sbss
> -#endif
>
> /*
> * GCC 4.5 and later have a 32 bytes section alignment for structures.
> @@ -580,9 +565,8 @@ defined(CONFIG_AUTOFDO_CLANG) || defined(CONFIG_PROPELLER_CLANG)
> * during second ld run in second ld pass when generating System.map
> *
> * TEXT_MAIN here will match symbols with a fixed pattern (for example,
> - * .text.hot or .text.unlikely) if dead code elimination or
> - * function-section is enabled. Match these symbols first before
> - * TEXT_MAIN to ensure they are grouped together.
> + * .text.hot or .text.unlikely). Match those before TEXT_MAIN to ensure
> + * they get grouped together.
> *
> * Also placing .text.hot section at the beginning of a page, this
> * would help the TLB performance.
> diff --git a/scripts/module.lds.S b/scripts/module.lds.S
> index ee79c41059f3d..2632c6cb8ebe7 100644
> --- a/scripts/module.lds.S
> +++ b/scripts/module.lds.S
> @@ -38,12 +38,10 @@ SECTIONS {
> __kcfi_traps : { KEEP(*(.kcfi_traps)) }
> #endif
>
> -#ifdef CONFIG_LTO_CLANG
> - /*
> - * With CONFIG_LTO_CLANG, LLD always enables -fdata-sections and
> - * -ffunction-sections, which increases the size of the final module.
> - * Merge the split sections in the final binary.
> - */
> + .text : {
> + *(.text .text.[0-9a-zA-Z_]*)
> + }
> +
Cc: Ard Biesheuvel <ardb@kernel.org>
Cc: Sami Tolvanen <samitolvanen@google.com>
I'm seeing some KP when trying to load modules after this change. I
believe there is some sort of incompatibility with the SCS (Shadow Call
Stack) code in arm64? The panic is always on __pi_scs_handle_fde_frame:
init: Loading module [...]/drivers/net/wireless/virtual/mac80211_hwsim.ko
Unable to handle kernel paging request at virtual address ffffffe6468f0ffc
[...]
pc : __pi_scs_handle_fde_frame+0xd8/0x15c
lr : __pi_$x+0x74/0x138
sp : ffffffc08005bb10
x29: ffffffc08005bb10 x28: ffffffc081873010 x27: 0000000000000000
x26: 0000000000000007 x25: 0000000000000000 x24: 0000000000000000
x23: 0000000000000001 x22: ffffffe649794fa0 x21: ffffffe6469190b4
x20: 000000000000182c x19: 0000000000000001 x18: ffffffc080053000
x17: 000000000000002d x16: ffffffe6469190c5 x15: ffffffe6468f1000
x14: 000000000000003e x13: ffffffe6469190c6 x12: 00000000d50323bf
x11: 00000000d503233f x10: ffffffe649119cb8 x9 : ffffffe6468f1000
x8 : 0000000000000100 x7 : 00656d6172665f68 x6 : 0000000000000001
x5 : 6372610000000000 x4 : 0000008000000000 x3 : 0000000000000000
x2 : ffffffe647e528f4 x1 : 0000000000000001 x0 : 0000000000000004
Call trace:
__pi_scs_handle_fde_frame+0xd8/0x15c (P)
module_finalize+0xfc/0x164
post_relocation+0xbc/0xd8
load_module+0xfd4/0x11a8
__arm64_sys_finit_module+0x23c/0x328
invoke_syscall+0x58/0xe4
el0_svc_common+0x80/0xdc
do_el0_svc+0x1c/0x28
el0_svc+0x54/0x1c4
el0t_64_sync_handler+0x68/0xdc
el0t_64_sync+0x1c4/0x1c8
Code: 54fffd4c 1400001f 3707ff63 aa0903ef (b85fcdf0)
This is not a problem if I disable UNWIND_PATCH_PAC_INTO_SCS but I have
no idea why. Looking around it seems like this might related:
$ cat arch/arm64/include/asm/module.lds.h
SECTIONS {
[...]
#ifdef CONFIG_UNWIND_TABLES
/*
* Currently, we only use unwind info at module load time, so we can
* put it into the .init allocation.
*/
.init.eh_frame : { *(.eh_frame) }
#endif
I must note that I've only seen this in Android kernels and I have not
tried to reproduce the issue elsewhere. However, the incompatibility
seems like it could be applicable upstream too and I'm hoping that the
issue is evident to others (I can't understand any of this).
Thanks,
--
Carlos Llamas
^ permalink raw reply
* Re: [PATCH v2 0/2] bpf, x86/unwind/orc: Support reliable unwinding through BPF stack frames
From: patchwork-bot+netdevbpf @ 2025-12-10 7:40 UTC (permalink / raw)
To: Josh Poimboeuf
Cc: x86, linux-kernel, live-patching, bpf, andrey.grodzovsky, pmladek,
song, raja.khan, mbenes, ast, daniel, andrii, peterz
In-Reply-To: <cover.1764818927.git.jpoimboe@kernel.org>
Hello:
This series was applied to bpf/bpf.git (master)
by Alexei Starovoitov <ast@kernel.org>:
On Wed, 3 Dec 2025 19:32:14 -0800 you wrote:
> Fix livepatch stalls which may be seen when a task is blocked with BPF
> JIT on its kernel stack.
>
> Changes since v1 (https://lore.kernel.org/cover.1764699074.git.jpoimboe@kernel.org):
> - fix NULL ptr deref in __arch_prepare_bpf_trampoline()
>
> Josh Poimboeuf (2):
> bpf: Add bpf_has_frame_pointer()
> x86/unwind/orc: Support reliable unwinding through BPF stack frames
>
> [...]
Here is the summary with links:
- [v2,1/2] bpf: Add bpf_has_frame_pointer()
https://git.kernel.org/bpf/bpf/c/ca45c84afb8c
- [v2,2/2] x86/unwind/orc: Support reliable unwinding through BPF stack frames
(no matching commit)
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* Re: [PATCH] powerpc64/bpf: support direct_call on livepatch function
From: Hari Bathini @ 2025-12-08 16:35 UTC (permalink / raw)
To: Naveen N Rao
Cc: Madhavan Srinivasan, linuxppc-dev, Christophe Leroy,
Michael Ellerman, Nicholas Piggin, bpf, Alexei Starovoitov,
Daniel Borkmann, Andrii Nakryiko, Song Liu, Jiri Olsa,
Viktor Malik, live-patching, Josh Poimboeuf, Joe Lawrence,
Jiri Kosina, linux-trace-kernel, Steven Rostedt, Masami Hiramatsu,
Mark Rutland, Shung-Hsi Yu
In-Reply-To: <nuinyo7o7uniemqqmoboctwrkkwkuv77nt7yk6td6eb3x43hv2@2lukfuvcmcko>
Thanks for the review, Naveen.
I was on leave for sometime and could not look into it in a while
after that.
On 15/10/25 11:48 am, Naveen N Rao wrote:
> On Fri, Oct 10, 2025 at 12:47:21PM +0530, Hari Bathini wrote:
>>
>>
>> On 09/10/25 4:57 pm, Naveen N Rao wrote:
>>> On Thu, Oct 09, 2025 at 11:19:45AM +0530, Hari Bathini wrote:
>>>>
>>>>
>>>> On 08/10/25 1:43 pm, Naveen N Rao wrote:
>>>>> On Mon, Oct 06, 2025 at 06:50:20PM +0530, Hari Bathini wrote:
>>>>>>
>>>>>>
>>>>>> On 06/10/25 1:22 pm, Naveen N Rao wrote:
>>>>>>> On Fri, Oct 03, 2025 at 12:57:54AM +0530, Hari Bathini wrote:
>>>>>>>> Today, livepatch takes precedence over direct_call. Instead, save the
>>>>>>>> state and make direct_call before handling livepatch.
>>>>>>>
>>>>>>> If we call into the BPF trampoline first and if we have
>>>>>>> BPF_TRAMP_F_CALL_ORIG set, does this result in the BPF trampoline
>>>>>>> calling the new copy of the live-patched function or the old one?
>>>>>>
>>>>>> Naveen, calls the new copy of the live-patched function..
>>>>>
>>>>> Hmm... I'm probably missing something.
>>>>>
>>>>> With ftrace OOL stubs, what I recall is that BPF trampoline derives the
>>>>> original function address from the OOL stub (which would be associated
>>>>> with the original function, not the livepatch one).
>>>>
>>>> Trampoline derives the address from LR.
>>>
>>> Does it? I'm referring to BPF_TRAMP_F_CALL_ORIG handling in
>>> __arch_prepare_bpf_trampoline().
>>
>>
>>> LR at BPF trampoline entry points at
>>> the ftrace OOL stub. We recover the "real LR" pointing to the function
>>> being traced from there so that we can call into it from within the BPF
>>> trampoline.
>>
>> Naveen, from the snippet in livepatch_handler code shared below,
>> the LR at BPF trmapoline entry points at the 'nop' after the call
>> to trampoline with 'bnectrl cr1' in the updated livepatch_handler.
>>
>> Mimic'ing ftrace OOL branch instruction in livepatch_handler
>> with 'b 1f' (the instruction after nop) to ensure the trmapoline
>> derives the real LR to '1f' and jumps back into the livepatch_handler..
>>
>> + /* Jump to the direct_call */
>> + bnectrl cr1
>> +
>> + /*
>> + * The address to jump after direct call is deduced based on ftrace
>> OOL stub sequence.
>> + * The seemingly insignificant couple of instructions below is to
>> mimic that here to
>> + * jump back to the livepatch handler code below.
>> + */
>> + nop
>> + b 1f
>> +
>> + /*
>> + * Restore the state for livepatching from the livepatch stack.
>> + * Before that, check if livepatch stack is intact. Use r0 for it.
>> + */
>> +1: mtctr r0
>
> Ah, so you are faking a ftrace OOL stub here. But, won't this mean that
Yeah.
> bpf_get_func_ip() won't return the function address anymore?
Right. I do agree it can have issues in some scenarios.
>
> One of the other thoughts I had was if we could stuff the function
> address into the ftrace OOL stub. I had considered this back when I
> implemented the OOL stubs, but didn't do it due to the extra memory
> requirement. However, given the dance we're having to do, I'm now
> thinking that may make sense and can simplify the code. If we can also
> hook into livepatch, then we should be able to update the function
> address in the stub to point to the new address and the trampoline
> should then "just work" since it already saves/restores the TOC [We may
> additionally have to update the function IP in _R12, but that would be a
> minor change overall]
>
> We will still need a way to restore livepatch TOC if the BPF trampoline
> doesn't itself call into the function, but we may be able to handle that
> if we change the return address to jump to a stub that restores the TOC
> from the livepatch stack.
Sounds doable. Looking into a couple of other things at the moment
though. Will try out this suggestion and get back post that.
Having said that, your thoughts on whether the current approach
is a viable option if bpf_get_func_ip() can be fixed somehow?
- Hari
^ permalink raw reply
* [PATCH AUTOSEL 6.18-5.10] livepatch: Match old_sympos 0 and 1 in klp_find_func()
From: Sasha Levin @ 2025-12-05 4:33 UTC (permalink / raw)
To: patches, stable
Cc: Song Liu, Josh Poimboeuf, Petr Mladek, Sasha Levin, jikos, mbenes,
live-patching
In-Reply-To: <20251205043401.528993-1-sashal@kernel.org>
From: Song Liu <song@kernel.org>
[ Upstream commit 139560e8b973402140cafeb68c656c1374bd4c20 ]
When there is only one function of the same name, old_sympos of 0 and 1
are logically identical. Match them in klp_find_func().
This is to avoid a corner case with different toolchain behavior.
In this specific issue, two versions of kpatch-build were used to
build livepatch for the same kernel. One assigns old_sympos == 0 for
unique local functions, the other assigns old_sympos == 1 for unique
local functions. Both versions work fine by themselves. (PS: This
behavior change was introduced in a downstream version of kpatch-build.
This change does not exist in upstream kpatch-build.)
However, during livepatch upgrade (with the replace flag set) from a
patch built with one version of kpatch-build to the same fix built with
the other version of kpatch-build, livepatching fails with errors like:
[ 14.218706] sysfs: cannot create duplicate filename 'xxx/somefunc,1'
...
[ 14.219466] Call Trace:
[ 14.219468] <TASK>
[ 14.219469] dump_stack_lvl+0x47/0x60
[ 14.219474] sysfs_warn_dup.cold+0x17/0x27
[ 14.219476] sysfs_create_dir_ns+0x95/0xb0
[ 14.219479] kobject_add_internal+0x9e/0x260
[ 14.219483] kobject_add+0x68/0x80
[ 14.219485] ? kstrdup+0x3c/0xa0
[ 14.219486] klp_enable_patch+0x320/0x830
[ 14.219488] patch_init+0x443/0x1000 [ccc_0_6]
[ 14.219491] ? 0xffffffffa05eb000
[ 14.219492] do_one_initcall+0x2e/0x190
[ 14.219494] do_init_module+0x67/0x270
[ 14.219496] init_module_from_file+0x75/0xa0
[ 14.219499] idempotent_init_module+0x15a/0x240
[ 14.219501] __x64_sys_finit_module+0x61/0xc0
[ 14.219503] do_syscall_64+0x5b/0x160
[ 14.219505] entry_SYSCALL_64_after_hwframe+0x4b/0x53
[ 14.219507] RIP: 0033:0x7f545a4bd96d
...
[ 14.219516] kobject: kobject_add_internal failed for somefunc,1 with
-EEXIST, don't try to register things with the same name ...
This happens because klp_find_func() thinks somefunc with old_sympos==0
is not the same as somefunc with old_sympos==1, and klp_add_object_nops
adds another xxx/func,1 to the list of functions to patch.
Signed-off-by: Song Liu <song@kernel.org>
Acked-by: Josh Poimboeuf <jpoimboe@kernel.org>
[pmladek@suse.com: Fixed some typos.]
Reviewed-by: Petr Mladek <pmladek@suse.com>
Tested-by: Petr Mladek <pmladek@suse.com>
Signed-off-by: Petr Mladek <pmladek@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
## Analysis
### 1. COMMIT MESSAGE ANALYSIS
**Subject:** `livepatch: Match old_sympos 0 and 1 in klp_find_func()`
**Key indicators:**
- Fixes a bug: livepatch upgrade failures with replace flag
- Real-world impact: sysfs duplicate filename error causing patch
enablement to fail
- Clear problem description with error logs
- Tested-by: Petr Mladek
- Reviewed-by: Petr Mladek, Josh Poimboeuf
**Root cause:** Different versions of kpatch-build assign `old_sympos` 0
vs 1 for unique functions. During livepatch upgrade with replace,
`klp_find_func()` doesn't match them, leading to duplicate sysfs
entries.
### 2. CODE CHANGE ANALYSIS
**Files changed:** 1 file (`kernel/livepatch/core.c`)
**Lines changed:** 7 lines added, 1 line modified
**Change:**
```c
// Before:
if ((strcmp(old_func->old_name, func->old_name) == 0) &&
(old_func->old_sympos == func->old_sympos)) {
// After:
if ((strcmp(old_func->old_name, func->old_name) == 0) &&
((old_func->old_sympos == func->old_sympos) ||
(old_func->old_sympos == 0 && func->old_sympos == 1) ||
(old_func->old_sympos == 1 && func->old_sympos == 0))) {
```
**Technical explanation:**
- For unique symbols, `old_sympos` 0 and 1 both refer to the first
occurrence
- `klp_find_object_symbol()` treats `sympos == 0` as "unique symbol"
(see lines 170-175)
- Sysfs displays `old_sympos == 0` as `1` (line 820: `func->old_sympos ?
func->old_sympos : 1`)
- The fix makes `klp_find_func()` treat 0 and 1 as equivalent for
matching
**Why this fixes the bug:**
- During replace upgrade, `klp_add_object_nops()` calls
`klp_find_func()` to check if a function already exists
- Without the fix, `old_sympos==0` and `old_sympos==1` don't match
- This causes duplicate sysfs entries, leading to `-EEXIST` and patch
enablement failure
### 3. CLASSIFICATION
**Type:** Bug fix (not a feature)
**Exception categories:** None needed — this is a bug fix
**Security:** No security impact, but prevents a reliability issue
### 4. SCOPE AND RISK ASSESSMENT
**Scope:**
- Single function (`klp_find_func()`)
- Localized change
- No architectural changes
**Risk:** Low
- Small, targeted change
- Clear logic
- No new code paths
- Only affects matching logic for unique symbols
**Potential issues:**
- None identified
- Change is conservative (adds equivalence, doesn't remove checks)
### 5. USER IMPACT
**Severity:** High for affected users
- Prevents livepatch upgrades with replace flag
- Causes kernel errors and patch enablement failure
- Affects users upgrading between different kpatch-build versions
**Affected users:**
- Users performing livepatch upgrades with replace
- Users mixing kpatch-build versions
- Enterprise users relying on livepatch for updates
**Impact assessment:**
- Core livepatch functionality (upgrade path)
- Real-world scenario (different toolchain versions)
- User-visible failure (error messages, failed upgrades)
### 6. STABILITY INDICATORS
**Testing:**
- Tested-by: Petr Mladek
- Reviewed-by: Petr Mladek, Josh Poimboeuf
- Real-world scenario documented
**Code maturity:**
- Function exists since atomic replace (Jan 2019)
- Present in stable trees (5.1+)
- Mature code path
### 7. DEPENDENCY CHECK
**Dependencies:**
1. `klp_find_func()` — introduced with atomic replace (commit
e1452b607c48c, Jan 2019)
2. `klp_add_object_nops()` — same commit
3. Replace functionality — present since ~5.1
**Backport compatibility:**
- Applies cleanly to any stable tree with atomic replace
- No other commits required
- Self-contained fix
**Affected stable versions:**
- Any stable tree with atomic replace (~5.1+)
- All current LTS trees (6.1.y, 6.6.y, etc.)
### 8. STABLE KERNEL RULES COMPLIANCE
**Meets criteria:**
1. Obviously correct: Yes — clear equivalence for unique symbols
2. Fixes real bug: Yes — documented failure case
3. Important issue: Yes — breaks livepatch upgrades
4. Small and contained: Yes — 7 lines, 1 function
5. No new features: Yes — bug fix only
6. Applies cleanly: Yes — no conflicts expected
**No violations:**
- No new features
- No API changes
- No architectural changes
- No new dependencies
### 9. RISK VS BENEFIT TRADE-OFF
**Benefit:**
- Fixes upgrade failures
- Low risk, high value
- Addresses real user issue
**Risk:**
- Minimal — localized change
- Conservative logic
- Well-tested
**Conclusion:** Strong benefit, minimal risk
### 10. FINAL ASSESSMENT
This commit should be backported to stable kernel trees.
**Reasons:**
1. Fixes a real bug that breaks livepatch upgrades
2. Small, localized change (7 lines)
3. Low risk, clear logic
4. Well-tested and reviewed
5. No new features or dependencies
6. Applies cleanly to stable trees with atomic replace
7. High user impact for affected users
**Recommendation:** Backport to all stable trees that include atomic
replace functionality (approximately 5.1.y and later).
**YES**
kernel/livepatch/core.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c
index 0e73fac55f8eb..4e7a5cbc40a91 100644
--- a/kernel/livepatch/core.c
+++ b/kernel/livepatch/core.c
@@ -88,8 +88,14 @@ static struct klp_func *klp_find_func(struct klp_object *obj,
struct klp_func *func;
klp_for_each_func(obj, func) {
+ /*
+ * Besides identical old_sympos, also consider old_sympos
+ * of 0 and 1 are identical.
+ */
if ((strcmp(old_func->old_name, func->old_name) == 0) &&
- (old_func->old_sympos == func->old_sympos)) {
+ ((old_func->old_sympos == func->old_sympos) ||
+ (old_func->old_sympos == 0 && func->old_sympos == 1) ||
+ (old_func->old_sympos == 1 && func->old_sympos == 0))) {
return func;
}
}
--
2.51.0
^ permalink raw reply related
* Re: [PATCH v2 1/2] bpf: Add bpf_has_frame_pointer()
From: Josh Poimboeuf @ 2025-12-04 17:02 UTC (permalink / raw)
To: Jiri Olsa
Cc: x86, linux-kernel, live-patching, bpf, Andrey Grodzovsky,
Petr Mladek, Song Liu, Raja Khan, Miroslav Benes,
Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Peter Zijlstra
In-Reply-To: <aTGU5zRKWWU78mCS@krava>
On Thu, Dec 04, 2025 at 03:04:23PM +0100, Jiri Olsa wrote:
> On Wed, Dec 03, 2025 at 07:32:15PM -0800, Josh Poimboeuf wrote:
> > EMIT1(0xC9); /* leave */
> > + if (im)
> > + im->ksym.fp_end = prog - (u8 *)rw_image;
>
> is the null check needed? there are other places in the function that
> use 'im' without that
That was a NULL pointer dereference found by BPF CI.
bpf_struct_ops_prepare_trampoline() calls arch_prepare_bpf_trampoline()
with NULL im.
--
Josh
^ permalink raw reply
* Re: [PATCH v2 0/2] bpf, x86/unwind/orc: Support reliable unwinding through BPF stack frames
From: Jiri Olsa @ 2025-12-04 14:27 UTC (permalink / raw)
To: Josh Poimboeuf
Cc: x86, linux-kernel, live-patching, bpf, Andrey Grodzovsky,
Petr Mladek, Song Liu, Raja Khan, Miroslav Benes,
Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Peter Zijlstra
In-Reply-To: <cover.1764818927.git.jpoimboe@kernel.org>
On Wed, Dec 03, 2025 at 07:32:14PM -0800, Josh Poimboeuf wrote:
> Fix livepatch stalls which may be seen when a task is blocked with BPF
> JIT on its kernel stack.
>
> Changes since v1 (https://lore.kernel.org/cover.1764699074.git.jpoimboe@kernel.org):
> - fix NULL ptr deref in __arch_prepare_bpf_trampoline()
>
> Josh Poimboeuf (2):
> bpf: Add bpf_has_frame_pointer()
> x86/unwind/orc: Support reliable unwinding through BPF stack frames
>
tried with bpftrace and it seems to go over bpf_prog properly
in this case:
bpf_prog_2beb79c650d605dd_fentry_bpf_testmod_bpf_kfunc_common_test_1+320
bpf_trampoline_354334973728+60
bpf_kfunc_common_test+9
bpf_prog_f837cdd29a0519b9_test1+25
trace_call_bpf+345
kprobe_perf_func+76
aggr_pre_handler+72
kprobe_ftrace_handler+361
drm_core_init+202
bpf_fentry_test1+9
bpf_prog_test_run_tracing+357
__sys_bpf+2263
__x64_sys_bpf+33
do_syscall_64+134
entry_SYSCALL_64_after_hwframe+118
Reviewed-by: Jiri Olsa <jolsa@kernel.org>
thanks,
jirka
^ permalink raw reply
* Re: [PATCH v2 1/2] bpf: Add bpf_has_frame_pointer()
From: Jiri Olsa @ 2025-12-04 14:04 UTC (permalink / raw)
To: Josh Poimboeuf
Cc: x86, linux-kernel, live-patching, bpf, Andrey Grodzovsky,
Petr Mladek, Song Liu, Raja Khan, Miroslav Benes,
Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Peter Zijlstra
In-Reply-To: <fd2bc5b4e261a680774b28f6100509fd5ebad2f0.1764818927.git.jpoimboe@kernel.org>
On Wed, Dec 03, 2025 at 07:32:15PM -0800, Josh Poimboeuf wrote:
> Introduce a bpf_has_frame_pointer() helper that unwinders can call to
> determine whether a given instruction pointer is within the valid frame
> pointer region of a BPF JIT program or trampoline (i.e., after the
> prologue, before the epilogue).
>
> This will enable livepatch (with the ORC unwinder) to reliably unwind
> through BPF JIT frames.
>
> Acked-by: Song Liu <song@kernel.org>
> Acked-and-tested-by: Andrey Grodzovsky<andrey.grodzovsky@crowdstrike.com>
> Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
> ---
> arch/x86/net/bpf_jit_comp.c | 12 ++++++++++++
> include/linux/bpf.h | 3 +++
> kernel/bpf/core.c | 16 ++++++++++++++++
> 3 files changed, 31 insertions(+)
>
> diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
> index de5083cb1d37..3ec4fa94086a 100644
> --- a/arch/x86/net/bpf_jit_comp.c
> +++ b/arch/x86/net/bpf_jit_comp.c
> @@ -1661,6 +1661,9 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image
> emit_prologue(&prog, image, stack_depth,
> bpf_prog_was_classic(bpf_prog), tail_call_reachable,
> bpf_is_subprog(bpf_prog), bpf_prog->aux->exception_cb);
> +
> + bpf_prog->aux->ksym.fp_start = prog - temp;
> +
> /* Exception callback will clobber callee regs for its own use, and
> * restore the original callee regs from main prog's stack frame.
> */
> @@ -2716,6 +2719,8 @@ st: if (is_imm8(insn->off))
> pop_r12(&prog);
> }
> EMIT1(0xC9); /* leave */
> + bpf_prog->aux->ksym.fp_end = prog - temp;
> +
> emit_return(&prog, image + addrs[i - 1] + (prog - temp));
> break;
>
> @@ -3299,6 +3304,9 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *rw_im
> }
> EMIT1(0x55); /* push rbp */
> EMIT3(0x48, 0x89, 0xE5); /* mov rbp, rsp */
> + if (im)
> + im->ksym.fp_start = prog - (u8 *)rw_image;
> +
> if (!is_imm8(stack_size)) {
> /* sub rsp, stack_size */
> EMIT3_off32(0x48, 0x81, 0xEC, stack_size);
> @@ -3436,7 +3444,11 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *rw_im
> emit_ldx(&prog, BPF_DW, BPF_REG_0, BPF_REG_FP, -8);
>
> emit_ldx(&prog, BPF_DW, BPF_REG_6, BPF_REG_FP, -rbx_off);
> +
> EMIT1(0xC9); /* leave */
> + if (im)
> + im->ksym.fp_end = prog - (u8 *)rw_image;
is the null check needed? there are other places in the function that
use 'im' without that
thanks,
jirka
> +
> if (flags & BPF_TRAMP_F_SKIP_FRAME) {
> /* skip our return address and return to parent */
> EMIT4(0x48, 0x83, 0xC4, 8); /* add rsp, 8 */
> diff --git a/include/linux/bpf.h b/include/linux/bpf.h
> index d808253f2e94..e3f56e8443da 100644
> --- a/include/linux/bpf.h
> +++ b/include/linux/bpf.h
> @@ -1257,6 +1257,8 @@ struct bpf_ksym {
> struct list_head lnode;
> struct latch_tree_node tnode;
> bool prog;
> + u32 fp_start;
> + u32 fp_end;
> };
>
> enum bpf_tramp_prog_type {
> @@ -1483,6 +1485,7 @@ void bpf_image_ksym_add(struct bpf_ksym *ksym);
> void bpf_image_ksym_del(struct bpf_ksym *ksym);
> void bpf_ksym_add(struct bpf_ksym *ksym);
> void bpf_ksym_del(struct bpf_ksym *ksym);
> +bool bpf_has_frame_pointer(unsigned long ip);
> int bpf_jit_charge_modmem(u32 size);
> void bpf_jit_uncharge_modmem(u32 size);
> bool bpf_prog_has_trampoline(const struct bpf_prog *prog);
> diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
> index d595fe512498..7cd8382d1152 100644
> --- a/kernel/bpf/core.c
> +++ b/kernel/bpf/core.c
> @@ -760,6 +760,22 @@ struct bpf_prog *bpf_prog_ksym_find(unsigned long addr)
> NULL;
> }
>
> +bool bpf_has_frame_pointer(unsigned long ip)
> +{
> + struct bpf_ksym *ksym;
> + unsigned long offset;
> +
> + guard(rcu)();
> +
> + ksym = bpf_ksym_find(ip);
> + if (!ksym || !ksym->fp_start || !ksym->fp_end)
> + return false;
> +
> + offset = ip - ksym->start;
> +
> + return offset >= ksym->fp_start && offset < ksym->fp_end;
> +}
> +
> const struct exception_table_entry *search_bpf_extables(unsigned long addr)
> {
> const struct exception_table_entry *e = NULL;
> --
> 2.51.1
>
>
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox