From e9b233d55d32af9e1c9680875c9932ba8f1fe517 Mon Sep 17 00:00:00 2001 From: Wardenjohn Date: Sat, 12 Oct 2024 11:15:16 +0800 Subject: [PATCH] kpatch: Add subcommand '--active-functions' to adjust new sysfs attribute 'stack_order' of livepatch Add an subcommand of kpatch list with '--active-functions' option to adjust kernel new attribute 'stack_order' of livepatch of kernel v6.13 or later. Now, using 'kpatch list --active-functions' can output the enabling function in the system and the relationship from the enabling function to its object and its related module. For older kernel, which is not support 'stack_order' attribute, if there are just one klp module loaded in the system, we support to output the active functions. However, if there are more than one klp module loaded, we can not output the active functions becase the information without 'stack_order' is not accurate. Suggested-by: Joe Lawrence Signed-off-by: Wardenjohn --- kpatch-build/kpatch-build | 2 +- kpatch/kpatch | 141 +++++++++++++++++++++++++++++++------- 2 files changed, 116 insertions(+), 27 deletions(-) diff --git a/kpatch-build/kpatch-build b/kpatch-build/kpatch-build index bc112fc9..97b20bc7 100755 --- a/kpatch-build/kpatch-build +++ b/kpatch-build/kpatch-build @@ -57,7 +57,7 @@ DEBUG_KCFLAGS="" declare -a PATCH_LIST APPLIED_PATCHES=0 OOT_MODULE= -KLP_REPLACE=1 +KLP_REPLACE=0 GCC="${CROSS_COMPILE:-}gcc" CLANG="${CROSS_COMPILE:-}clang" diff --git a/kpatch/kpatch b/kpatch/kpatch index 0e94a5d7..7d1950ce 100755 --- a/kpatch/kpatch +++ b/kpatch/kpatch @@ -56,6 +56,7 @@ usage () { usage_cmd "info " "show information about a patch module" echo >&2 usage_cmd "list" "list installed patch modules" + usage_cmd "list --active-functions" "list the enabling functions and its relationship from patch module to the function enabling in the system. For the older version which is not support 'stack_order' attribute, only one patch loaded is accurate." echo >&2 usage_cmd "signal" "signal/poke any process stalling the current patch transition. This is only useful on systems that have the sysfs livepatch signal interface. On other systems, the signaling should be done automatically by the OS and this subcommand is a no-op." echo >&2 @@ -446,6 +447,104 @@ get_module_version() { MODVER="${MODVER/ */}" } +declare -A function_map +show_enabled_function() { + + for module_dir in /sys/kernel/livepatch/*; do + if [ -d "$module_dir" ]; then + if [[ ! -e "$module_dir/stack_order" ]]; then + folder_count=$(ls "/sys/kernel/livepatch/" | wc -l) + if [[ $folder_count -le 1 ]]; then + # older version without 'stack_order' with only one patch is accurate + module_name=$(basename "$module_dir") + for obj_dir in "$module_dir"/*/; do + for func_dir in "$obj_dir"/*; do + obj_name=$(basename "$obj_dir") + if [ -d "$func_dir" ]; then + func_name=$(basename "$func_dir") + func_name=${func_name%%,*} + function_map[$func_name]="$stack_order:$module_name:$obj_name" + fi + done + done + echo "" + echo "The function enabling in the system:" + output_data=( + "Module Object Function" + ) + for func_name in "${!function_map[@]}"; do + IFS=':' read -r stack_order module_name obj_name <<< "${function_map[$func_name]}" + output_data+=("$module_name $obj_name $func_name") + done + printf "%s\n" "${output_data[@]}" | column -t + else + echo "This kernel don't support stack_order attribute, we don't support situation that more than one patch loaded." + fi + return; + fi + stack_order=$(cat "$module_dir/stack_order") + + module_name=$(basename "$module_dir") + for obj_dir in "$module_dir"/*/; do + for func_dir in "$obj_dir"/*; do + obj_name=$(basename "$obj_dir") + if [ -d "$func_dir" ]; then + func_name=$(basename "$func_dir") + func_name=${func_name%%,*} + if [[ -z "${function_map[$func_name]}" ]]; then + function_map[$func_name]="$stack_order:$module_name:$obj_name" + else + IFS=':' read -r recorded_order this_module this_obj <<< "${function_map[$func_name]}" + if [[ $recorded_order -lt $stack_order ]]; then + function_map[$func_name]="$stack_order:$module_name:$obj_name" + fi + fi + fi + done + done + fi + done + + echo "" + echo "The function enabling in the system:" + output_data=( + "Module Object Function" + ) + for func_name in "${!function_map[@]}"; do + IFS=':' read -r stack_order module_name obj_name <<< "${function_map[$func_name]}" + output_data+=("$module_name $obj_name $func_name") + done + printf "%s\n" "${output_data[@]}" | column -t +} + +print_patch_info() { + echo "Loaded patch modules:" + for module in "$SYSFS"/*; do + if [[ -e "$module" ]]; then + modname=$(basename "$module") + if [[ "$(cat "$module/enabled" 2>/dev/null)" -eq 1 ]]; then + in_transition "$modname" && state="enabling..." \ + || state="enabled" + else + in_transition "$modname" && state="disabling..." \ + || state="disabled" + fi + echo "$modname [$state]" + fi + done + show_stalled_processes + echo "" + echo "Installed patch modules:" + for kdir in "$INSTALLDIR"/*; do + [[ -e "$kdir" ]] || continue + for module in "$kdir"/*.ko; do + [[ -e "$module" ]] || continue + mod_name "$module" + echo "$MODNAME ($(basename "$kdir"))" + done + done +} + unset MODULE # Initialize the $SYSFS var. This only works if the core module has been @@ -592,32 +691,22 @@ case "$1" in ;; "list") - [[ "$#" -ne 1 ]] && usage - echo "Loaded patch modules:" - for module in "$SYSFS"/*; do - if [[ -e "$module" ]]; then - modname=$(basename "$module") - if [[ "$(cat "$module/enabled" 2>/dev/null)" -eq 1 ]]; then - in_transition "$modname" && state="enabling..." \ - || state="enabled" - else - in_transition "$modname" && state="disabling..." \ - || state="disabled" - fi - echo "$modname [$state]" - fi - done - show_stalled_processes - echo "" - echo "Installed patch modules:" - for kdir in "$INSTALLDIR"/*; do - [[ -e "$kdir" ]] || continue - for module in "$kdir"/*.ko; do - [[ -e "$module" ]] || continue - mod_name "$module" - echo "$MODNAME ($(basename "$kdir"))" - done - done + [[ "$#" -gt 2 ]] && usage + if [[ -n "$2" ]]; then + case "$2" in + --active-functions) + print_patch_info + show_enabled_function + shift + ;; + *) + usage + shift + ;; + esac + else + print_patch_info + fi ;; "info")