@@ -10,7 +10,8 @@ TEST_PROGS := \
test-state.sh \
test-ftrace.sh \
test-sysfs.sh \
- test-syscall.sh
+ test-syscall.sh \
+ test-extern.sh
TEST_FILES := settings
@@ -7,6 +7,7 @@
MAX_RETRIES=600
RETRY_INTERVAL=".1" # seconds
KLP_SYSFS_DIR="/sys/kernel/livepatch"
+MODULE_SYSFS_DIR="/sys/module"
# Kselftest framework requirement - SKIP code is 4
ksft_skip=4
@@ -344,3 +345,16 @@ function check_sysfs_value() {
die "Unexpected value in $path: $expected_value vs. $value"
fi
}
+
+# read_module_param_value(modname, param) - read module parameter value
+# modname - livepatch module creating the sysfs interface
+# param - parameter name
+function read_module_param() {
+ local mod="$1"; shift
+ local param="$1"; shift
+
+ local path="$MODULE_SYSFS_DIR/$mod/parameters/$param"
+
+ log "% echo \"$mod/parameters/$param: \$(cat $path)\""
+ log "$mod/parameters/$param: $(cat $path)"
+}
new file mode 100755
@@ -0,0 +1,57 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2024 Lukas Hruska <lhruska@suse.cz>
+
+. $(dirname $0)/functions.sh
+
+MOD_LIVEPATCH=test_klp_extern
+MOD_HELLO=test_klp_extern_hello
+PARAM_HELLO=hello
+
+setup_config
+
+# - load a module to be livepatched
+# - load a livepatch that modifies the output from 'hello' parameter
+# of the previously loaded module and verify correct behaviour
+# - unload the livepatch and make sure the patch was removed
+# - unload the module that was livepatched
+
+start_test "livepatch with external symbol"
+
+load_mod $MOD_HELLO
+
+read_module_param $MOD_HELLO $PARAM_HELLO
+
+load_lp $MOD_LIVEPATCH
+
+read_module_param $MOD_HELLO $PARAM_HELLO
+
+disable_lp $MOD_LIVEPATCH
+unload_lp $MOD_LIVEPATCH
+
+read_module_param $MOD_HELLO $PARAM_HELLO
+
+unload_mod $MOD_HELLO
+
+check_result "% insmod test_modules/$MOD_HELLO.ko
+% echo \"$MOD_HELLO/parameters/$PARAM_HELLO: \$(cat /sys/module/$MOD_HELLO/parameters/$PARAM_HELLO)\"
+$MOD_HELLO/parameters/$PARAM_HELLO: Hello from kernel module.
+% 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
+% echo \"$MOD_HELLO/parameters/$PARAM_HELLO: \$(cat /sys/module/$MOD_HELLO/parameters/$PARAM_HELLO)\"
+$MOD_HELLO/parameters/$PARAM_HELLO: Hello from livepatched module.
+% echo 0 > /sys/kernel/livepatch/$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
+% echo \"$MOD_HELLO/parameters/$PARAM_HELLO: \$(cat /sys/module/$MOD_HELLO/parameters/$PARAM_HELLO)\"
+$MOD_HELLO/parameters/$PARAM_HELLO: Hello from kernel module.
+% rmmod $MOD_HELLO"
+
+exit 0
@@ -6,6 +6,8 @@ obj-m += test_klp_atomic_replace.o \
test_klp_callbacks_demo.o \
test_klp_callbacks_demo2.o \
test_klp_callbacks_mod.o \
+ test_klp_extern.o \
+ test_klp_extern_hello.o \
test_klp_livepatch.o \
test_klp_state.o \
test_klp_state2.o \
new file mode 100644
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2024 Lukas Hruska <lhruska@suse.cz>
+
+#define pr_fmt(fmt) "test_klp_extern_hello: " fmt
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/livepatch.h>
+
+extern const char *hello_msg \
+ KLP_RELOC_SYMBOL(test_klp_extern_hello, test_klp_extern_hello, hello_msg);
+
+static int hello_get(char *buffer, const struct kernel_param *kp)
+{
+ return sysfs_emit(buffer, "%s livepatched module.\n", hello_msg);
+}
+
+static struct klp_func funcs[] = {
+ {
+ .old_name = "hello_get",
+ .new_func = hello_get,
+ }, { }
+};
+
+static struct klp_object objs[] = {
+ {
+ .name = "test_klp_extern_hello",
+ .funcs = funcs,
+ }, { }
+};
+
+static struct klp_patch patch = {
+ .mod = THIS_MODULE,
+ .objs = objs,
+};
+
+static int test_klp_extern_init(void)
+{
+ return klp_enable_patch(&patch);
+}
+
+static void test_klp_extern_exit(void)
+{
+}
+
+module_init(test_klp_extern_init);
+module_exit(test_klp_extern_exit);
+MODULE_LICENSE("GPL");
+MODULE_INFO(livepatch, "Y");
+MODULE_AUTHOR("Lukas Hruska <lhruska@suse.cz>");
+MODULE_DESCRIPTION("Livepatch test: external symbol relocation");
new file mode 100644
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2024 Lukas Hruska <lhruska@suse.cz>
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+const char *hello_msg = "Hello from";
+
+static int hello_get(char *buffer, const struct kernel_param *kp)
+{
+ return sysfs_emit(buffer, "%s kernel module.\n", hello_msg);
+}
+
+static const struct kernel_param_ops hello_ops = {
+ .get = hello_get,
+};
+
+module_param_cb(hello, &hello_ops, NULL, 0400);
+MODULE_PARM_DESC(hello, "Read only parameter greeting the reader.");
+
+static int test_klp_extern_hello_init(void)
+{
+ return 0;
+}
+
+static void test_klp_extern_hello_exit(void)
+{
+}
+
+module_init(test_klp_extern_hello_init);
+module_exit(test_klp_extern_hello_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Lukas Hruska <lhruska@suse.cz>");
+MODULE_DESCRIPTION("Livepatch test: external symbol relocation - test module");