diff options
Diffstat (limited to 'tools/testing/selftests/livepatch')
9 files changed, 479 insertions, 112 deletions
diff --git a/tools/testing/selftests/livepatch/functions.sh b/tools/testing/selftests/livepatch/functions.sh index 15601402dee6..30dc677b2f45 100644 --- a/tools/testing/selftests/livepatch/functions.sh +++ b/tools/testing/selftests/livepatch/functions.sh @@ -4,12 +4,19 @@ # Shell functions for the rest of the scripts. +export LC_ALL=C + MAX_RETRIES=600 RETRY_INTERVAL=".1" # seconds 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" +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 @@ -62,6 +69,9 @@ function push_config() { awk -F'[: ]' '{print "file " $1 " line " $2 " " $4}') FTRACE_ENABLED=$(sysctl --values kernel.ftrace_enabled) KPROBE_ENABLED=$(cat "$SYSFS_KPROBES_DIR/enabled") + TRACING_ON=$(cat "$SYSFS_TRACING_DIR/tracing_on") + CURRENT_TRACER=$(cat "$SYSFS_TRACING_DIR/current_tracer") + FTRACE_FILTER=$(cat "$SYSFS_TRACING_DIR/set_ftrace_filter") } function pop_config() { @@ -74,6 +84,17 @@ function pop_config() { if [[ -n "$KPROBE_ENABLED" ]]; then echo "$KPROBE_ENABLED" > "$SYSFS_KPROBES_DIR/enabled" fi + if [[ -n "$TRACING_ON" ]]; then + echo "$TRACING_ON" > "$SYSFS_TRACING_DIR/tracing_on" + fi + if [[ -n "$CURRENT_TRACER" ]]; then + echo "$CURRENT_TRACER" > "$SYSFS_TRACING_DIR/current_tracer" + fi + if [[ -n "$FTRACE_FILTER" ]]; then + echo "$FTRACE_FILTER" \ + | sed -e "/#### all functions enabled ####/d" \ + > "$SYSFS_TRACING_DIR/set_ftrace_filter" + fi } function set_dynamic_debug() { @@ -320,6 +341,16 @@ function check_result { fi } +# does_sysfs_exist(modname, attr) - check sysfs attribute existence +# modname - livepatch module creating the sysfs interface +# attr - attribute name to be checked +function does_sysfs_exist() { + local mod="$1"; shift + local attr="$1"; shift + + [[ -f "$SYSFS_KLP_DIR/$mod/$attr" ]] +} + # check_sysfs_rights(modname, rel_path, expected_rights) - check sysfs # path permissions # modname - livepatch module creating the sysfs interface @@ -352,3 +383,37 @@ function check_sysfs_value() { die "Unexpected value in $path: $expected_value vs. $value" fi } + +# cleanup_tracing() - stop and clean up function tracing +function cleanup_tracing() { + echo 0 > "$SYSFS_TRACING_DIR/tracing_on" + echo "" > "$SYSFS_TRACING_DIR/set_ftrace_filter" + echo "nop" > "$SYSFS_TRACING_DIR/current_tracer" + echo "" > "$SYSFS_TRACING_DIR/trace" +} + +# trace_function(function) - start tracing of a function +# function - to be traced function +function trace_function() { + local function="$1"; shift + + cleanup_tracing + + echo "function" > "$SYSFS_TRACING_DIR/current_tracer" + echo "$function" > "$SYSFS_TRACING_DIR/set_ftrace_filter" + echo 1 > "$SYSFS_TRACING_DIR/tracing_on" +} + +# check_traced_functions(functions...) - check whether each function appeared in the trace log +# functions - list of functions to be checked +function check_traced_functions() { + local function + + for function in "$@"; do + if ! grep -Fwq "$function" "$SYSFS_TRACING_DIR/trace" ; then + die "Function ($function) did not appear in the trace" + fi + done + + cleanup_tracing +} diff --git a/tools/testing/selftests/livepatch/test-ftrace.sh b/tools/testing/selftests/livepatch/test-ftrace.sh index fe14f248913a..d2c3dea63104 100755 --- a/tools/testing/selftests/livepatch/test-ftrace.sh +++ b/tools/testing/selftests/livepatch/test-ftrace.sh @@ -61,4 +61,74 @@ livepatch: '$MOD_LIVEPATCH': unpatching complete % rmmod $MOD_LIVEPATCH" +# - verify livepatch can load +# - check if traces have a patched function +# - reset trace and unload livepatch + +start_test "trace livepatched function and check that the live patch remains in effect" + +FUNCTION_NAME="livepatch_cmdline_proc_show" + +load_lp $MOD_LIVEPATCH +trace_function "$FUNCTION_NAME" + +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" + + +# - 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-kprobe.sh b/tools/testing/selftests/livepatch/test-kprobe.sh index 115065156016..7ced4082cff3 100755 --- a/tools/testing/selftests/livepatch/test-kprobe.sh +++ b/tools/testing/selftests/livepatch/test-kprobe.sh @@ -5,6 +5,8 @@ . $(dirname $0)/functions.sh +grep -q kprobe_ftrace_ops /proc/kallsyms || skip "test-kprobe requires CONFIG_KPROBES_ON_FTRACE" + MOD_LIVEPATCH=test_klp_livepatch MOD_KPROBE=test_klp_kprobe @@ -18,11 +20,11 @@ start_test "livepatch interaction with kprobed function with post_handler" echo 1 > "$SYSFS_KPROBES_DIR/enabled" -load_mod $MOD_KPROBE has_post_handler=true +load_mod $MOD_KPROBE has_post_handler=y load_failing_mod $MOD_LIVEPATCH unload_mod $MOD_KPROBE -check_result "% insmod test_modules/test_klp_kprobe.ko has_post_handler=true +check_result "% insmod test_modules/test_klp_kprobe.ko has_post_handler=y % insmod test_modules/$MOD_LIVEPATCH.ko livepatch: enabling patch '$MOD_LIVEPATCH' livepatch: '$MOD_LIVEPATCH': initializing patching transition @@ -37,14 +39,14 @@ insmod: ERROR: could not insert module test_modules/$MOD_LIVEPATCH.ko: Device or start_test "livepatch interaction with kprobed function without post_handler" -load_mod $MOD_KPROBE has_post_handler=false +load_mod $MOD_KPROBE has_post_handler=n load_lp $MOD_LIVEPATCH unload_mod $MOD_KPROBE disable_lp $MOD_LIVEPATCH unload_lp $MOD_LIVEPATCH -check_result "% insmod test_modules/test_klp_kprobe.ko has_post_handler=false +check_result "% insmod test_modules/test_klp_kprobe.ko has_post_handler=n % insmod test_modules/$MOD_LIVEPATCH.ko livepatch: enabling patch '$MOD_LIVEPATCH' livepatch: '$MOD_LIVEPATCH': initializing patching transition 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-sysfs.sh b/tools/testing/selftests/livepatch/test-sysfs.sh index 58fe1d96997c..3b16285c6e67 100755 --- a/tools/testing/selftests/livepatch/test-sysfs.sh +++ b/tools/testing/selftests/livepatch/test-sysfs.sh @@ -8,6 +8,10 @@ MOD_LIVEPATCH=test_klp_livepatch MOD_LIVEPATCH2=test_klp_callbacks_demo MOD_LIVEPATCH3=test_klp_syscall +HAS_PATCH_ATTR=0 +HAS_REPLACE_ATTR=0 +HAS_STACK_ORDER_ATTR=0 + setup_config # - load a livepatch and verifies the sysfs entries work as expected @@ -20,13 +24,25 @@ check_sysfs_rights "$MOD_LIVEPATCH" "" "drwxr-xr-x" check_sysfs_rights "$MOD_LIVEPATCH" "enabled" "-rw-r--r--" check_sysfs_value "$MOD_LIVEPATCH" "enabled" "1" check_sysfs_rights "$MOD_LIVEPATCH" "force" "--w-------" -check_sysfs_rights "$MOD_LIVEPATCH" "replace" "-r--r--r--" -check_sysfs_rights "$MOD_LIVEPATCH" "stack_order" "-r--r--r--" -check_sysfs_value "$MOD_LIVEPATCH" "stack_order" "1" check_sysfs_rights "$MOD_LIVEPATCH" "transition" "-r--r--r--" check_sysfs_value "$MOD_LIVEPATCH" "transition" "0" -check_sysfs_rights "$MOD_LIVEPATCH" "vmlinux/patched" "-r--r--r--" -check_sysfs_value "$MOD_LIVEPATCH" "vmlinux/patched" "1" + +if does_sysfs_exist "$MOD_LIVEPATCH/vmlinux" "patched"; then + check_sysfs_rights "$MOD_LIVEPATCH" "vmlinux/patched" "-r--r--r--" + check_sysfs_value "$MOD_LIVEPATCH" "vmlinux/patched" "1" + HAS_PATCH_ATTR=1 +fi + +if does_sysfs_exist "$MOD_LIVEPATCH" "replace"; then + check_sysfs_rights "$MOD_LIVEPATCH" "replace" "-r--r--r--" + HAS_REPLACE_ATTR=1 +fi + +if does_sysfs_exist "$MOD_LIVEPATCH" "stack_order"; then + check_sysfs_rights "$MOD_LIVEPATCH" "stack_order" "-r--r--r--" + check_sysfs_value "$MOD_LIVEPATCH" "stack_order" "1" + HAS_STACK_ORDER_ATTR=1 +fi disable_lp $MOD_LIVEPATCH @@ -45,123 +61,127 @@ livepatch: '$MOD_LIVEPATCH': completing unpatching transition livepatch: '$MOD_LIVEPATCH': unpatching complete % rmmod $MOD_LIVEPATCH" -start_test "sysfs test object/patched" +if [[ "$HAS_PATCH_ATTR" == "1" ]]; then + start_test "sysfs test object/patched" -MOD_LIVEPATCH=test_klp_callbacks_demo -MOD_TARGET=test_klp_callbacks_mod -load_lp $MOD_LIVEPATCH + MOD_TARGET=test_klp_callbacks_mod + load_lp $MOD_LIVEPATCH2 -# check the "patch" file changes as target module loads/unloads -check_sysfs_value "$MOD_LIVEPATCH" "$MOD_TARGET/patched" "0" -load_mod $MOD_TARGET -check_sysfs_value "$MOD_LIVEPATCH" "$MOD_TARGET/patched" "1" -unload_mod $MOD_TARGET -check_sysfs_value "$MOD_LIVEPATCH" "$MOD_TARGET/patched" "0" + # check the "patch" file changes as target module loads/unloads + check_sysfs_value "$MOD_LIVEPATCH2" "$MOD_TARGET/patched" "0" + load_mod $MOD_TARGET + check_sysfs_value "$MOD_LIVEPATCH2" "$MOD_TARGET/patched" "1" + unload_mod $MOD_TARGET + check_sysfs_value "$MOD_LIVEPATCH2" "$MOD_TARGET/patched" "0" -disable_lp $MOD_LIVEPATCH -unload_lp $MOD_LIVEPATCH + disable_lp $MOD_LIVEPATCH2 + unload_lp $MOD_LIVEPATCH2 -check_result "% insmod test_modules/test_klp_callbacks_demo.ko -livepatch: enabling patch 'test_klp_callbacks_demo' -livepatch: 'test_klp_callbacks_demo': initializing patching transition -test_klp_callbacks_demo: pre_patch_callback: vmlinux -livepatch: 'test_klp_callbacks_demo': starting patching transition -livepatch: 'test_klp_callbacks_demo': completing patching transition -test_klp_callbacks_demo: post_patch_callback: vmlinux -livepatch: 'test_klp_callbacks_demo': patching complete -% insmod test_modules/test_klp_callbacks_mod.ko -livepatch: applying patch 'test_klp_callbacks_demo' to loading module 'test_klp_callbacks_mod' -test_klp_callbacks_demo: pre_patch_callback: test_klp_callbacks_mod -> [MODULE_STATE_COMING] Full formed, running module_init -test_klp_callbacks_demo: post_patch_callback: test_klp_callbacks_mod -> [MODULE_STATE_COMING] Full formed, running module_init -test_klp_callbacks_mod: test_klp_callbacks_mod_init -% rmmod test_klp_callbacks_mod -test_klp_callbacks_mod: test_klp_callbacks_mod_exit -test_klp_callbacks_demo: pre_unpatch_callback: test_klp_callbacks_mod -> [MODULE_STATE_GOING] Going away -livepatch: reverting patch 'test_klp_callbacks_demo' on unloading module 'test_klp_callbacks_mod' -test_klp_callbacks_demo: post_unpatch_callback: test_klp_callbacks_mod -> [MODULE_STATE_GOING] Going away -% echo 0 > $SYSFS_KLP_DIR/test_klp_callbacks_demo/enabled -livepatch: 'test_klp_callbacks_demo': initializing unpatching transition -test_klp_callbacks_demo: pre_unpatch_callback: vmlinux -livepatch: 'test_klp_callbacks_demo': starting unpatching transition -livepatch: 'test_klp_callbacks_demo': completing unpatching transition -test_klp_callbacks_demo: post_unpatch_callback: vmlinux -livepatch: 'test_klp_callbacks_demo': unpatching complete -% rmmod test_klp_callbacks_demo" - -start_test "sysfs test replace enabled" - -MOD_LIVEPATCH=test_klp_atomic_replace -load_lp $MOD_LIVEPATCH replace=1 - -check_sysfs_rights "$MOD_LIVEPATCH" "replace" "-r--r--r--" -check_sysfs_value "$MOD_LIVEPATCH" "replace" "1" + check_result "% insmod test_modules/$MOD_LIVEPATCH2.ko +livepatch: enabling patch '$MOD_LIVEPATCH2' +livepatch: '$MOD_LIVEPATCH2': initializing patching transition +$MOD_LIVEPATCH2: pre_patch_callback: vmlinux +livepatch: '$MOD_LIVEPATCH2': starting patching transition +livepatch: '$MOD_LIVEPATCH2': completing patching transition +$MOD_LIVEPATCH2: post_patch_callback: vmlinux +livepatch: '$MOD_LIVEPATCH2': patching complete +% insmod test_modules/$MOD_TARGET.ko +livepatch: applying patch '$MOD_LIVEPATCH2' to loading module '$MOD_TARGET' +$MOD_LIVEPATCH2: pre_patch_callback: $MOD_TARGET -> [MODULE_STATE_COMING] Full formed, running module_init +$MOD_LIVEPATCH2: post_patch_callback: $MOD_TARGET -> [MODULE_STATE_COMING] Full formed, running module_init +$MOD_TARGET: test_klp_callbacks_mod_init +% rmmod $MOD_TARGET +$MOD_TARGET: test_klp_callbacks_mod_exit +$MOD_LIVEPATCH2: pre_unpatch_callback: $MOD_TARGET -> [MODULE_STATE_GOING] Going away +livepatch: reverting patch '$MOD_LIVEPATCH2' on unloading module '$MOD_TARGET' +$MOD_LIVEPATCH2: post_unpatch_callback: $MOD_TARGET -> [MODULE_STATE_GOING] Going away +% echo 0 > $SYSFS_KLP_DIR/$MOD_LIVEPATCH2/enabled +livepatch: '$MOD_LIVEPATCH2': initializing unpatching transition +$MOD_LIVEPATCH2: pre_unpatch_callback: vmlinux +livepatch: '$MOD_LIVEPATCH2': starting unpatching transition +livepatch: '$MOD_LIVEPATCH2': completing unpatching transition +$MOD_LIVEPATCH2: post_unpatch_callback: vmlinux +livepatch: '$MOD_LIVEPATCH2': unpatching complete +% rmmod $MOD_LIVEPATCH2" +fi -disable_lp $MOD_LIVEPATCH -unload_lp $MOD_LIVEPATCH +if [[ "$HAS_REPLACE_ATTR" == "1" ]]; then + start_test "sysfs test replace enabled" -check_result "% insmod test_modules/$MOD_LIVEPATCH.ko replace=1 -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 -% 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" + MOD_ATOMIC_REPLACE=test_klp_atomic_replace + load_lp $MOD_ATOMIC_REPLACE replace=1 -start_test "sysfs test replace disabled" + check_sysfs_rights "$MOD_ATOMIC_REPLACE" "replace" "-r--r--r--" + check_sysfs_value "$MOD_ATOMIC_REPLACE" "replace" "1" -load_lp $MOD_LIVEPATCH replace=0 + disable_lp $MOD_ATOMIC_REPLACE + unload_lp $MOD_ATOMIC_REPLACE -check_sysfs_rights "$MOD_LIVEPATCH" "replace" "-r--r--r--" -check_sysfs_value "$MOD_LIVEPATCH" "replace" "0" + check_result "% insmod test_modules/$MOD_ATOMIC_REPLACE.ko replace=1 +livepatch: enabling patch '$MOD_ATOMIC_REPLACE' +livepatch: '$MOD_ATOMIC_REPLACE': initializing patching transition +livepatch: '$MOD_ATOMIC_REPLACE': starting patching transition +livepatch: '$MOD_ATOMIC_REPLACE': completing patching transition +livepatch: '$MOD_ATOMIC_REPLACE': patching complete +% echo 0 > $SYSFS_KLP_DIR/$MOD_ATOMIC_REPLACE/enabled +livepatch: '$MOD_ATOMIC_REPLACE': initializing unpatching transition +livepatch: '$MOD_ATOMIC_REPLACE': starting unpatching transition +livepatch: '$MOD_ATOMIC_REPLACE': completing unpatching transition +livepatch: '$MOD_ATOMIC_REPLACE': unpatching complete +% rmmod $MOD_ATOMIC_REPLACE" -disable_lp $MOD_LIVEPATCH -unload_lp $MOD_LIVEPATCH + start_test "sysfs test replace disabled" -check_result "% insmod test_modules/$MOD_LIVEPATCH.ko replace=0 -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 -% 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" + load_lp $MOD_ATOMIC_REPLACE replace=0 -start_test "sysfs test stack_order value" + check_sysfs_rights "$MOD_ATOMIC_REPLACE" "replace" "-r--r--r--" + check_sysfs_value "$MOD_ATOMIC_REPLACE" "replace" "0" -load_lp $MOD_LIVEPATCH + disable_lp $MOD_ATOMIC_REPLACE + unload_lp $MOD_ATOMIC_REPLACE -check_sysfs_value "$MOD_LIVEPATCH" "stack_order" "1" + check_result "% insmod test_modules/$MOD_ATOMIC_REPLACE.ko replace=0 +livepatch: enabling patch '$MOD_ATOMIC_REPLACE' +livepatch: '$MOD_ATOMIC_REPLACE': initializing patching transition +livepatch: '$MOD_ATOMIC_REPLACE': starting patching transition +livepatch: '$MOD_ATOMIC_REPLACE': completing patching transition +livepatch: '$MOD_ATOMIC_REPLACE': patching complete +% echo 0 > $SYSFS_KLP_DIR/$MOD_ATOMIC_REPLACE/enabled +livepatch: '$MOD_ATOMIC_REPLACE': initializing unpatching transition +livepatch: '$MOD_ATOMIC_REPLACE': starting unpatching transition +livepatch: '$MOD_ATOMIC_REPLACE': completing unpatching transition +livepatch: '$MOD_ATOMIC_REPLACE': unpatching complete +% rmmod $MOD_ATOMIC_REPLACE" +fi -load_lp $MOD_LIVEPATCH2 +if [[ "$HAS_STACK_ORDER_ATTR" == "1" ]]; then + start_test "sysfs test stack_order value" -check_sysfs_value "$MOD_LIVEPATCH2" "stack_order" "2" + load_lp $MOD_LIVEPATCH -load_lp $MOD_LIVEPATCH3 + check_sysfs_value "$MOD_LIVEPATCH" "stack_order" "1" -check_sysfs_value "$MOD_LIVEPATCH3" "stack_order" "3" + load_lp $MOD_LIVEPATCH2 -disable_lp $MOD_LIVEPATCH2 -unload_lp $MOD_LIVEPATCH2 + check_sysfs_value "$MOD_LIVEPATCH2" "stack_order" "2" -check_sysfs_value "$MOD_LIVEPATCH" "stack_order" "1" -check_sysfs_value "$MOD_LIVEPATCH3" "stack_order" "2" + load_lp $MOD_LIVEPATCH3 -disable_lp $MOD_LIVEPATCH3 -unload_lp $MOD_LIVEPATCH3 + check_sysfs_value "$MOD_LIVEPATCH3" "stack_order" "3" -disable_lp $MOD_LIVEPATCH -unload_lp $MOD_LIVEPATCH + disable_lp $MOD_LIVEPATCH2 + unload_lp $MOD_LIVEPATCH2 -check_result "% insmod test_modules/$MOD_LIVEPATCH.ko + check_sysfs_value "$MOD_LIVEPATCH" "stack_order" "1" + check_sysfs_value "$MOD_LIVEPATCH3" "stack_order" "2" + + disable_lp $MOD_LIVEPATCH3 + unload_lp $MOD_LIVEPATCH3 + + 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 @@ -201,5 +221,6 @@ livepatch: '$MOD_LIVEPATCH': starting unpatching transition livepatch: '$MOD_LIVEPATCH': completing unpatching transition livepatch: '$MOD_LIVEPATCH': unpatching complete % rmmod $MOD_LIVEPATCH" +fi 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"); diff --git a/tools/testing/selftests/livepatch/test_modules/test_klp_syscall.c b/tools/testing/selftests/livepatch/test_modules/test_klp_syscall.c index dd802783ea84..08aacc0e14de 100644 --- a/tools/testing/selftests/livepatch/test_modules/test_klp_syscall.c +++ b/tools/testing/selftests/livepatch/test_modules/test_klp_syscall.c @@ -12,15 +12,26 @@ #include <linux/slab.h> #include <linux/livepatch.h> -#if defined(__x86_64__) -#define FN_PREFIX __x64_ -#elif defined(__s390x__) -#define FN_PREFIX __s390x_ -#elif defined(__aarch64__) -#define FN_PREFIX __arm64_ +/* + * Before CONFIG_ARCH_HAS_SYSCALL_WRAPPER was introduced there were no + * prefixes for system calls. + * powerpc set this config based on configs, so it can be enabled or not. + */ +#if defined(CONFIG_ARCH_HAS_SYSCALL_WRAPPER) + #if defined(__x86_64__) + #define FN_PREFIX __x64_ + #elif defined(__s390x__) + #define FN_PREFIX __s390x_ + #elif defined(__aarch64__) + #define FN_PREFIX __arm64_ + #elif defined(__powerpc__) + #define FN_PREFIX + #else + #error "Missing syscall wrapper for the given architecture." + #endif #else -/* powerpc does not select ARCH_HAS_SYSCALL_WRAPPER */ -#define FN_PREFIX + /* Do not set a prefix for architectures that do not enable wrappers. */ + #define FN_PREFIX #endif /* Protects klp_pids */ @@ -98,7 +109,11 @@ static int livepatch_init(void) */ npids = npids_pending; - return klp_enable_patch(&patch); + ret = klp_enable_patch(&patch); + if (ret) + kobject_put(klp_kobj); + + return ret; } static void livepatch_exit(void) |
