Unified · Split
| @@ -55,6 +55,14 @@ Description: · 54 unmodified lines | ||
| 55 | 55 | The object directory contains subdirectories for each function |
| 56 | 56 | that is patched within the object. |
| 57 | 57 | |
| 58 | +What: /sys/kernel/livepatch/<patch>/<object>/patched | |
| 59 | +Date: August 2022 | |
| 60 | +KernelVersion: 6.1.0 | |
| 61 | +Contact: live-patching@vger.kernel.org | |
| 62 | +Description: | |
| 63 | + An attribute which indicates whether the object is currently | |
| 64 | + patched. | |
| 65 | + | |
| 58 | 66 | What: /sys/kernel/livepatch/<patch>/<object>/<function,sympos> |
| 59 | 67 | Date: Nov 2014 |
| 60 | 68 | KernelVersion: 3.19.0 |
| @@ -325,6 +325,7 @@ int klp_apply_section_relocs(struct module *pmod, Elf_Shdr *sechdrs, · 324 unmodified lines | ||
| 325 | 325 | * /sys/kernel/livepatch/<patch>/transition |
| 326 | 326 | * /sys/kernel/livepatch/<patch>/force |
| 327 | 327 | * /sys/kernel/livepatch/<patch>/<object> |
| 328 | + * /sys/kernel/livepatch/<patch>/<object>/patched | |
| 328 | 329 | * /sys/kernel/livepatch/<patch>/<object>/<function,sympos> |
| 329 | 330 | */ |
| 330 | 331 | static int __klp_disable_patch(struct klp_patch *patch); |
| @@ -431,6 +432,22 @@ static struct attribute *klp_patch_attrs[] = { · 100 unmodified lines | ||
| 431 | 432 | }; |
| 432 | 433 | ATTRIBUTE_GROUPS(klp_patch); |
| 433 | 434 | |
| 435 | +static ssize_t patched_show(struct kobject *kobj, | |
| 436 | + struct kobj_attribute *attr, char *buf) | |
| 437 | +{ | |
| 438 | + struct klp_object *obj; | |
| 439 | + | |
| 440 | + obj = container_of(kobj, struct klp_object, kobj); | |
| 441 | + return sysfs_emit(buf, "%d\n", obj->patched); | |
| 442 | +} | |
| 443 | + | |
| 444 | +static struct kobj_attribute patched_kobj_attr = __ATTR_RO(patched); | |
| 445 | +static struct attribute *klp_object_attrs[] = { | |
| 446 | + &patched_kobj_attr.attr, | |
| 447 | + NULL, | |
| 448 | +}; | |
| 449 | +ATTRIBUTE_GROUPS(klp_object); | |
| 450 | + | |
| 434 | 451 | static void klp_free_object_dynamic(struct klp_object *obj) |
| 435 | 452 | { |
| 436 | 453 | kfree(obj->name); |
| @@ -576,6 +593,7 @@ static void klp_kobj_release_object(struct kobject *kobj) · 139 unmodified lines | ||
| 576 | 593 | static struct kobj_type klp_ktype_object = { |
| 577 | 594 | .release = klp_kobj_release_object, |
| 578 | 595 | .sysfs_ops = &kobj_sysfs_ops, |
| 596 | + .default_groups = klp_object_groups, | |
| 579 | 597 | }; |
| 580 | 598 | |
| 581 | 599 | static void klp_kobj_release_func(struct kobject *kobj) |
| @@ -6,7 +6,8 @@ TEST_PROGS := \ · 5 unmodified lines | ||
| 6 | 6 | test-callbacks.sh \ |
| 7 | 7 | test-shadow-vars.sh \ |
| 8 | 8 | test-state.sh \ |
| 9 | − test-ftrace.sh | |
| 9 | + test-ftrace.sh \ | |
| 10 | + test-sysfs.sh | |
| 10 | 11 | |
| 11 | 12 | TEST_FILES := settings |
| 12 | 13 | |
| @@ -6,6 +6,7 @@ · 5 unmodified lines | ||
| 6 | 6 | |
| 7 | 7 | MAX_RETRIES=600 |
| 8 | 8 | RETRY_INTERVAL=".1" # seconds |
| 9 | +KLP_SYSFS_DIR="/sys/kernel/livepatch" | |
| 9 | 10 | |
| 10 | 11 | # Kselftest framework requirement - SKIP code is 4 |
| 11 | 12 | ksft_skip=4 |
| @@ -308,3 +309,36 @@ function check_result { · 296 unmodified lines | ||
| 308 | 309 | |
| 309 | 310 | cleanup_dmesg_file |
| 310 | 311 | } |
| 312 | + | |
| 313 | +# check_sysfs_rights(modname, rel_path, expected_rights) - check sysfs | |
| 314 | +# path permissions | |
| 315 | +# modname - livepatch module creating the sysfs interface | |
| 316 | +# rel_path - relative path of the sysfs interface | |
| 317 | +# expected_rights - expected access rights | |
| 318 | +function check_sysfs_rights() { | |
| 319 | + local mod="$1"; shift | |
| 320 | + local rel_path="$1"; shift | |
| 321 | + local expected_rights="$1"; shift | |
| 322 | + | |
| 323 | + local path="$KLP_SYSFS_DIR/$mod/$rel_path" | |
| 324 | + local rights=$(/bin/stat --format '%A' "$path") | |
| 325 | + if test "$rights" != "$expected_rights" ; then | |
| 326 | + die "Unexpected access rights of $path: $expected_rights vs. $rights" | |
| 327 | + fi | |
| 328 | +} | |
| 329 | + | |
| 330 | +# check_sysfs_value(modname, rel_path, expected_value) - check sysfs value | |
| 331 | +# modname - livepatch module creating the sysfs interface | |
| 332 | +# rel_path - relative path of the sysfs interface | |
| 333 | +# expected_value - expected value read from the file | |
| 334 | +function check_sysfs_value() { | |
| 335 | + local mod="$1"; shift | |
| 336 | + local rel_path="$1"; shift | |
| 337 | + local expected_value="$1"; shift | |
| 338 | + | |
| 339 | + local path="$KLP_SYSFS_DIR/$mod/$rel_path" | |
| 340 | + local value=`cat $path` | |
| 341 | + if test "$value" != "$expected_value" ; then | |
| 342 | + die "Unexpected value in $path: $expected_value vs. $value" | |
| 343 | + fi | |
| 344 | +} | |
| @@ -0,0 +1,86 @@ | ||
| 1 | +#!/bin/bash | |
| 2 | +# SPDX-License-Identifier: GPL-2.0 | |
| 3 | +# Copyright (C) 2022 Song Liu <song@kernel.org> | |
| 4 | + | |
| 5 | +. $(dirname $0)/functions.sh | |
| 6 | + | |
| 7 | +MOD_LIVEPATCH=test_klp_livepatch | |
| 8 | + | |
| 9 | +setup_config | |
| 10 | + | |
| 11 | +# - load a livepatch and verifies the sysfs entries work as expected | |
| 12 | + | |
| 13 | +start_test "sysfs test" | |
| 14 | + | |
| 15 | +load_lp $MOD_LIVEPATCH | |
| 16 | + | |
| 17 | +check_sysfs_rights "$MOD_LIVEPATCH" "" "drwxr-xr-x" | |
| 18 | +check_sysfs_rights "$MOD_LIVEPATCH" "enabled" "-rw-r--r--" | |
| 19 | +check_sysfs_value "$MOD_LIVEPATCH" "enabled" "1" | |
| 20 | +check_sysfs_rights "$MOD_LIVEPATCH" "force" "--w-------" | |
| 21 | +check_sysfs_rights "$MOD_LIVEPATCH" "transition" "-r--r--r--" | |
| 22 | +check_sysfs_value "$MOD_LIVEPATCH" "transition" "0" | |
| 23 | +check_sysfs_rights "$MOD_LIVEPATCH" "vmlinux/patched" "-r--r--r--" | |
| 24 | +check_sysfs_value "$MOD_LIVEPATCH" "vmlinux/patched" "1" | |
| 25 | + | |
| 26 | +disable_lp $MOD_LIVEPATCH | |
| 27 | + | |
| 28 | +unload_lp $MOD_LIVEPATCH | |
| 29 | + | |
| 30 | +check_result "% modprobe $MOD_LIVEPATCH | |
| 31 | +livepatch: enabling patch '$MOD_LIVEPATCH' | |
| 32 | +livepatch: '$MOD_LIVEPATCH': initializing patching transition | |
| 33 | +livepatch: '$MOD_LIVEPATCH': starting patching transition | |
| 34 | +livepatch: '$MOD_LIVEPATCH': completing patching transition | |
| 35 | +livepatch: '$MOD_LIVEPATCH': patching complete | |
| 36 | +% echo 0 > /sys/kernel/livepatch/$MOD_LIVEPATCH/enabled | |
| 37 | +livepatch: '$MOD_LIVEPATCH': initializing unpatching transition | |
| 38 | +livepatch: '$MOD_LIVEPATCH': starting unpatching transition | |
| 39 | +livepatch: '$MOD_LIVEPATCH': completing unpatching transition | |
| 40 | +livepatch: '$MOD_LIVEPATCH': unpatching complete | |
| 41 | +% rmmod $MOD_LIVEPATCH" | |
| 42 | + | |
| 43 | +start_test "sysfs test object/patched" | |
| 44 | + | |
| 45 | +MOD_LIVEPATCH=test_klp_callbacks_demo | |
| 46 | +MOD_TARGET=test_klp_callbacks_mod | |
| 47 | +load_lp $MOD_LIVEPATCH | |
| 48 | + | |
| 49 | +# check the "patch" file changes as target module loads/unloads | |
| 50 | +check_sysfs_value "$MOD_LIVEPATCH" "$MOD_TARGET/patched" "0" | |
| 51 | +load_mod $MOD_TARGET | |
| 52 | +check_sysfs_value "$MOD_LIVEPATCH" "$MOD_TARGET/patched" "1" | |
| 53 | +unload_mod $MOD_TARGET | |
| 54 | +check_sysfs_value "$MOD_LIVEPATCH" "$MOD_TARGET/patched" "0" | |
| 55 | + | |
| 56 | +disable_lp $MOD_LIVEPATCH | |
| 57 | +unload_lp $MOD_LIVEPATCH | |
| 58 | + | |
| 59 | +check_result "% modprobe test_klp_callbacks_demo | |
| 60 | +livepatch: enabling patch 'test_klp_callbacks_demo' | |
| 61 | +livepatch: 'test_klp_callbacks_demo': initializing patching transition | |
| 62 | +test_klp_callbacks_demo: pre_patch_callback: vmlinux | |
| 63 | +livepatch: 'test_klp_callbacks_demo': starting patching transition | |
| 64 | +livepatch: 'test_klp_callbacks_demo': completing patching transition | |
| 65 | +test_klp_callbacks_demo: post_patch_callback: vmlinux | |
| 66 | +livepatch: 'test_klp_callbacks_demo': patching complete | |
| 67 | +% modprobe test_klp_callbacks_mod | |
| 68 | +livepatch: applying patch 'test_klp_callbacks_demo' to loading module 'test_klp_callbacks_mod' | |
| 69 | +test_klp_callbacks_demo: pre_patch_callback: test_klp_callbacks_mod -> [MODULE_STATE_COMING] Full formed, running module_init | |
| 70 | +test_klp_callbacks_demo: post_patch_callback: test_klp_callbacks_mod -> [MODULE_STATE_COMING] Full formed, running module_init | |
| 71 | +test_klp_callbacks_mod: test_klp_callbacks_mod_init | |
| 72 | +% rmmod test_klp_callbacks_mod | |
| 73 | +test_klp_callbacks_mod: test_klp_callbacks_mod_exit | |
| 74 | +test_klp_callbacks_demo: pre_unpatch_callback: test_klp_callbacks_mod -> [MODULE_STATE_GOING] Going away | |
| 75 | +livepatch: reverting patch 'test_klp_callbacks_demo' on unloading module 'test_klp_callbacks_mod' | |
| 76 | +test_klp_callbacks_demo: post_unpatch_callback: test_klp_callbacks_mod -> [MODULE_STATE_GOING] Going away | |
| 77 | +% echo 0 > /sys/kernel/livepatch/test_klp_callbacks_demo/enabled | |
| 78 | +livepatch: 'test_klp_callbacks_demo': initializing unpatching transition | |
| 79 | +test_klp_callbacks_demo: pre_unpatch_callback: vmlinux | |
| 80 | +livepatch: 'test_klp_callbacks_demo': starting unpatching transition | |
| 81 | +livepatch: 'test_klp_callbacks_demo': completing unpatching transition | |
| 82 | +test_klp_callbacks_demo: post_unpatch_callback: vmlinux | |
| 83 | +livepatch: 'test_klp_callbacks_demo': unpatching complete | |
| 84 | +% rmmod test_klp_callbacks_demo" | |
| 85 | + | |
| 86 | +exit 0 | |