diff options
Diffstat (limited to 'tools/testing/selftests/livepatch')
9 files changed, 432 insertions, 129 deletions
diff --git a/tools/testing/selftests/livepatch/functions.sh b/tools/testing/selftests/livepatch/functions.sh index 8ec0cb64ad94..a65b7b1ac8ad 100644 --- a/tools/testing/selftests/livepatch/functions.sh +++ b/tools/testing/selftests/livepatch/functions.sh @@ -4,6 +4,8 @@ # Shell functions for the rest of the scripts. +export LC_ALL=C + MAX_RETRIES=600 RETRY_INTERVAL=".1" # seconds SYSFS_KERNEL_DIR="/sys/kernel" @@ -124,6 +126,20 @@ function set_ftrace_enabled() { echo "livepatch: kernel.ftrace_enabled = $result" > /dev/kmsg } +# ftrace_disable_supported() - probe whether kernel.ftrace_enabled=0 +# can still disable ftrace on this kernel. Newer kernels deprecate +# the knob and always refuse the write with -EOPNOTSUPP. +function ftrace_disable_supported() { + local orig result + + orig=$(sysctl --values kernel.ftrace_enabled) + sysctl -q kernel.ftrace_enabled=0 &> /dev/null + result=$(sysctl --values kernel.ftrace_enabled) + sysctl -q "kernel.ftrace_enabled=$orig" &> /dev/null + + [[ "$result" == "0" ]] +} + function cleanup() { pop_config } @@ -339,6 +355,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 diff --git a/tools/testing/selftests/livepatch/test-ftrace.sh b/tools/testing/selftests/livepatch/test-ftrace.sh index 094176f1a46a..cd27148510f8 100755 --- a/tools/testing/selftests/livepatch/test-ftrace.sh +++ b/tools/testing/selftests/livepatch/test-ftrace.sh @@ -12,29 +12,32 @@ setup_config # - turn ftrace_enabled OFF and verify livepatches can't load # - turn ftrace_enabled ON and verify livepatch can load # - verify that ftrace_enabled can't be turned OFF while a livepatch is loaded +# (skipped on kernels where the sysctl is deprecated and always refuses 0) start_test "livepatch interaction with ftrace_enabled sysctl" -set_ftrace_enabled 0 -load_failing_mod $MOD_LIVEPATCH +if ftrace_disable_supported; then -set_ftrace_enabled 1 -load_lp $MOD_LIVEPATCH -if [[ "$(cat /proc/cmdline)" != "$MOD_LIVEPATCH: this has been live patched" ]] ; then - echo -e "FAIL\n\n" - die "livepatch kselftest(s) failed" -fi + set_ftrace_enabled 0 + load_failing_mod $MOD_LIVEPATCH -# Check that ftrace could not get disabled when a livepatch is enabled -set_ftrace_enabled --fail 0 -if [[ "$(cat /proc/cmdline)" != "$MOD_LIVEPATCH: this has been live patched" ]] ; then - echo -e "FAIL\n\n" - die "livepatch kselftest(s) failed" -fi -disable_lp $MOD_LIVEPATCH -unload_lp $MOD_LIVEPATCH + set_ftrace_enabled 1 + load_lp $MOD_LIVEPATCH + if [[ "$(cat /proc/cmdline)" != "$MOD_LIVEPATCH: this has been live patched" ]] ; then + echo -e "FAIL\n\n" + die "livepatch kselftest(s) failed" + fi + + # Check that ftrace could not get disabled when a livepatch is enabled + set_ftrace_enabled --fail 0 + if [[ "$(cat /proc/cmdline)" != "$MOD_LIVEPATCH: this has been live patched" ]] ; then + echo -e "FAIL\n\n" + die "livepatch kselftest(s) failed" + fi + disable_lp $MOD_LIVEPATCH + unload_lp $MOD_LIVEPATCH -check_result "livepatch: kernel.ftrace_enabled = 0 + check_result "livepatch: kernel.ftrace_enabled = 0 % insmod test_modules/$MOD_LIVEPATCH.ko livepatch: enabling patch '$MOD_LIVEPATCH' livepatch: '$MOD_LIVEPATCH': initializing patching transition @@ -60,6 +63,14 @@ livepatch: '$MOD_LIVEPATCH': completing unpatching transition livepatch: '$MOD_LIVEPATCH': unpatching complete % rmmod $MOD_LIVEPATCH" +else + + set_ftrace_enabled --fail 0 + check_result "livepatch: sysctl: setting key \"kernel.ftrace_enabled\": \ +Operation not supported" + +fi + # - verify livepatch can load # - check if traces have a patched function @@ -95,4 +106,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-kprobe.sh b/tools/testing/selftests/livepatch/test-kprobe.sh index b67dfad03d97..7ced4082cff3 100755 --- a/tools/testing/selftests/livepatch/test-kprobe.sh +++ b/tools/testing/selftests/livepatch/test-kprobe.sh @@ -20,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 @@ -39,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) |
