Loading tools/testing/selftests/livepatch/test-livepatch.sh +100 −0 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 tools/testing/selftests/livepatch/test_modules/Makefile +2 −0 Original line number Diff line number Diff line Loading @@ -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 \ Loading tools/testing/selftests/livepatch/test_modules/test_klp_mod_patch.c 0 → 100644 +53 −0 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0 // Copyright (C) 2026 Pablo Hugen <phugen@redhat.com> #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 <phugen@redhat.com>"); MODULE_DESCRIPTION("Livepatch test: patch for module-provided function"); tools/testing/selftests/livepatch/test_modules/test_klp_mod_target.c 0 → 100644 +39 −0 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0 // Copyright (C) 2026 Pablo Hugen <phugen@redhat.com> #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 <phugen@redhat.com>"); MODULE_DESCRIPTION("Livepatch test: target module with proc entry"); Loading
tools/testing/selftests/livepatch/test-livepatch.sh +100 −0 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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
tools/testing/selftests/livepatch/test_modules/Makefile +2 −0 Original line number Diff line number Diff line Loading @@ -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 \ Loading
tools/testing/selftests/livepatch/test_modules/test_klp_mod_patch.c 0 → 100644 +53 −0 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0 // Copyright (C) 2026 Pablo Hugen <phugen@redhat.com> #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 <phugen@redhat.com>"); MODULE_DESCRIPTION("Livepatch test: patch for module-provided function");
tools/testing/selftests/livepatch/test_modules/test_klp_mod_target.c 0 → 100644 +39 −0 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0 // Copyright (C) 2026 Pablo Hugen <phugen@redhat.com> #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 <phugen@redhat.com>"); MODULE_DESCRIPTION("Livepatch test: target module with proc entry");