livepatching changes for 7.2

-----BEGIN PGP SIGNATURE-----
 
 iQJPBAABCAA5FiEESH4wyp42V4tXvYsjUqAMR0iAlPIFAmoxRegbFIAAAAAABAAO
 bWFudTIsMi41KzEuMTIsMiwyAAoJEFKgDEdIgJTymxUP/iJEA5aswiFZGknP07LR
 jQi9ooeBPaM1cnPyQ+daNXrhsXVJ9I1tUUC/jlUNIYF/RRA1EnCPHVjTaKDfMTsL
 doiDBEsVim3RHXvwn517Yt8RIJDMY6USn7UYqIJ35yZGZZkUn+y/VIllNF40FFV+
 tXVb5JVU4825vpmdrl3pwh/Tiyx9llvMdxMdq2IwTxVcl+Ip1t5NXZ4anOQR8T2g
 B12IsM8cklRNdRqlGPSc1GNzevAkky8uzTpYYDjk08pOpMh2G+Ols1sK+zx6MfAM
 yn7IvT4HnltZPkXu7OfYxefK/DekbmlbkEoJ2uDEPfhv3qY53BKdF17XawWa9dmz
 5lrhtD0Ga5jucNXq3bk/UQ3P9/q9WNtsE2u9iUvGDagVqImsPhs1st8olHyF9fha
 pA3cwTz9XmnxoZ5ESZi+f5M2LsuzugY75j/2YiMuPFNxTmCEdNPlQ7GkBDyPXWLn
 QT77ROHo8YATvxsg4Atj1h57fMh0dq77Zmsxew1SmfsmoTWPKFLzTDQttE9Vvf+s
 6FR74UXzRZFsU7cPrFYULfJyekhlPQE4+W/TOe5LXz/4LnwkjERFJ5ETfsp7Cxne
 aJZ93BWI+SVqShN6sUKia5h8QjXponAZh31NiTbkvCBxNtBxvNeJopqHqfFsco4a
 vyjGwFOywFn7/fFg83vzfgrr
 =lQUD
 -----END PGP SIGNATURE-----

Merge tag 'livepatching-for-7.2' of git://git.kernel.org/pub/scm/linux/kernel/git/livepatching/livepatching

Pull livepatching updates from Petr Mladek:

 - Fix a potential memory leak in a selftest module

 - Make selftests locale independent

 - Allow running the selftest with older kernels back to 4.12

* tag 'livepatching-for-7.2' of git://git.kernel.org/pub/scm/linux/kernel/git/livepatching/livepatching:
  selftests/livepatch: fix resource leak in test_klp_syscall init error path
  selftests: livepatch: set LC_ALL=C to fix locale-dependent test failure
  selftests: livepatch: Check if stack_order sysfs attribute exists
  selftests: livepatch: Check if replace sysfs attribute exists
  selftests: livepatch: Check if patched sysfs attribute exists
  selftests: livepatch: Introduce does_sysfs_exist function
  selftests: livepatch: Replace true/false module parameter by y/n
  selftests: livepatch: Check for ARCH_HAS_SYSCALL_WRAPPER config
This commit is contained in:
Linus Torvalds 2026-06-17 12:10:52 -07:00
commit 0839c8963b
4 changed files with 157 additions and 109 deletions

View File

@ -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"
@ -339,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

View File

@ -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

View File

@ -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"
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
start_test "sysfs test replace enabled"
if [[ "$HAS_REPLACE_ATTR" == "1" ]]; then
start_test "sysfs test replace enabled"
MOD_LIVEPATCH=test_klp_atomic_replace
load_lp $MOD_LIVEPATCH replace=1
MOD_ATOMIC_REPLACE=test_klp_atomic_replace
load_lp $MOD_ATOMIC_REPLACE replace=1
check_sysfs_rights "$MOD_LIVEPATCH" "replace" "-r--r--r--"
check_sysfs_value "$MOD_LIVEPATCH" "replace" "1"
check_sysfs_rights "$MOD_ATOMIC_REPLACE" "replace" "-r--r--r--"
check_sysfs_value "$MOD_ATOMIC_REPLACE" "replace" "1"
disable_lp $MOD_LIVEPATCH
unload_lp $MOD_LIVEPATCH
disable_lp $MOD_ATOMIC_REPLACE
unload_lp $MOD_ATOMIC_REPLACE
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"
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"
start_test "sysfs test replace disabled"
start_test "sysfs test replace disabled"
load_lp $MOD_LIVEPATCH replace=0
load_lp $MOD_ATOMIC_REPLACE replace=0
check_sysfs_rights "$MOD_LIVEPATCH" "replace" "-r--r--r--"
check_sysfs_value "$MOD_LIVEPATCH" "replace" "0"
check_sysfs_rights "$MOD_ATOMIC_REPLACE" "replace" "-r--r--r--"
check_sysfs_value "$MOD_ATOMIC_REPLACE" "replace" "0"
disable_lp $MOD_LIVEPATCH
unload_lp $MOD_LIVEPATCH
disable_lp $MOD_ATOMIC_REPLACE
unload_lp $MOD_ATOMIC_REPLACE
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"
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
start_test "sysfs test stack_order value"
if [[ "$HAS_STACK_ORDER_ATTR" == "1" ]]; then
start_test "sysfs test stack_order value"
load_lp $MOD_LIVEPATCH
load_lp $MOD_LIVEPATCH
check_sysfs_value "$MOD_LIVEPATCH" "stack_order" "1"
check_sysfs_value "$MOD_LIVEPATCH" "stack_order" "1"
load_lp $MOD_LIVEPATCH2
load_lp $MOD_LIVEPATCH2
check_sysfs_value "$MOD_LIVEPATCH2" "stack_order" "2"
check_sysfs_value "$MOD_LIVEPATCH2" "stack_order" "2"
load_lp $MOD_LIVEPATCH3
load_lp $MOD_LIVEPATCH3
check_sysfs_value "$MOD_LIVEPATCH3" "stack_order" "3"
check_sysfs_value "$MOD_LIVEPATCH3" "stack_order" "3"
disable_lp $MOD_LIVEPATCH2
unload_lp $MOD_LIVEPATCH2
disable_lp $MOD_LIVEPATCH2
unload_lp $MOD_LIVEPATCH2
check_sysfs_value "$MOD_LIVEPATCH" "stack_order" "1"
check_sysfs_value "$MOD_LIVEPATCH3" "stack_order" "2"
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_LIVEPATCH3
unload_lp $MOD_LIVEPATCH3
disable_lp $MOD_LIVEPATCH
unload_lp $MOD_LIVEPATCH
disable_lp $MOD_LIVEPATCH
unload_lp $MOD_LIVEPATCH
check_result "% insmod test_modules/$MOD_LIVEPATCH.ko
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

View File

@ -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)