From: Pablo Alessandro Santos Hugen <[email protected]>

Add a target module and livepatch pair that verify module function
patching via a proc entry. Two test cases cover both the
klp_enable_patch path (target loaded before livepatch) and the
klp_module_coming path (livepatch loaded before target).

Signed-off-by: Pablo Alessandro Santos Hugen <[email protected]>
---
 .../selftests/livepatch/test-livepatch.sh     | 100 ++++++++++++++++++
 .../selftests/livepatch/test_modules/Makefile |   2 +
 .../test_modules/test_klp_mod_patch.c         |  53 ++++++++++
 .../test_modules/test_klp_mod_target.c        |  39 +++++++
 4 files changed, 194 insertions(+)
 create mode 100644 
tools/testing/selftests/livepatch/test_modules/test_klp_mod_patch.c
 create mode 100644 
tools/testing/selftests/livepatch/test_modules/test_klp_mod_target.c

diff --git a/tools/testing/selftests/livepatch/test-livepatch.sh 
b/tools/testing/selftests/livepatch/test-livepatch.sh
index 6673023d2b66..c44c5341a2f1 100755
--- a/tools/testing/selftests/livepatch/test-livepatch.sh
+++ b/tools/testing/selftests/livepatch/test-livepatch.sh
@@ -8,6 +8,8 @@ MOD_LIVEPATCH1=test_klp_livepatch
 MOD_LIVEPATCH2=test_klp_syscall
 MOD_LIVEPATCH3=test_klp_callbacks_demo
 MOD_REPLACE=test_klp_atomic_replace
+MOD_TARGET=test_klp_mod_target
+MOD_TARGET_PATCH=test_klp_mod_patch
 
 setup_config
 
@@ -196,4 +198,102 @@ livepatch: '$MOD_REPLACE': unpatching complete
 % rmmod $MOD_REPLACE"
 
 
