diff options
Diffstat (limited to 'tools/testing/selftests/livepatch')
6 files changed, 235 insertions, 1 deletions
diff --git a/tools/testing/selftests/livepatch/functions.sh b/tools/testing/selftests/livepatch/functions.sh index 46991a029f7c..8ec0cb64ad94 100644 --- a/tools/testing/selftests/livepatch/functions.sh +++ b/tools/testing/selftests/livepatch/functions.sh @@ -10,7 +10,11 @@ SYSFS_KERNEL_DIR="/sys/kernel" SYSFS_KLP_DIR="$SYSFS_KERNEL_DIR/livepatch" SYSFS_DEBUG_DIR="$SYSFS_KERNEL_DIR/debug" SYSFS_KPROBES_DIR="$SYSFS_DEBUG_DIR/kprobes" -SYSFS_TRACING_DIR="$SYSFS_DEBUG_DIR/tracing" +if [[ -e /sys/kernel/tracing/trace ]]; then + SYSFS_TRACING_DIR="$SYSFS_KERNEL_DIR/tracing" +else + SYSFS_TRACING_DIR="$SYSFS_DEBUG_DIR/tracing" +fi # Kselftest framework requirement - SKIP code is 4 ksft_skip=4 diff --git a/tools/testing/selftests/livepatch/test-ftrace.sh b/tools/testing/selftests/livepatch/test-ftrace.sh index 094176f1a46a..d2c3dea63104 100755 --- a/tools/testing/selftests/livepatch/test-ftrace.sh +++ b/tools/testing/selftests/livepatch/test-ftrace.sh @@ -95,4 +95,40 @@ livepatch: '$MOD_LIVEPATCH': completing unpatching transition livepatch: '$MOD_LIVEPATCH': unpatching complete % rmmod $MOD_LIVEPATCH" + +# - trace a function +# - verify livepatch can load targgeting on the same traced function +# - check if the livepatch is in effect +# - reset trace and unload livepatch + +start_test "livepatch a traced function and check that the live patch remains in effect" + +FUNCTION_NAME="cmdline_proc_show" + +trace_function "$FUNCTION_NAME" +load_lp $MOD_LIVEPATCH + +if [[ "$(cat /proc/cmdline)" == "$MOD_LIVEPATCH: this has been live patched" ]] ; then + log "livepatch: ok" +fi + +check_traced_functions "$FUNCTION_NAME" + +disable_lp $MOD_LIVEPATCH +unload_lp $MOD_LIVEPATCH + +check_result "% insmod test_modules/$MOD_LIVEPATCH.ko +livepatch: enabling patch '$MOD_LIVEPATCH' +livepatch: '$MOD_LIVEPATCH': initializing patching transition +livepatch: '$MOD_LIVEPATCH': starting patching transition +livepatch: '$MOD_LIVEPATCH': completing patching transition +livepatch: '$MOD_LIVEPATCH': patching complete +livepatch: ok +% echo 0 > $SYSFS_KLP_DIR/$MOD_LIVEPATCH/enabled +livepatch: '$MOD_LIVEPATCH': initializing unpatching transition +livepatch: '$MOD_LIVEPATCH': starting unpatching transition +livepatch: '$MOD_LIVEPATCH': completing unpatching transition +livepatch: '$MOD_LIVEPATCH': unpatching complete +% rmmod $MOD_LIVEPATCH" + exit 0 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 <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"); 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 <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"); |
