* [PATCH bpf-next] selftests/bpf: Add BPF struct_ops + livepatch integration test @ 2026-04-08 17:52 Song Liu 2026-04-12 8:43 ` Yafang Shao 2026-04-12 21:02 ` Alexei Starovoitov 0 siblings, 2 replies; 10+ messages in thread From: Song Liu @ 2026-04-08 17:52 UTC (permalink / raw) To: bpf Cc: ast, daniel, andrii, martin.lau, eddyz87, memxor, yonghong.song, jolsa, kernel-team, laoar.shao, Song Liu Add a selftest that demonstrates BPF struct_ops controlling kernel behavior through livepatch. A kernel module (test_klp_bpf) livepatches cmdline_proc_show() and delegates output to a BPF struct_ops callback. The BPF program writes a custom string to /proc/cmdline via the bpf_klp_seq_write kfunc. Components: - test_kmods/test_klp_bpf.c: kernel module that registers a klp_bpf_cmdline_ops struct_ops type, livepatches cmdline_proc_show, and provides bpf_klp_seq_write kfunc for seq_file writes - progs/test_klp_bpf.c: BPF struct_ops program implementing set_cmdline callback - prog_tests/test_klp_bpf.c: userspace test verifying /proc/cmdline output with and without BPF struct_ops attached Assisted-by: Claude:claude-opus-4-6 Signed-off-by: Song Liu <song@kernel.org> --- This shows an alternative solution to the idea proposed in [1]. This approach doesn't need any kernel change. [1] https://lore.kernel.org/bpf/20260402092607.96430-1-laoar.shao@gmail.com/ --- tools/testing/selftests/bpf/Makefile | 2 +- .../selftests/bpf/prog_tests/test_klp_bpf.c | 109 ++++++++++++ .../selftests/bpf/progs/test_klp_bpf.c | 26 +++ .../testing/selftests/bpf/test_kmods/Makefile | 3 +- .../selftests/bpf/test_kmods/test_klp_bpf.c | 166 ++++++++++++++++++ .../selftests/bpf/test_kmods/test_klp_bpf.h | 12 ++ 6 files changed, 316 insertions(+), 2 deletions(-) create mode 100644 tools/testing/selftests/bpf/prog_tests/test_klp_bpf.c create mode 100644 tools/testing/selftests/bpf/progs/test_klp_bpf.c create mode 100644 tools/testing/selftests/bpf/test_kmods/test_klp_bpf.c create mode 100644 tools/testing/selftests/bpf/test_kmods/test_klp_bpf.h diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index f75c4f52c028..22ef1f76196d 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -121,7 +121,7 @@ TEST_PROGS_EXTENDED := \ ima_setup.sh verify_sig_setup.sh TEST_KMODS := bpf_testmod.ko bpf_test_no_cfi.ko bpf_test_modorder_x.ko \ - bpf_test_modorder_y.ko bpf_test_rqspinlock.ko + bpf_test_modorder_y.ko bpf_test_rqspinlock.ko test_klp_bpf.ko TEST_KMOD_TARGETS = $(addprefix $(OUTPUT)/,$(TEST_KMODS)) # Compile but not part of 'make run_tests' diff --git a/tools/testing/selftests/bpf/prog_tests/test_klp_bpf.c b/tools/testing/selftests/bpf/prog_tests/test_klp_bpf.c new file mode 100644 index 000000000000..f70c4d1d0176 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/test_klp_bpf.c @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2026 Meta Platforms, Inc. and affiliates. */ + +#include <test_progs.h> +#include "testing_helpers.h" +#include "test_klp_bpf.skel.h" + +#define KLP_MODULE_NAME "test_klp_bpf" +#define KLP_ENABLED_PATH "/sys/kernel/livepatch/" KLP_MODULE_NAME "/enabled" + +static int load_klp_module(void) +{ + return load_module("test_klp_bpf.ko", env_verbosity > VERBOSE_NONE); +} + +static void unload_klp_module(void) +{ + /* Disable the livepatch before unloading */ + if (!access(KLP_ENABLED_PATH, F_OK)) + system("echo 0 > " KLP_ENABLED_PATH); + + unload_module(KLP_MODULE_NAME, env_verbosity > VERBOSE_NONE); +} + +static int read_proc_cmdline(char *buf, size_t buf_sz) +{ + int fd, ret; + + fd = open("/proc/cmdline", O_RDONLY); + if (fd < 0) + return -errno; + + ret = read(fd, buf, buf_sz - 1); + close(fd); + if (ret < 0) + return -errno; + + buf[ret] = '\0'; + return 0; +} + +void test_klp_bpf(void) +{ + struct test_klp_bpf *skel = NULL; + struct bpf_link *link = NULL; + char buf[4096] = {}; + int err; + + /* Skip if kernel was built without CONFIG_LIVEPATCH */ + if (access("/sys/kernel/livepatch", F_OK)) { + test__skip(); + return; + } + + err = load_klp_module(); + if (err) { + if (err == -ENOENT) { + test__skip(); + return; + } + /* Module may already be loaded; unload and retry */ + unload_klp_module(); + err = load_klp_module(); + if (!ASSERT_OK(err, "load_klp_module")) + return; + } + + /* Verify livepatch is active with fallback message */ + err = read_proc_cmdline(buf, sizeof(buf)); + if (!ASSERT_OK(err, "read_cmdline_fallback")) + goto out; + if (!ASSERT_OK(strncmp(buf, "test_klp_bpf: no struct_ops attached", + strlen("test_klp_bpf: no struct_ops attached")), + "fallback_msg")) + goto out; + + /* Load and attach BPF struct_ops */ + skel = test_klp_bpf__open_and_load(); + if (!ASSERT_OK_PTR(skel, "skel_open_and_load")) + goto out; + + link = bpf_map__attach_struct_ops(skel->maps.cmdline_ops); + if (!ASSERT_OK_PTR(link, "attach_struct_ops")) + goto out; + + /* Verify BPF-controlled cmdline */ + memset(buf, 0, sizeof(buf)); + err = read_proc_cmdline(buf, sizeof(buf)); + if (!ASSERT_OK(err, "read_cmdline_bpf")) + goto out; + ASSERT_STREQ(buf, "klp_bpf: custom cmdline\n", "bpf_cmdline"); + + /* Detach and verify fallback resumes */ + bpf_link__destroy(link); + link = NULL; + + memset(buf, 0, sizeof(buf)); + err = read_proc_cmdline(buf, sizeof(buf)); + if (!ASSERT_OK(err, "read_cmdline_detached")) + goto out; + ASSERT_OK(strncmp(buf, "test_klp_bpf: no struct_ops attached", + strlen("test_klp_bpf: no struct_ops attached")), + "detached_fallback_msg"); + +out: + bpf_link__destroy(link); + test_klp_bpf__destroy(skel); + unload_klp_module(); +} diff --git a/tools/testing/selftests/bpf/progs/test_klp_bpf.c b/tools/testing/selftests/bpf/progs/test_klp_bpf.c new file mode 100644 index 000000000000..f3b68232231a --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_klp_bpf.c @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2026 Meta Platforms, Inc. and affiliates. */ + +#include <vmlinux.h> +#include <bpf/bpf_helpers.h> +#include <bpf/bpf_tracing.h> +#include "../test_kmods/test_klp_bpf.h" + +char _license[] SEC("license") = "GPL"; + +extern void bpf_klp_seq_write(struct seq_file *m, + const char *data, u32 data__sz) __ksym; + +SEC("struct_ops/set_cmdline") +int BPF_PROG(set_cmdline, struct seq_file *m) +{ + char custom[] = "klp_bpf: custom cmdline\n"; + + bpf_klp_seq_write(m, custom, sizeof(custom) - 1); + return 0; +} + +SEC(".struct_ops.link") +struct klp_bpf_cmdline_ops cmdline_ops = { + .set_cmdline = (void *)set_cmdline, +}; diff --git a/tools/testing/selftests/bpf/test_kmods/Makefile b/tools/testing/selftests/bpf/test_kmods/Makefile index 63c4d3f6a12f..bb182d668277 100644 --- a/tools/testing/selftests/bpf/test_kmods/Makefile +++ b/tools/testing/selftests/bpf/test_kmods/Makefile @@ -8,11 +8,12 @@ Q = @ endif MODULES = bpf_testmod.ko bpf_test_no_cfi.ko bpf_test_modorder_x.ko \ - bpf_test_modorder_y.ko bpf_test_rqspinlock.ko + bpf_test_modorder_y.ko bpf_test_rqspinlock.ko test_klp_bpf.ko $(foreach m,$(MODULES),$(eval obj-m += $(m:.ko=.o))) CFLAGS_bpf_testmod.o = -I$(src) +CFLAGS_test_klp_bpf.o = -I$(src) all: $(Q)$(MAKE) -C $(KDIR) M=$(TEST_KMOD_DIR) modules diff --git a/tools/testing/selftests/bpf/test_kmods/test_klp_bpf.c b/tools/testing/selftests/bpf/test_kmods/test_klp_bpf.c new file mode 100644 index 000000000000..62943b6db4a3 --- /dev/null +++ b/tools/testing/selftests/bpf/test_kmods/test_klp_bpf.c @@ -0,0 +1,166 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2026 Meta Platforms, Inc. and affiliates. */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/bpf.h> +#include <linux/btf.h> +#include <linux/btf_ids.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/livepatch.h> +#include <linux/seq_file.h> +#include <linux/bpf_verifier.h> +#include "test_klp_bpf.h" + +static struct klp_bpf_cmdline_ops *active_ops; + +/* --- kfunc: allow BPF struct_ops programs to write to seq_file --- */ + +__bpf_kfunc_start_defs(); + +__bpf_kfunc void bpf_klp_seq_write(struct seq_file *m, + const char *data, u32 data__sz) +{ + seq_write(m, data, data__sz); +} + +__bpf_kfunc_end_defs(); + +BTF_KFUNCS_START(klp_bpf_kfunc_ids) +BTF_ID_FLAGS(func, bpf_klp_seq_write) +BTF_KFUNCS_END(klp_bpf_kfunc_ids) + +static const struct btf_kfunc_id_set klp_bpf_kfunc_set = { + .owner = THIS_MODULE, + .set = &klp_bpf_kfunc_ids, +}; + +/* --- Livepatch replacement for cmdline_proc_show --- */ + +static int livepatch_cmdline_proc_show(struct seq_file *m, void *v) +{ + struct klp_bpf_cmdline_ops *ops = READ_ONCE(active_ops); + + if (ops && ops->set_cmdline) + return ops->set_cmdline(m); + + seq_printf(m, "%s: no struct_ops attached\n", THIS_MODULE->name); + return 0; +} + +static struct klp_func funcs[] = { + { + .old_name = "cmdline_proc_show", + .new_func = livepatch_cmdline_proc_show, + }, { } +}; + +static struct klp_object objs[] = { + { + /* name being NULL means vmlinux */ + .funcs = funcs, + }, { } +}; + +static struct klp_patch patch = { + .mod = THIS_MODULE, + .objs = objs, +}; + +/* --- struct_ops registration --- */ + +static int klp_bpf_cmdline_reg(void *kdata, struct bpf_link *link) +{ + struct klp_bpf_cmdline_ops *ops = kdata; + + if (cmpxchg(&active_ops, NULL, ops)) + return -EBUSY; + + return 0; +} + +static void klp_bpf_cmdline_unreg(void *kdata, struct bpf_link *link) +{ + WRITE_ONCE(active_ops, NULL); +} + +static int klp_bpf_cmdline_init(struct btf *btf) +{ + return 0; +} + +static int klp_bpf_cmdline_init_member(const struct btf_type *t, + const struct btf_member *member, + void *kdata, const void *udata) +{ + return 0; +} + +static bool klp_bpf_cmdline_is_valid_access(int off, int size, + enum bpf_access_type type, + const struct bpf_prog *prog, + struct bpf_insn_access_aux *info) +{ + return bpf_tracing_btf_ctx_access(off, size, type, prog, info); +} + +static int klp_bpf_cmdline_btf_struct_access(struct bpf_verifier_log *log, + const struct bpf_reg_state *reg, + int off, int size) +{ + return -EACCES; +} + +static const struct bpf_verifier_ops klp_bpf_cmdline_verifier_ops = { + .is_valid_access = klp_bpf_cmdline_is_valid_access, + .btf_struct_access = klp_bpf_cmdline_btf_struct_access, +}; + +/* CFI stubs */ +static int klp_bpf_cmdline__set_cmdline(struct seq_file *m) +{ + return 0; +} + +static struct klp_bpf_cmdline_ops __bpf_klp_bpf_cmdline_ops = { + .set_cmdline = klp_bpf_cmdline__set_cmdline, +}; + +static struct bpf_struct_ops bpf_klp_bpf_cmdline_ops = { + .verifier_ops = &klp_bpf_cmdline_verifier_ops, + .init = klp_bpf_cmdline_init, + .init_member = klp_bpf_cmdline_init_member, + .reg = klp_bpf_cmdline_reg, + .unreg = klp_bpf_cmdline_unreg, + .cfi_stubs = &__bpf_klp_bpf_cmdline_ops, + .name = "klp_bpf_cmdline_ops", + .owner = THIS_MODULE, +}; + +/* --- Module init/exit --- */ + +static int __init test_klp_bpf_init(void) +{ + int ret; + + ret = register_btf_kfunc_id_set(BPF_PROG_TYPE_STRUCT_OPS, + &klp_bpf_kfunc_set); + ret = ret ?: register_bpf_struct_ops(&bpf_klp_bpf_cmdline_ops, + klp_bpf_cmdline_ops); + if (ret) + return ret; + + return klp_enable_patch(&patch); +} + +static void __exit test_klp_bpf_exit(void) +{ +} + +module_init(test_klp_bpf_init); +module_exit(test_klp_bpf_exit); +MODULE_LICENSE("GPL"); +MODULE_INFO(livepatch, "Y"); +MODULE_AUTHOR("Song Liu"); +MODULE_DESCRIPTION("Test: BPF struct_ops + livepatch integration"); diff --git a/tools/testing/selftests/bpf/test_kmods/test_klp_bpf.h b/tools/testing/selftests/bpf/test_kmods/test_klp_bpf.h new file mode 100644 index 000000000000..0ead3681fb89 --- /dev/null +++ b/tools/testing/selftests/bpf/test_kmods/test_klp_bpf.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2026 Meta Platforms, Inc. and affiliates. */ +#ifndef _TEST_KLP_BPF_H +#define _TEST_KLP_BPF_H + +struct seq_file; + +struct klp_bpf_cmdline_ops { + int (*set_cmdline)(struct seq_file *m); +}; + +#endif /* _TEST_KLP_BPF_H */ -- 2.52.0 ^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH bpf-next] selftests/bpf: Add BPF struct_ops + livepatch integration test 2026-04-08 17:52 [PATCH bpf-next] selftests/bpf: Add BPF struct_ops + livepatch integration test Song Liu @ 2026-04-12 8:43 ` Yafang Shao 2026-04-13 21:41 ` Song Liu 2026-04-12 21:02 ` Alexei Starovoitov 1 sibling, 1 reply; 10+ messages in thread From: Yafang Shao @ 2026-04-12 8:43 UTC (permalink / raw) To: Song Liu Cc: bpf, ast, daniel, andrii, martin.lau, eddyz87, memxor, yonghong.song, jolsa, kernel-team On Thu, Apr 9, 2026 at 1:52 AM Song Liu <song@kernel.org> wrote: > > Add a selftest that demonstrates BPF struct_ops controlling kernel > behavior through livepatch. A kernel module (test_klp_bpf) livepatches > cmdline_proc_show() and delegates output to a BPF struct_ops callback. > The BPF program writes a custom string to /proc/cmdline via the > bpf_klp_seq_write kfunc. > > Components: > - test_kmods/test_klp_bpf.c: kernel module that registers a > klp_bpf_cmdline_ops struct_ops type, livepatches cmdline_proc_show, > and provides bpf_klp_seq_write kfunc for seq_file writes > - progs/test_klp_bpf.c: BPF struct_ops program implementing > set_cmdline callback > - prog_tests/test_klp_bpf.c: userspace test verifying /proc/cmdline > output with and without BPF struct_ops attached Cool idea! I just checked it out, and it works perfectly. [...] > --- /dev/null > +++ b/tools/testing/selftests/bpf/test_kmods/test_klp_bpf.c > @@ -0,0 +1,166 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* Copyright (c) 2026 Meta Platforms, Inc. and affiliates. */ > + > +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt > + > +#include <linux/bpf.h> > +#include <linux/btf.h> > +#include <linux/btf_ids.h> > +#include <linux/init.h> > +#include <linux/module.h> > +#include <linux/livepatch.h> > +#include <linux/seq_file.h> > +#include <linux/bpf_verifier.h> > +#include "test_klp_bpf.h" > + > +static struct klp_bpf_cmdline_ops *active_ops; > + > +/* --- kfunc: allow BPF struct_ops programs to write to seq_file --- */ > + > +__bpf_kfunc_start_defs(); > + > +__bpf_kfunc void bpf_klp_seq_write(struct seq_file *m, > + const char *data, u32 data__sz) > +{ > + seq_write(m, data, data__sz); > +} > + > +__bpf_kfunc_end_defs(); > + > +BTF_KFUNCS_START(klp_bpf_kfunc_ids) > +BTF_ID_FLAGS(func, bpf_klp_seq_write) > +BTF_KFUNCS_END(klp_bpf_kfunc_ids) > + > +static const struct btf_kfunc_id_set klp_bpf_kfunc_set = { > + .owner = THIS_MODULE, > + .set = &klp_bpf_kfunc_ids, > +}; > + > +/* --- Livepatch replacement for cmdline_proc_show --- */ > + > +static int livepatch_cmdline_proc_show(struct seq_file *m, void *v) > +{ > + struct klp_bpf_cmdline_ops *ops = READ_ONCE(active_ops); > + > + if (ops && ops->set_cmdline) > + return ops->set_cmdline(m); > + > + seq_printf(m, "%s: no struct_ops attached\n", THIS_MODULE->name); > + return 0; > +} > + > +static struct klp_func funcs[] = { > + { > + .old_name = "cmdline_proc_show", > + .new_func = livepatch_cmdline_proc_show, > + }, { } > +}; > + > +static struct klp_object objs[] = { > + { > + /* name being NULL means vmlinux */ > + .funcs = funcs, > + }, { } > +}; > + > +static struct klp_patch patch = { > + .mod = THIS_MODULE, > + .objs = objs, > +}; > + > +/* --- struct_ops registration --- */ > + > +static int klp_bpf_cmdline_reg(void *kdata, struct bpf_link *link) > +{ > + struct klp_bpf_cmdline_ops *ops = kdata; > + > + if (cmpxchg(&active_ops, NULL, ops)) > + return -EBUSY; > + > + return 0; > +} > + > +static void klp_bpf_cmdline_unreg(void *kdata, struct bpf_link *link) > +{ > + WRITE_ONCE(active_ops, NULL); > +} > + > +static int klp_bpf_cmdline_init(struct btf *btf) > +{ > + return 0; > +} > + > +static int klp_bpf_cmdline_init_member(const struct btf_type *t, > + const struct btf_member *member, > + void *kdata, const void *udata) > +{ > + return 0; > +} > + > +static bool klp_bpf_cmdline_is_valid_access(int off, int size, > + enum bpf_access_type type, > + const struct bpf_prog *prog, > + struct bpf_insn_access_aux *info) > +{ > + return bpf_tracing_btf_ctx_access(off, size, type, prog, info); > +} > + > +static int klp_bpf_cmdline_btf_struct_access(struct bpf_verifier_log *log, > + const struct bpf_reg_state *reg, > + int off, int size) > +{ > + return -EACCES; > +} > + > +static const struct bpf_verifier_ops klp_bpf_cmdline_verifier_ops = { > + .is_valid_access = klp_bpf_cmdline_is_valid_access, > + .btf_struct_access = klp_bpf_cmdline_btf_struct_access, > +}; > + > +/* CFI stubs */ > +static int klp_bpf_cmdline__set_cmdline(struct seq_file *m) > +{ > + return 0; > +} > + > +static struct klp_bpf_cmdline_ops __bpf_klp_bpf_cmdline_ops = { > + .set_cmdline = klp_bpf_cmdline__set_cmdline, > +}; > + > +static struct bpf_struct_ops bpf_klp_bpf_cmdline_ops = { > + .verifier_ops = &klp_bpf_cmdline_verifier_ops, > + .init = klp_bpf_cmdline_init, > + .init_member = klp_bpf_cmdline_init_member, > + .reg = klp_bpf_cmdline_reg, > + .unreg = klp_bpf_cmdline_unreg, > + .cfi_stubs = &__bpf_klp_bpf_cmdline_ops, > + .name = "klp_bpf_cmdline_ops", > + .owner = THIS_MODULE, > +}; > + > +/* --- Module init/exit --- */ > + > +static int __init test_klp_bpf_init(void) > +{ > + int ret; > + > + ret = register_btf_kfunc_id_set(BPF_PROG_TYPE_STRUCT_OPS, > + &klp_bpf_kfunc_set); > + ret = ret ?: register_bpf_struct_ops(&bpf_klp_bpf_cmdline_ops, > + klp_bpf_cmdline_ops); Is it possible to integrate this BTF registration directly into klp-build? It appears we might need to extend scripts/livepatch/init.c to provide the necessary support. -- Regards Yafang ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH bpf-next] selftests/bpf: Add BPF struct_ops + livepatch integration test 2026-04-12 8:43 ` Yafang Shao @ 2026-04-13 21:41 ` Song Liu 2026-04-14 6:55 ` Yafang Shao 0 siblings, 1 reply; 10+ messages in thread From: Song Liu @ 2026-04-13 21:41 UTC (permalink / raw) To: Yafang Shao Cc: bpf, ast, daniel, andrii, martin.lau, eddyz87, memxor, yonghong.song, jolsa, kernel-team [-- Attachment #1: Type: text/plain, Size: 763 bytes --] On Sun, Apr 12, 2026 at 1:44 AM Yafang Shao <laoar.shao@gmail.com> wrote: [...] > > + > > +/* --- Module init/exit --- */ > > + > > +static int __init test_klp_bpf_init(void) > > +{ > > + int ret; > > + > > + ret = register_btf_kfunc_id_set(BPF_PROG_TYPE_STRUCT_OPS, > > + &klp_bpf_kfunc_set); > > + ret = ret ?: register_bpf_struct_ops(&bpf_klp_bpf_cmdline_ops, > > + klp_bpf_cmdline_ops); > > Is it possible to integrate this BTF registration directly into > klp-build? It appears we might need to extend scripts/livepatch/init.c > to provide the necessary support. Can you try the attached patch and see whether it works? Thanks, Song [-- Attachment #2: klp-build.patch --] [-- Type: application/octet-stream, Size: 2894 bytes --] diff --git i/scripts/livepatch/klp-build w/scripts/livepatch/klp-build index 7b82c7503c2b..6201f99e4d05 100755 --- i/scripts/livepatch/klp-build +++ w/scripts/livepatch/klp-build @@ -566,6 +566,11 @@ copy_orig_objects() { done xtrace_restore + # Save vmlinux for BTF base reference when generating module BTF + if [[ -v CONFIG_DEBUG_INFO_BTF_MODULES ]] && [[ -f "$OBJ/vmlinux" ]]; then + cp -f "$OBJ/vmlinux" "$ORIG_DIR/vmlinux" + fi + mv -f "$TMP_DIR/build.log" "$ORIG_DIR" touch "$TIMESTAMP" } @@ -715,6 +720,36 @@ diff_checksums() { done } +# Regenerate BTF for the livepatch module +gen_module_btf() { + local kmod_file="$1" + + # Use the original (pre-patch) vmlinux as BTF base, since the module + # will be loaded on a kernel running that vmlinux. The patched vmlinux + # (currently at $OBJ/vmlinux) has different BTF string offsets. + local btf_base="$ORIG_DIR/vmlinux" + + [[ ! -f "$btf_base" ]] && { warn "original vmlinux not found, skipping BTF"; return; } + + # gen-btf.sh is a subprocess and needs these variables exported. + # Query tool paths and flags from kbuild rather than hardcoding + # them, since they vary with LLVM= and CROSS_COMPILE=. + local pahole objcopy pahole_flags + pahole="$(cd "$SRC" && make -s --no-print-directory \ + --eval='print-var: ; @echo $(PAHOLE)' print-var 2>/dev/null)" + objcopy="$(cd "$SRC" && make -s --no-print-directory \ + --eval='print-var: ; @echo $(OBJCOPY)' print-var 2>/dev/null)" + pahole_flags="$(cd "$SRC" && make -s --no-print-directory \ + --eval='print-var: ; @echo $(PAHOLE_FLAGS)' print-var 2>/dev/null)" + + PAHOLE="$pahole" PAHOLE_FLAGS="$pahole_flags" OBJCOPY="$objcopy" \ + RESOLVE_BTFIDS="$OBJ/tools/bpf/resolve_btfids/resolve_btfids" \ + RESOLVE_BTFIDS_FLAGS="--distill_base" \ + objtree="$OBJ" KBUILD_VERBOSE="" \ + "$SRC/scripts/gen-btf.sh" --btf_base "$btf_base" "$kmod_file" \ + || die "BTF generation failed" +} + # Build and post-process livepatch module in $KMOD_DIR build_patch_module() { local makefile="$KMOD_DIR/Kbuild" @@ -781,12 +816,22 @@ build_patch_module() { # Save off the intermediate binary for debugging cp -f "$kmod_file" "$kmod_file.orig" - # Work around issue where slight .config change makes corrupt BTF - objcopy --remove-section=.BTF "$kmod_file" + # Remove BTF sections from the kbuild M= build. They were generated + # against the patched vmlinux and will be regenerated below against + # the original vmlinux. + objcopy --remove-section=.BTF \ + --remove-section=.BTF.base \ + --remove-section=.BTF_ids \ + "$kmod_file" # Fix (and work around) linker wreckage for klp syms / relocs "$SRC/tools/objtool/objtool" klp post-link "$kmod_file" || die "objtool klp post-link failed" + # Regenerate BTF after post-link + if [[ -v CONFIG_DEBUG_INFO_BTF_MODULES ]]; then + gen_module_btf "$kmod_file" + fi + cp -f "$kmod_file" "$OUTFILE" } ^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH bpf-next] selftests/bpf: Add BPF struct_ops + livepatch integration test 2026-04-13 21:41 ` Song Liu @ 2026-04-14 6:55 ` Yafang Shao 2026-04-14 22:17 ` Song Liu 0 siblings, 1 reply; 10+ messages in thread From: Yafang Shao @ 2026-04-14 6:55 UTC (permalink / raw) To: Song Liu Cc: bpf, ast, daniel, andrii, martin.lau, eddyz87, memxor, yonghong.song, jolsa, kernel-team On Tue, Apr 14, 2026 at 5:42 AM Song Liu <song@kernel.org> wrote: > > On Sun, Apr 12, 2026 at 1:44 AM Yafang Shao <laoar.shao@gmail.com> wrote: > [...] > > > + > > > +/* --- Module init/exit --- */ > > > + > > > +static int __init test_klp_bpf_init(void) > > > +{ > > > + int ret; > > > + > > > + ret = register_btf_kfunc_id_set(BPF_PROG_TYPE_STRUCT_OPS, > > > + &klp_bpf_kfunc_set); > > > + ret = ret ?: register_bpf_struct_ops(&bpf_klp_bpf_cmdline_ops, > > > + klp_bpf_cmdline_ops); > > > > Is it possible to integrate this BTF registration directly into > > klp-build? It appears we might need to extend scripts/livepatch/init.c > > to provide the necessary support. > > Can you try the attached patch and see whether it works? While your klp-build.patch generates the necessary BTF for the livepatch, it doesn't actually handle the registration of specific struct_ops like klp_bpf_cmdline_ops, does it? Consequently, this struct_ops approach seems to require a hand-written kernel module rather than a patch-generated one, as we can't trigger register_bpf_struct_ops() from a .patch file without modifying scripts/livepatch/init.c. The primary motivation for staying with the .patch workflow is the scope: a standard kernel module is restricted to exported symbols, whereas a patch-generated module grants us access to non-exported functions. Am I missing any alternative workarounds? -- Regards Yafang ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH bpf-next] selftests/bpf: Add BPF struct_ops + livepatch integration test 2026-04-14 6:55 ` Yafang Shao @ 2026-04-14 22:17 ` Song Liu 2026-04-16 7:20 ` Yafang Shao 0 siblings, 1 reply; 10+ messages in thread From: Song Liu @ 2026-04-14 22:17 UTC (permalink / raw) To: Yafang Shao Cc: bpf, ast, daniel, andrii, martin.lau, eddyz87, memxor, yonghong.song, jolsa, kernel-team [-- Attachment #1: Type: text/plain, Size: 2194 bytes --] On Mon, Apr 13, 2026 at 11:56 PM Yafang Shao <laoar.shao@gmail.com> wrote: > > On Tue, Apr 14, 2026 at 5:42 AM Song Liu <song@kernel.org> wrote: > > > > On Sun, Apr 12, 2026 at 1:44 AM Yafang Shao <laoar.shao@gmail.com> wrote: > > [...] > > > > + > > > > +/* --- Module init/exit --- */ > > > > + > > > > +static int __init test_klp_bpf_init(void) > > > > +{ > > > > + int ret; > > > > + > > > > + ret = register_btf_kfunc_id_set(BPF_PROG_TYPE_STRUCT_OPS, > > > > + &klp_bpf_kfunc_set); > > > > + ret = ret ?: register_bpf_struct_ops(&bpf_klp_bpf_cmdline_ops, > > > > + klp_bpf_cmdline_ops); > > > > > > Is it possible to integrate this BTF registration directly into > > > klp-build? It appears we might need to extend scripts/livepatch/init.c > > > to provide the necessary support. > > > > Can you try the attached patch and see whether it works? > > While your klp-build.patch generates the necessary BTF for the > livepatch, it doesn't actually handle the registration of specific > struct_ops like klp_bpf_cmdline_ops, does it? > > Consequently, this struct_ops approach seems to require a hand-written > kernel module rather than a patch-generated one, as we can't trigger > register_bpf_struct_ops() from a .patch file without modifying > scripts/livepatch/init.c. > > The primary motivation for staying with the .patch workflow is the > scope: a standard kernel module is restricted to exported symbols, > whereas a patch-generated module grants us access to non-exported > functions. Am I missing any alternative workarounds? There are other ways to access non-exported symbols. :) But I agree that binary diff based solutions (klp-build, kpatch-build) have their advantages. 0001-objtool-klp-Build-proper-BTF-for-the-livepatch-modul.patch (attached) seems to work for this. It is not very clean though. I tested it with 0001-test-klp-build-btf.patch (also attached) as: ./scripts/livepatch/klp-build -e scripts/livepatch/test_klp_bpf_ops.c 0001-test-klp-build-btf.patch Does this work for your use cases? Thanks, Song [-- Attachment #2: 0001-objtool-klp-Build-proper-BTF-for-the-livepatch-modul.patch --] [-- Type: application/octet-stream, Size: 7630 bytes --] From bad2de891014de41cc11646501519d01fff20074 Mon Sep 17 00:00:00 2001 From: Song Liu <song@kernel.org> Date: Mon, 13 Apr 2026 14:53:56 -0700 Subject: [PATCH] objtool/klp: Build proper BTF for the livepatch module Signed-off-by: Song Liu <song@kernel.org> --- scripts/livepatch/init.c | 16 +++++++ scripts/livepatch/klp-build | 87 +++++++++++++++++++++++++++++++++---- 2 files changed, 95 insertions(+), 8 deletions(-) diff --git a/scripts/livepatch/init.c b/scripts/livepatch/init.c index f14d8c8fb35f..2fb07fc86dd4 100644 --- a/scripts/livepatch/init.c +++ b/scripts/livepatch/init.c @@ -6,9 +6,18 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/kernel.h> +#include <linux/module.h> #include <linux/slab.h> #include <linux/livepatch.h> +/* + * Optional module init hook for extra source files (--extra-mod). + * Override this to register kfuncs, struct_ops, etc. The 'mod' argument + * is the livepatch module (THIS_MODULE from init.c). + */ +extern int __klp_mod_init(struct module *mod); +int __weak __klp_mod_init(struct module *mod) { return 0; } + static struct klp_patch *patch; static int __init livepatch_mod_init(void) @@ -78,8 +87,15 @@ static int __init livepatch_mod_init(void) patch->replace = true; #endif + ret = __klp_mod_init(THIS_MODULE); + if (ret) + goto err_free_funcs; + return klp_enable_patch(patch); +err_free_funcs: + klp_for_each_object_static(patch, objs) + kfree(objs->funcs); err_free_objs: kfree(objs); err_free_patch: diff --git a/scripts/livepatch/klp-build b/scripts/livepatch/klp-build index 7b82c7503c2b..aa6464b44475 100755 --- a/scripts/livepatch/klp-build +++ b/scripts/livepatch/klp-build @@ -22,6 +22,7 @@ shopt -s lastpipe unset DEBUG_CLONE DIFF_CHECKSUM SKIP_CLEANUP XTRACE +declare -a EXTRA_MOD_SRCS REPLACE=1 SHORT_CIRCUIT=0 JOBS="$(getconf _NPROCESSORS_ONLN)" @@ -119,6 +120,7 @@ Options: -o, --output=<file.ko> Output file [default: livepatch-<patch-name>.ko] --no-replace Disable livepatch atomic replace -v, --verbose Pass V=1 to kernel/module builds + -e, --extra-mod=<file.c> Extra source file compiled into the module Advanced Options: -d, --debug Show symbol/reloc cloning decisions @@ -142,8 +144,8 @@ process_args() { local long local args - short="hfj:o:vdS:T" - long="help,show-first-changed,jobs:,output:,no-replace,verbose,debug,short-circuit:,keep-tmp" + short="hfj:o:ve:dS:T" + long="help,show-first-changed,jobs:,output:,no-replace,verbose,extra-mod:,debug,short-circuit:,keep-tmp" args=$(getopt --options "$short" --longoptions "$long" -- "$@") || { echo; usage; exit @@ -180,6 +182,10 @@ process_args() { VERBOSE="V=1" shift ;; + -e | --extra-mod) + EXTRA_MOD_SRCS+=("$SRC/$2") + shift 2 + ;; -d | --debug) DEBUG_CLONE=1 keep_tmp=1 @@ -301,6 +307,7 @@ get_patch_files() { grep0 -E '^(--- |\+\+\+ )' "$patch" \ | gawk '{print $2}' \ | sed 's|^[^/]*/||' \ + | grep -v '^dev/null$' \ | sort -u } @@ -315,7 +322,8 @@ git_refresh() { ( cd "$SRC" - git update-index -q --refresh -- "${files[@]}" + # Filter out files that don't exist (e.g. new files removed by reverse) + git update-index -q --refresh -- "${files[@]}" 2>/dev/null || true ) } @@ -434,12 +442,20 @@ refresh_patch() { # Get all source files affected by the patch get_patch_files "$patch" | mapfile -t files - # Copy orig source files to 'a' - ( cd "$SRC" && echo "${files[@]}" | xargs cp --parents --target-directory="$tmpdir/a" ) + # Copy orig source files to 'a' (skip files that don't exist yet) + for file in "${files[@]}"; do + [[ -f "$SRC/$file" ]] || continue + mkdir -p "$tmpdir/a/$(dirname "$file")" + cp -f "$SRC/$file" "$tmpdir/a/$file" + done # Copy patched source files to 'b' apply_patch "$patch" --recount - ( cd "$SRC" && echo "${files[@]}" | xargs cp --parents --target-directory="$tmpdir/b" ) + for file in "${files[@]}"; do + [[ -f "$SRC/$file" ]] || continue + mkdir -p "$tmpdir/b/$(dirname "$file")" + cp -f "$SRC/$file" "$tmpdir/b/$file" + done revert_patch "$patch" --recount # Diff 'a' and 'b' to make a clean patch @@ -566,6 +582,11 @@ copy_orig_objects() { done xtrace_restore + # Save vmlinux for BTF base reference when generating module BTF + if [[ -v CONFIG_DEBUG_INFO_BTF_MODULES ]] && [[ -f "$OBJ/vmlinux" ]]; then + cp -f "$OBJ/vmlinux" "$ORIG_DIR/vmlinux" + fi + mv -f "$TMP_DIR/build.log" "$ORIG_DIR" touch "$TIMESTAMP" } @@ -715,6 +736,36 @@ diff_checksums() { done } +# Regenerate BTF for the livepatch module +gen_module_btf() { + local kmod_file="$1" + + # Use the original (pre-patch) vmlinux as BTF base, since the module + # will be loaded on a kernel running that vmlinux. The patched vmlinux + # (currently at $OBJ/vmlinux) has different BTF string offsets. + local btf_base="$ORIG_DIR/vmlinux" + + [[ ! -f "$btf_base" ]] && { warn "original vmlinux not found, skipping BTF"; return; } + + # gen-btf.sh is a subprocess and needs these variables exported. + # Query tool paths and flags from kbuild rather than hardcoding + # them, since they vary with LLVM= and CROSS_COMPILE=. + local pahole objcopy pahole_flags + pahole="$(cd "$SRC" && make -s --no-print-directory \ + --eval='print-var: ; @echo $(PAHOLE)' print-var 2>/dev/null)" + objcopy="$(cd "$SRC" && make -s --no-print-directory \ + --eval='print-var: ; @echo $(OBJCOPY)' print-var 2>/dev/null)" + pahole_flags="$(cd "$SRC" && make -s --no-print-directory \ + --eval='print-var: ; @echo $(PAHOLE_FLAGS)' print-var 2>/dev/null)" + + PAHOLE="$pahole" PAHOLE_FLAGS="$pahole_flags" OBJCOPY="$objcopy" \ + RESOLVE_BTFIDS="$OBJ/tools/bpf/resolve_btfids/resolve_btfids" \ + RESOLVE_BTFIDS_FLAGS="--distill_base" \ + objtree="$OBJ" KBUILD_VERBOSE="" \ + "$SRC/scripts/gen-btf.sh" --btf_base "$btf_base" "$kmod_file" \ + || die "BTF generation failed" +} + # Build and post-process livepatch module in $KMOD_DIR build_patch_module() { local makefile="$KMOD_DIR/Kbuild" @@ -755,6 +806,13 @@ build_patch_module() { echo -n " $rel_file" >> "$makefile" done + # Copy extra .c files into the kmod directory + for src in "${EXTRA_MOD_SRCS[@]}"; do + local base="$(basename "$src")" + cp -f "$TMP_DIR/$base" "$KMOD_DIR/$base" + echo -n " ${base%.c}.o" >> "$makefile" + done + echo >> "$makefile" cflags=("-ffunction-sections") @@ -781,12 +839,21 @@ build_patch_module() { # Save off the intermediate binary for debugging cp -f "$kmod_file" "$kmod_file.orig" - # Work around issue where slight .config change makes corrupt BTF - objcopy --remove-section=.BTF "$kmod_file" + # Remove BTF sections from the kbuild M= build. They were generated + # against the patched vmlinux and will be regenerated below against + # the original vmlinux. Keep .BTF_ids as it contains runtime data. + objcopy --remove-section=.BTF \ + --remove-section=.BTF.base \ + "$kmod_file" # Fix (and work around) linker wreckage for klp syms / relocs "$SRC/tools/objtool/objtool" klp post-link "$kmod_file" || die "objtool klp post-link failed" + # Regenerate BTF after post-link + if [[ -v CONFIG_DEBUG_INFO_BTF_MODULES ]]; then + gen_module_btf "$kmod_file" + fi + cp -f "$kmod_file" "$OUTFILE" } @@ -810,6 +877,10 @@ if (( SHORT_CIRCUIT <= 2 )); then status "Fixing patch(es)" fix_patches apply_patches + # Save extra-mod files before revert_patches deletes them + for src in "${EXTRA_MOD_SRCS[@]}"; do + [[ -f "$src" ]] && cp -f "$src" "$TMP_DIR/$(basename "$src")" + done status "Building patched kernel" build_kernel revert_patches -- 2.52.0 [-- Attachment #3: 0001-test-klp-build-btf.patch --] [-- Type: application/octet-stream, Size: 4534 bytes --] From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Song Liu <song@kernel.org> Date: Mon, 14 Apr 2026 00:00:00 -0700 Subject: [PATCH] test-klp-bpf Livepatch cmdline_proc_show to delegate to BPF struct_ops. Use with: klp-build -e scripts/livepatch/test_klp_bpf_ops.c --- diff --git a/fs/proc/cmdline.c b/fs/proc/cmdline.c index a6f76121955f..c672ead00ff4 100644 --- a/fs/proc/cmdline.c +++ b/fs/proc/cmdline.c @@ -5,10 +5,20 @@ #include <linux/seq_file.h> #include "internal.h" +struct klp_bpf_cmdline_ops { + int (*set_cmdline)(struct seq_file *m); +}; + +struct klp_bpf_cmdline_ops *active_ops; + static int cmdline_proc_show(struct seq_file *m, void *v) { - seq_puts(m, saved_command_line); - seq_putc(m, '\n'); + struct klp_bpf_cmdline_ops *ops = READ_ONCE(active_ops); + + if (ops && ops->set_cmdline) + return ops->set_cmdline(m); + + seq_puts(m, "klp_bpf: no struct_ops attached\n"); return 0; } diff --git b/scripts/livepatch/test_klp_bpf_ops.c b/scripts/livepatch/test_klp_bpf_ops.c new file mode 100644 index 000000000000..b8ae4bad5181 --- /dev/null +++ b/scripts/livepatch/test_klp_bpf_ops.c @@ -0,0 +1,129 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2026 Meta Platforms, Inc. and affiliates. + * + * BPF struct_ops + kfunc infrastructure for klp-build livepatch test. + * Compiled into the livepatch module via --extra-mod so that: + * 1. pahole generates BTF from DWARF for kfunc and struct_ops types + * 2. __klp_mod_init receives THIS_MODULE from init.c + */ + +#include <linux/bpf.h> +#include <linux/btf.h> +#include <linux/btf_ids.h> +#include <linux/bpf_verifier.h> +#include <linux/module.h> +#include <linux/seq_file.h> + +/* --- struct_ops type definition --- */ + +struct klp_bpf_cmdline_ops { + int (*set_cmdline)(struct seq_file *m); +}; + +/* Defined in the diff object (patched cmdline.c) */ +extern struct klp_bpf_cmdline_ops *active_ops; + +/* --- kfunc --- */ + +__bpf_kfunc_start_defs(); + +__bpf_kfunc void bpf_klp_seq_write(struct seq_file *m, + const char *data, u32 data__sz) +{ + seq_write(m, data, data__sz); +} + +__bpf_kfunc_end_defs(); + +BTF_KFUNCS_START(klp_bpf_kfunc_ids) +BTF_ID_FLAGS(func, bpf_klp_seq_write) +BTF_KFUNCS_END(klp_bpf_kfunc_ids) + +static struct btf_kfunc_id_set klp_bpf_kfunc_set = { + .set = &klp_bpf_kfunc_ids, +}; + +/* --- struct_ops --- */ + +static int klp_bpf_cmdline_reg(void *kdata, struct bpf_link *link) +{ + struct klp_bpf_cmdline_ops *ops = kdata; + + if (cmpxchg(&active_ops, NULL, ops)) + return -EBUSY; + + return 0; +} + +static void klp_bpf_cmdline_unreg(void *kdata, struct bpf_link *link) +{ + WRITE_ONCE(active_ops, NULL); +} + +static int klp_bpf_cmdline_init(struct btf *btf) +{ + return 0; +} + +static int klp_bpf_cmdline_init_member(const struct btf_type *t, + const struct btf_member *member, + void *kdata, const void *udata) +{ + return 0; +} + +static bool klp_bpf_cmdline_is_valid_access(int off, int size, + enum bpf_access_type type, + const struct bpf_prog *prog, + struct bpf_insn_access_aux *info) +{ + return bpf_tracing_btf_ctx_access(off, size, type, prog, info); +} + +static int klp_bpf_cmdline_btf_struct_access(struct bpf_verifier_log *log, + const struct bpf_reg_state *reg, + int off, int size) +{ + return -EACCES; +} + +static const struct bpf_verifier_ops klp_bpf_cmdline_verifier_ops = { + .is_valid_access = klp_bpf_cmdline_is_valid_access, + .btf_struct_access = klp_bpf_cmdline_btf_struct_access, +}; + +static int klp_bpf_cmdline__set_cmdline(struct seq_file *m) +{ + return 0; +} + +static struct klp_bpf_cmdline_ops __bpf_klp_bpf_cmdline_ops = { + .set_cmdline = klp_bpf_cmdline__set_cmdline, +}; + +static struct bpf_struct_ops bpf_klp_bpf_cmdline_ops = { + .verifier_ops = &klp_bpf_cmdline_verifier_ops, + .init = klp_bpf_cmdline_init, + .init_member = klp_bpf_cmdline_init_member, + .reg = klp_bpf_cmdline_reg, + .unreg = klp_bpf_cmdline_unreg, + .cfi_stubs = &__bpf_klp_bpf_cmdline_ops, + .name = "klp_bpf_cmdline_ops", +}; + +/* --- Module init hook (called from init.c with THIS_MODULE) --- */ + +extern int __klp_mod_init(struct module *mod); +int __klp_mod_init(struct module *mod) +{ + int ret; + + klp_bpf_kfunc_set.owner = mod; + bpf_klp_bpf_cmdline_ops.owner = mod; + + ret = register_btf_kfunc_id_set(BPF_PROG_TYPE_STRUCT_OPS, + &klp_bpf_kfunc_set); + ret = ret ?: register_bpf_struct_ops(&bpf_klp_bpf_cmdline_ops, + klp_bpf_cmdline_ops); + return ret; +} -- 2.52.0 ^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH bpf-next] selftests/bpf: Add BPF struct_ops + livepatch integration test 2026-04-14 22:17 ` Song Liu @ 2026-04-16 7:20 ` Yafang Shao 0 siblings, 0 replies; 10+ messages in thread From: Yafang Shao @ 2026-04-16 7:20 UTC (permalink / raw) To: Song Liu Cc: bpf, ast, daniel, andrii, martin.lau, eddyz87, memxor, yonghong.song, jolsa, kernel-team On Wed, Apr 15, 2026 at 6:17 AM Song Liu <song@kernel.org> wrote: > > On Mon, Apr 13, 2026 at 11:56 PM Yafang Shao <laoar.shao@gmail.com> wrote: > > > > On Tue, Apr 14, 2026 at 5:42 AM Song Liu <song@kernel.org> wrote: > > > > > > On Sun, Apr 12, 2026 at 1:44 AM Yafang Shao <laoar.shao@gmail.com> wrote: > > > [...] > > > > > + > > > > > +/* --- Module init/exit --- */ > > > > > + > > > > > +static int __init test_klp_bpf_init(void) > > > > > +{ > > > > > + int ret; > > > > > + > > > > > + ret = register_btf_kfunc_id_set(BPF_PROG_TYPE_STRUCT_OPS, > > > > > + &klp_bpf_kfunc_set); > > > > > + ret = ret ?: register_bpf_struct_ops(&bpf_klp_bpf_cmdline_ops, > > > > > + klp_bpf_cmdline_ops); > > > > > > > > Is it possible to integrate this BTF registration directly into > > > > klp-build? It appears we might need to extend scripts/livepatch/init.c > > > > to provide the necessary support. > > > > > > Can you try the attached patch and see whether it works? > > > > While your klp-build.patch generates the necessary BTF for the > > livepatch, it doesn't actually handle the registration of specific > > struct_ops like klp_bpf_cmdline_ops, does it? > > > > Consequently, this struct_ops approach seems to require a hand-written > > kernel module rather than a patch-generated one, as we can't trigger > > register_bpf_struct_ops() from a .patch file without modifying > > scripts/livepatch/init.c. > > > > The primary motivation for staying with the .patch workflow is the > > scope: a standard kernel module is restricted to exported symbols, > > whereas a patch-generated module grants us access to non-exported > > functions. Am I missing any alternative workarounds? > > There are other ways to access non-exported symbols. :) But I agree > that binary diff based solutions (klp-build, kpatch-build) have their > advantages. > > 0001-objtool-klp-Build-proper-BTF-for-the-livepatch-modul.patch > (attached) seems to work for this. It is not very clean though. > > I tested it with 0001-test-klp-build-btf.patch (also attached) as: > > ./scripts/livepatch/klp-build -e scripts/livepatch/test_klp_bpf_ops.c > 0001-test-klp-build-btf.patch I tested the case you provided, and it performed as expected. > > Does this work for your use cases? I haven't tested this with my specific use case yet, but I expect it will work as intended. I’ll set aside some time to verify it shortly. Could you please submit an official patch? -- Regards Yafang ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH bpf-next] selftests/bpf: Add BPF struct_ops + livepatch integration test 2026-04-08 17:52 [PATCH bpf-next] selftests/bpf: Add BPF struct_ops + livepatch integration test Song Liu 2026-04-12 8:43 ` Yafang Shao @ 2026-04-12 21:02 ` Alexei Starovoitov 2026-04-13 21:43 ` Song Liu 1 sibling, 1 reply; 10+ messages in thread From: Alexei Starovoitov @ 2026-04-12 21:02 UTC (permalink / raw) To: Song Liu Cc: bpf, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko, Martin KaFai Lau, Eduard, Kumar Kartikeya Dwivedi, Yonghong Song, Jiri Olsa, Kernel Team, Yafang Shao On Wed, Apr 8, 2026 at 10:52 AM Song Liu <song@kernel.org> wrote: > > Add a selftest that demonstrates BPF struct_ops controlling kernel > behavior through livepatch. A kernel module (test_klp_bpf) livepatches > cmdline_proc_show() and delegates output to a BPF struct_ops callback. > The BPF program writes a custom string to /proc/cmdline via the > bpf_klp_seq_write kfunc. > > Components: > - test_kmods/test_klp_bpf.c: kernel module that registers a > klp_bpf_cmdline_ops struct_ops type, livepatches cmdline_proc_show, > and provides bpf_klp_seq_write kfunc for seq_file writes > - progs/test_klp_bpf.c: BPF struct_ops program implementing > set_cmdline callback > - prog_tests/test_klp_bpf.c: userspace test verifying /proc/cmdline > output with and without BPF struct_ops attached > > Assisted-by: Claude:claude-opus-4-6 > Signed-off-by: Song Liu <song@kernel.org> > > --- > > This shows an alternative solution to the idea proposed in [1]. This > approach doesn't need any kernel change. > > [1] https://lore.kernel.org/bpf/20260402092607.96430-1-laoar.shao@gmail.com/ > --- > tools/testing/selftests/bpf/Makefile | 2 +- > .../selftests/bpf/prog_tests/test_klp_bpf.c | 109 ++++++++++++ > .../selftests/bpf/progs/test_klp_bpf.c | 26 +++ > .../testing/selftests/bpf/test_kmods/Makefile | 3 +- > .../selftests/bpf/test_kmods/test_klp_bpf.c | 166 ++++++++++++++++++ > .../selftests/bpf/test_kmods/test_klp_bpf.h | 12 ++ > 6 files changed, 316 insertions(+), 2 deletions(-) It looks good, but takes 1.6 seconds on a non-debug kernel. This example can stay out of the tree. ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH bpf-next] selftests/bpf: Add BPF struct_ops + livepatch integration test 2026-04-12 21:02 ` Alexei Starovoitov @ 2026-04-13 21:43 ` Song Liu 2026-04-14 6:59 ` Yafang Shao 0 siblings, 1 reply; 10+ messages in thread From: Song Liu @ 2026-04-13 21:43 UTC (permalink / raw) To: Alexei Starovoitov Cc: bpf, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko, Martin KaFai Lau, Eduard, Kumar Kartikeya Dwivedi, Yonghong Song, Jiri Olsa, Kernel Team, Yafang Shao On Sun, Apr 12, 2026 at 2:02 PM Alexei Starovoitov <alexei.starovoitov@gmail.com> wrote: [...] > > > > This shows an alternative solution to the idea proposed in [1]. This > > approach doesn't need any kernel change. > > > > [1] https://lore.kernel.org/bpf/20260402092607.96430-1-laoar.shao@gmail.com/ > > --- > > tools/testing/selftests/bpf/Makefile | 2 +- > > .../selftests/bpf/prog_tests/test_klp_bpf.c | 109 ++++++++++++ > > .../selftests/bpf/progs/test_klp_bpf.c | 26 +++ > > .../testing/selftests/bpf/test_kmods/Makefile | 3 +- > > .../selftests/bpf/test_kmods/test_klp_bpf.c | 166 ++++++++++++++++++ > > .../selftests/bpf/test_kmods/test_klp_bpf.h | 12 ++ > > 6 files changed, 316 insertions(+), 2 deletions(-) > > It looks good, but takes 1.6 seconds on a non-debug kernel. > This example can stay out of the tree. Sure. This is not a typical self test to begin with. Thanks, Song ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH bpf-next] selftests/bpf: Add BPF struct_ops + livepatch integration test 2026-04-13 21:43 ` Song Liu @ 2026-04-14 6:59 ` Yafang Shao 2026-04-14 22:33 ` Song Liu 0 siblings, 1 reply; 10+ messages in thread From: Yafang Shao @ 2026-04-14 6:59 UTC (permalink / raw) To: Song Liu Cc: Alexei Starovoitov, bpf, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko, Martin KaFai Lau, Eduard, Kumar Kartikeya Dwivedi, Yonghong Song, Jiri Olsa, Kernel Team On Tue, Apr 14, 2026 at 5:43 AM Song Liu <song@kernel.org> wrote: > > On Sun, Apr 12, 2026 at 2:02 PM Alexei Starovoitov > <alexei.starovoitov@gmail.com> wrote: > [...] > > > > > > This shows an alternative solution to the idea proposed in [1]. This > > > approach doesn't need any kernel change. > > > > > > [1] https://lore.kernel.org/bpf/20260402092607.96430-1-laoar.shao@gmail.com/ > > > --- > > > tools/testing/selftests/bpf/Makefile | 2 +- > > > .../selftests/bpf/prog_tests/test_klp_bpf.c | 109 ++++++++++++ > > > .../selftests/bpf/progs/test_klp_bpf.c | 26 +++ > > > .../testing/selftests/bpf/test_kmods/Makefile | 3 +- > > > .../selftests/bpf/test_kmods/test_klp_bpf.c | 166 ++++++++++++++++++ > > > .../selftests/bpf/test_kmods/test_klp_bpf.h | 12 ++ > > > 6 files changed, 316 insertions(+), 2 deletions(-) > > > > It looks good, but takes 1.6 seconds on a non-debug kernel. > > This example can stay out of the tree. > > Sure. This is not a typical self test to begin with. How about adding this test case to tools/testing/selftests/livepatch/test_modules/? It would serve as an excellent demonstration of how livepatching can be leveraged for more creative kernel extensions. -- Regards Yafang ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH bpf-next] selftests/bpf: Add BPF struct_ops + livepatch integration test 2026-04-14 6:59 ` Yafang Shao @ 2026-04-14 22:33 ` Song Liu 0 siblings, 0 replies; 10+ messages in thread From: Song Liu @ 2026-04-14 22:33 UTC (permalink / raw) To: Yafang Shao Cc: Alexei Starovoitov, bpf, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko, Martin KaFai Lau, Eduard, Kumar Kartikeya Dwivedi, Yonghong Song, Jiri Olsa, Kernel Team On Tue, Apr 14, 2026 at 12:00 AM Yafang Shao <laoar.shao@gmail.com> wrote: > > On Tue, Apr 14, 2026 at 5:43 AM Song Liu <song@kernel.org> wrote: > > > > On Sun, Apr 12, 2026 at 2:02 PM Alexei Starovoitov > > <alexei.starovoitov@gmail.com> wrote: > > [...] > > > > > > > > This shows an alternative solution to the idea proposed in [1]. This > > > > approach doesn't need any kernel change. > > > > > > > > [1] https://lore.kernel.org/bpf/20260402092607.96430-1-laoar.shao@gmail.com/ > > > > --- > > > > tools/testing/selftests/bpf/Makefile | 2 +- > > > > .../selftests/bpf/prog_tests/test_klp_bpf.c | 109 ++++++++++++ > > > > .../selftests/bpf/progs/test_klp_bpf.c | 26 +++ > > > > .../testing/selftests/bpf/test_kmods/Makefile | 3 +- > > > > .../selftests/bpf/test_kmods/test_klp_bpf.c | 166 ++++++++++++++++++ > > > > .../selftests/bpf/test_kmods/test_klp_bpf.h | 12 ++ > > > > 6 files changed, 316 insertions(+), 2 deletions(-) > > > > > > It looks good, but takes 1.6 seconds on a non-debug kernel. > > > This example can stay out of the tree. > > > > Sure. This is not a typical self test to begin with. > > How about adding this test case to > tools/testing/selftests/livepatch/test_modules/? It would serve as an > excellent demonstration of how livepatching can be leveraged for more > creative kernel extensions. I don't know whether we want BPF heavy code in selftests/livepatch/. Maybe we can just add the livepatch module to samples/livepatch/. Thanks, Song ^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2026-04-16 7:21 UTC | newest] Thread overview: 10+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-04-08 17:52 [PATCH bpf-next] selftests/bpf: Add BPF struct_ops + livepatch integration test Song Liu 2026-04-12 8:43 ` Yafang Shao 2026-04-13 21:41 ` Song Liu 2026-04-14 6:55 ` Yafang Shao 2026-04-14 22:17 ` Song Liu 2026-04-16 7:20 ` Yafang Shao 2026-04-12 21:02 ` Alexei Starovoitov 2026-04-13 21:43 ` Song Liu 2026-04-14 6:59 ` Yafang Shao 2026-04-14 22:33 ` Song Liu
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.