+# - load a target module that provides /proc/test_klp_mod_target with
+#   original output
+# - load a livepatch that patches the target module's show function
+# - verify the proc entry returns livepatched output
+# - disable and unload the livepatch
+# - verify the proc entry returns original output again
+# - unload the target module
+
+start_test "module function patching"
+
+load_mod $MOD_TARGET
+
+if [[ "$(cat /proc/$MOD_TARGET)" != "$MOD_TARGET: original output" ]] ; then
+       echo -e "FAIL\n\n"
+       die "livepatch kselftest(s) failed"
+fi
+
+load_lp $MOD_TARGET_PATCH
+
+if [[ "$(cat /proc/$MOD_TARGET)" != "$MOD_TARGET_PATCH: this has been live 
patched" ]] ; then
+       echo -e "FAIL\n\n"
+       die "livepatch kselftest(s) failed"
+fi
+
+disable_lp $MOD_TARGET_PATCH
+unload_lp $MOD_TARGET_PATCH
+
+if [[ "$(cat /proc/$MOD_TARGET)" != "$MOD_TARGET: original output" ]] ; then
+       echo -e "FAIL\n\n"
+       die "livepatch kselftest(s) failed"
+fi
+
+unload_mod $MOD_TARGET
+
+check_result "% insmod test_modules/$MOD_TARGET.ko
+$MOD_TARGET: test_klp_mod_target_init
+% insmod test_modules/$MOD_TARGET_PATCH.ko
+livepatch: enabling patch '$MOD_TARGET_PATCH'
+livepatch: '$MOD_TARGET_PATCH': initializing patching transition
+livepatch: '$MOD_TARGET_PATCH': starting patching transition
+livepatch: '$MOD_TARGET_PATCH': completing patching transition
+livepatch: '$MOD_TARGET_PATCH': patching complete
+% echo 0 > $SYSFS_KLP_DIR/$MOD_TARGET_PATCH/enabled
+livepatch: '$MOD_TARGET_PATCH': initializing unpatching transition
+livepatch: '$MOD_TARGET_PATCH': starting unpatching transition
+livepatch: '$MOD_TARGET_PATCH': completing unpatching transition
+livepatch: '$MOD_TARGET_PATCH': unpatching complete
+% rmmod $MOD_TARGET_PATCH
+% rmmod $MOD_TARGET
+$MOD_TARGET: test_klp_mod_target_exit"
+
+
+# - load a livepatch that targets a not-yet-loaded module
+# - load the target module: klp_module_coming patches it immediately
+# - verify the proc entry returns livepatched output
+# - disable and unload the livepatch
+# - verify the proc entry returns original output again
+# - unload the target module
+
+start_test "module function patching (livepatch first)"
+
+load_lp $MOD_TARGET_PATCH
+load_mod $MOD_TARGET
+
+if [[ "$(cat /proc/$MOD_TARGET)" != "$MOD_TARGET_PATCH: this has been live 
patched" ]] ; then
+       echo -e "FAIL\n\n"
+       die "livepatch kselftest(s) failed"
+fi
+
+disable_lp $MOD_TARGET_PATCH
+unload_lp $MOD_TARGET_PATCH
+
+if [[ "$(cat /proc/$MOD_TARGET)" != "$MOD_TARGET: original output" ]] ; then
+       echo -e "FAIL\n\n"
+       die "livepatch kselftest(s) failed"
+fi
+
+unload_mod $MOD_TARGET
+
+check_result "% insmod test_modules/$MOD_TARGET_PATCH.ko
+livepatch: enabling patch '$MOD_TARGET_PATCH'
+livepatch: '$MOD_TARGET_PATCH': initializing patching transition
+livepatch: '$MOD_TARGET_PATCH': starting patching transition
+livepatch: '$MOD_TARGET_PATCH': completing patching transition
+livepatch: '$MOD_TARGET_PATCH': patching complete
+% insmod test_modules/$MOD_TARGET.ko
+livepatch: applying patch '$MOD_TARGET_PATCH' to loading module '$MOD_TARGET'
+$MOD_TARGET: test_klp_mod_target_init
+% echo 0 > $SYSFS_KLP_DIR/$MOD_TARGET_PATCH/enabled
+livepatch: '$MOD_TARGET_PATCH': initializing unpatching transition
+livepatch: '$MOD_TARGET_PATCH': starting unpatching transition
+livepatch: '$MOD_TARGET_PATCH': completing unpatching transition
+livepatch: '$MOD_TARGET_PATCH': unpatching complete
+% rmmod $MOD_TARGET_PATCH
+% rmmod $MOD_TARGET
+$MOD_TARGET: test_klp_mod_target_exit"
+
+
 exit 0
diff --git a/tools/testing/selftests/livepatch/test_modules/Makefile 
b/tools/testing/selftests/livepatch/test_modules/Makefile
index 939230e571f5..a13d398585dc 100644
--- a/tools/testing/selftests/livepatch/test_modules/Makefile
+++ b/tools/testing/selftests/livepatch/test_modules/Makefile
@@ -8,6 +8,8 @@ obj-m += test_klp_atomic_replace.o \
        test_klp_callbacks_mod.o \
        test_klp_kprobe.o \
        test_klp_livepatch.o \
+       test_klp_mod_patch.o \
+       test_klp_mod_target.o \
        test_klp_shadow_vars.o \
        test_klp_state.o \
        test_klp_state2.o \
diff --git 
a/tools/testing/selftests/livepatch/test_modules/test_klp_mod_patch.c 
b/tools/testing/selftests/livepatch/test_modules/test_klp_mod_patch.c
new file mode 100644
index 000000000000..6725b4720365
--- /dev/null
+++ b/tools/testing/selftests/livepatch/test_modules/test_klp_mod_patch.c
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2026 Pablo Hugen <[email protected]>
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/livepatch.h>
+#include <linux/seq_file.h>
+
+static int livepatch_mod_target_show(struct seq_file *m, void *v)
+{
+       seq_printf(m, "%s: %s\n", THIS_MODULE->name,
+                  "this has been live patched");
+       return 0;
+}
+
+static struct klp_func funcs[] = {
+       {
+               .old_name = "test_klp_mod_target_show",
+               .new_func = livepatch_mod_target_show,
+       },
+       {},
+};
+
+static struct klp_object objs[] = {
+       {
+               .name = "test_klp_mod_target",
+               .funcs = funcs,
+       },
+       {},
+};
+
+static struct klp_patch patch = {
+       .mod = THIS_MODULE,
+       .objs = objs,
+};
+
+static int test_klp_mod_patch_init(void)
+{
+       return klp_enable_patch(&patch);
+}
+
+static void test_klp_mod_patch_exit(void)
+{
+}
+
+module_init(test_klp_mod_patch_init);
+module_exit(test_klp_mod_patch_exit);
+MODULE_LICENSE("GPL");
+MODULE_INFO(livepatch, "Y");
+MODULE_AUTHOR("Pablo Hugen <[email protected]>");
+MODULE_DESCRIPTION("Livepatch test: patch for module-provided function");
diff --git 
a/tools/testing/selftests/livepatch/test_modules/test_klp_mod_target.c 
b/tools/testing/selftests/livepatch/test_modules/test_klp_mod_target.c
new file mode 100644
index 000000000000..9643984d2402
--- /dev/null
+++ b/tools/testing/selftests/livepatch/test_modules/test_klp_mod_target.c
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2026 Pablo Hugen <[email protected]>
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+
+static struct proc_dir_entry *pde;
+
+static noinline int test_klp_mod_target_show(struct seq_file *m, void *v)
+{
+       seq_printf(m, "%s: %s\n", THIS_MODULE->name, "original output");
+       return 0;
+}
+
+static int test_klp_mod_target_init(void)
+{
+       pr_info("%s\n", __func__);
+       pde = proc_create_single("test_klp_mod_target", 0, NULL,
+                                test_klp_mod_target_show);
+       if (!pde)
+               return -ENOMEM;
+       return 0;
+}
+
+static void test_klp_mod_target_exit(void)
+{
+       pr_info("%s\n", __func__);
+       proc_remove(pde);
+}
+
+module_init(test_klp_mod_target_init);
+module_exit(test_klp_mod_target_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Pablo Hugen <[email protected]>");
+MODULE_DESCRIPTION("Livepatch test: target module with proc entry");
-- 
2.53.0


Reply via email to