From: Yafang Shao <laoar.shao@gmail.com>
To: jpoimboe@kernel.org, jikos@kernel.org, mbenes@suse.cz,
pmladek@suse.com, joe.lawrence@redhat.com, song@kernel.org
Cc: live-patching@vger.kernel.org, Yafang Shao <laoar.shao@gmail.com>
Subject: [PATCH v5 9/9] selftests: livepatch: Add test for function conflict across provides
Date: Sun, 9 Aug 2026 17:19:53 +0800 [thread overview]
Message-ID: <20260809091954.22930-10-laoar.shao@gmail.com> (raw)
In-Reply-To: <20260809091954.22930-1-laoar.shao@gmail.com>
Livepatches with different provides ids must not modify the same
function. If a second livepatch attempts to modify a function that
has already been modified by a loaded livepatch with a different
provides id, the loading will fail. If the second livepatch shares
the same provides id, or if its obsoletes list contains the first
livepatch's provides id, it will load successfully and replace the
first one.
Add a new test module test_klp_provides.c that patches meminfo_proc_show
(the same function as test_klp_atomic_replace) so that the two modules
can be loaded with different provides ids to test the function conflict
detection.
Add three test scenarios to test-provides.sh:
1. Function conflict across provides: load test_klp_atomic_replace with
provides=1, then attempt to load test_klp_provides with provides=2.
The second livepatch is rejected because livepatches with different
provides ids and no obsoletes must not modify the same function.
2. Function replace within same provides: load test_klp_atomic_replace
with provides=1, then load test_klp_provides with provides=1. The
second livepatch loads successfully and replaces the first one
because they share the same provides id.
3. Function replace across provides with obsoletes: load
test_klp_atomic_replace with provides=1, then load test_klp_provides
with provides=2 and obsoletes=[1]. The second livepatch loads
successfully and replaces the first one because the obsoletes list
allows it to replace a livepatch with a different provides id.
Assisted-by: Comagic:DeepSeek-V4-Flash
Signed-off-by: Yafang Shao <laoar.shao@gmail.com>
---
.../livepatch/test-provides-obsoletes.sh | 120 ++++++++++++++++++
.../selftests/livepatch/test_modules/Makefile | 1 +
.../test_modules/test_klp_provides.c | 72 +++++++++++
3 files changed, 193 insertions(+)
create mode 100644 tools/testing/selftests/livepatch/test_modules/test_klp_provides.c
diff --git a/tools/testing/selftests/livepatch/test-provides-obsoletes.sh b/tools/testing/selftests/livepatch/test-provides-obsoletes.sh
index 1b2c73bdd50b..32885625401d 100755
--- a/tools/testing/selftests/livepatch/test-provides-obsoletes.sh
+++ b/tools/testing/selftests/livepatch/test-provides-obsoletes.sh
@@ -8,6 +8,7 @@ MOD_ATOMIC=test_klp_atomic_replace
MOD_LIVEPATCH=test_klp_livepatch
MOD_STATE=test_klp_state
MOD_STATE2=test_klp_state2
+MOD_PROVIDES=test_klp_provides
setup_config
@@ -278,4 +279,123 @@ $MOD_STATE2: free_loglevel_state: freeing space for the stored console_loglevel
livepatch: '$MOD_STATE2': unpatching complete
% rmmod $MOD_STATE2"
+
+# - load a livepatch with provides=1 that modifies meminfo_proc_show
+# - try to load another livepatch with provides=2 that modifies the
+# same function. The second one must be rejected because livepatches
+# with different provides ids and no obsoletes must not modify
+# the same function.
+# - disable and unload the remaining livepatch
+
+start_test "function conflict across provides"
+
+load_lp $MOD_ATOMIC provides=1
+load_failing_mod $MOD_PROVIDES provides=2
+
+disable_lp $MOD_ATOMIC
+unload_lp $MOD_ATOMIC
+
+check_result "% insmod test_modules/$MOD_ATOMIC.ko provides=1
+livepatch: enabling patch '$MOD_ATOMIC'
+livepatch: '$MOD_ATOMIC': initializing patching transition
+livepatch: '$MOD_ATOMIC': starting patching transition
+livepatch: '$MOD_ATOMIC': completing patching transition
+livepatch: '$MOD_ATOMIC': patching complete
+% insmod test_modules/$MOD_PROVIDES.ko provides=2
+livepatch: Livepatch patch ($MOD_PROVIDES) is not compatible with the already installed livepatches.
+insmod: ERROR: could not insert module test_modules/$MOD_PROVIDES.ko: Invalid parameters
+% echo 0 > $SYSFS_KLP_DIR/$MOD_ATOMIC/enabled
+livepatch: '$MOD_ATOMIC': initializing unpatching transition
+livepatch: '$MOD_ATOMIC': starting unpatching transition
+livepatch: '$MOD_ATOMIC': completing unpatching transition
+livepatch: '$MOD_ATOMIC': unpatching complete
+% rmmod $MOD_ATOMIC"
+
+
+# - load a livepatch with provides=1 that modifies meminfo_proc_show
+# - load another livepatch with provides=1 that modifies the same
+# function. The second one loads successfully because livepatches
+# with the same provides id replace each other.
+# - disable and unload the remaining livepatch
+
+start_test "function replace within same provides"
+
+load_lp $MOD_ATOMIC provides=1
+load_lp $MOD_PROVIDES provides=1
+
+mods=($SYSFS_KLP_DIR/*)
+nmods=${#mods[@]}
+if [[ "$nmods" -ne 1 ]]; then
+ die "Expecting one module listed, found $nmods"
+fi
+check_sysfs_value "$MOD_PROVIDES" "enabled" "1"
+
+disable_lp $MOD_PROVIDES
+unload_lp $MOD_PROVIDES
+unload_lp $MOD_ATOMIC
+
+check_result "% insmod test_modules/$MOD_ATOMIC.ko provides=1
+livepatch: enabling patch '$MOD_ATOMIC'
+livepatch: '$MOD_ATOMIC': initializing patching transition
+livepatch: '$MOD_ATOMIC': starting patching transition
+livepatch: '$MOD_ATOMIC': completing patching transition
+livepatch: '$MOD_ATOMIC': patching complete
+% insmod test_modules/$MOD_PROVIDES.ko provides=1
+livepatch: enabling patch '$MOD_PROVIDES'
+livepatch: '$MOD_PROVIDES': initializing patching transition
+livepatch: '$MOD_PROVIDES': starting patching transition
+livepatch: '$MOD_PROVIDES': completing patching transition
+livepatch: '$MOD_PROVIDES': patching complete
+% echo 0 > $SYSFS_KLP_DIR/$MOD_PROVIDES/enabled
+livepatch: '$MOD_PROVIDES': initializing unpatching transition
+livepatch: '$MOD_PROVIDES': starting unpatching transition
+livepatch: '$MOD_PROVIDES': completing unpatching transition
+livepatch: '$MOD_PROVIDES': unpatching complete
+% rmmod $MOD_PROVIDES
+% rmmod $MOD_ATOMIC"
+
+
+# - load a livepatch with provides=1 that modifies meminfo_proc_show
+# - load another livepatch with provides=2 and obsoletes=[1] that
+# modifies the same function. The second one loads successfully
+# because the obsoletes list allows it to replace the first one
+# even though they have different provides ids.
+# - disable and unload the remaining livepatch
+
+start_test "function replace across provides with obsoletes"
+
+load_lp $MOD_ATOMIC provides=1
+load_lp $MOD_PROVIDES provides=2 obsoletes=1
+
+mods=($SYSFS_KLP_DIR/*)
+nmods=${#mods[@]}
+if [[ "$nmods" -ne 1 ]]; then
+ die "Expecting one module listed, found $nmods"
+fi
+check_sysfs_value "$MOD_PROVIDES" "enabled" "1"
+
+disable_lp $MOD_PROVIDES
+unload_lp $MOD_PROVIDES
+unload_lp $MOD_ATOMIC
+
+check_result "% insmod test_modules/$MOD_ATOMIC.ko provides=1
+livepatch: enabling patch '$MOD_ATOMIC'
+livepatch: '$MOD_ATOMIC': initializing patching transition
+livepatch: '$MOD_ATOMIC': starting patching transition
+livepatch: '$MOD_ATOMIC': completing patching transition
+livepatch: '$MOD_ATOMIC': patching complete
+% insmod test_modules/$MOD_PROVIDES.ko provides=2 obsoletes=1
+livepatch: enabling patch '$MOD_PROVIDES'
+livepatch: '$MOD_PROVIDES': initializing patching transition
+livepatch: '$MOD_PROVIDES': starting patching transition
+livepatch: '$MOD_PROVIDES': completing patching transition
+livepatch: '$MOD_PROVIDES': patching complete
+% echo 0 > $SYSFS_KLP_DIR/$MOD_PROVIDES/enabled
+livepatch: '$MOD_PROVIDES': initializing unpatching transition
+livepatch: '$MOD_PROVIDES': starting unpatching transition
+livepatch: '$MOD_PROVIDES': completing unpatching transition
+livepatch: '$MOD_PROVIDES': unpatching complete
+% rmmod $MOD_PROVIDES
+% rmmod $MOD_ATOMIC"
+
exit 0
diff --git a/tools/testing/selftests/livepatch/test_modules/Makefile b/tools/testing/selftests/livepatch/test_modules/Makefile
index 29c55df36046..9f5ea09c55f7 100644
--- a/tools/testing/selftests/livepatch/test_modules/Makefile
+++ b/tools/testing/selftests/livepatch/test_modules/Makefile
@@ -10,6 +10,7 @@ obj-m += test_klp_atomic_replace.o \
test_klp_livepatch.o \
test_klp_mod_patch.o \
test_klp_mod_target.o \
+ test_klp_provides.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_provides.c b/tools/testing/selftests/livepatch/test_modules/test_klp_provides.c
new file mode 100644
index 000000000000..9751a6f6c851
--- /dev/null
+++ b/tools/testing/selftests/livepatch/test_modules/test_klp_provides.c
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/livepatch.h>
+
+#ifdef KLP_HAS_REPLACE
+static int replace;
+module_param(replace, int, 0644);
+MODULE_PARM_DESC(replace, "replace (default=0)");
+#else
+static unsigned int provides;
+module_param(provides, uint, 0644);
+MODULE_PARM_DESC(provides, "provides id (default=0)");
+
+#define KLP_MAX_OBSOLETES 16
+static unsigned int obsoletes[KLP_MAX_OBSOLETES];
+static int nr_obsoletes;
+module_param_array(obsoletes, uint, &nr_obsoletes, 0644);
+MODULE_PARM_DESC(obsoletes, "obsoletes provides ids");
+#endif
+
+#include <linux/seq_file.h>
+static int livepatch_meminfo_proc_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 = "meminfo_proc_show",
+ .new_func = livepatch_meminfo_proc_show,
+ }, {}
+};
+
+static struct klp_object objs[] = {
+ {
+ /* name being NULL means vmlinux */
+ .funcs = funcs,
+ }, {}
+};
+
+static struct klp_patch patch = {
+ .mod = THIS_MODULE,
+ .objs = objs,
+};
+
+static int test_klp_provides_init(void)
+{
+#ifdef KLP_HAS_REPLACE
+ patch.replace = replace;
+#else
+ patch.provides = provides;
+ if (nr_obsoletes > 0) {
+ patch.obsoletes = obsoletes;
+ patch.nr_obsoletes = nr_obsoletes;
+ }
+#endif
+ return klp_enable_patch(&patch);
+}
+
+static void test_klp_provides_exit(void)
+{
+}
+
+module_init(test_klp_provides_init);
+module_exit(test_klp_provides_exit);
+MODULE_LICENSE("GPL");
+MODULE_INFO(livepatch, "Y");
+MODULE_DESCRIPTION("Livepatch test: provides conflict");
--
2.52.0
next prev parent reply other threads:[~2026-08-09 9:20 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-09 9:19 [PATCH v5 0/9] livepatch: Introduce replace set support Yafang Shao
2026-08-09 9:19 ` [PATCH v5 1/9] livepatch: Fix wrong index in funcs cleanup error path Yafang Shao
2026-08-09 9:28 ` sashiko-bot
2026-08-09 9:36 ` Yafang Shao
2026-08-09 9:19 ` [PATCH v5 2/9] livepatch: Make klp_find_func() non static Yafang Shao
2026-08-09 9:32 ` sashiko-bot
2026-08-09 9:39 ` Yafang Shao
2026-08-09 9:19 ` [PATCH v5 3/9] livepatch: Call klp_init_patch_early() earlier Yafang Shao
2026-08-09 9:40 ` sashiko-bot
2026-08-09 9:19 ` [PATCH v5 4/9] livepatch: Implement replace set for scoped atomic replace Yafang Shao
2026-08-09 9:33 ` sashiko-bot
2026-08-09 9:19 ` [PATCH v5 5/9] livepatch: Deprecate stack_order Yafang Shao
2026-08-09 9:19 ` [PATCH v5 6/9] selftests: livepatch: Adapt atomic replace tests to provides/obsoletes Yafang Shao
2026-08-09 9:33 ` sashiko-bot
2026-08-09 9:45 ` Yafang Shao
2026-08-09 9:19 ` [PATCH v5 7/9] selftests: livepatch: Add provides/obsoletes test scenarios Yafang Shao
2026-08-09 9:31 ` sashiko-bot
2026-08-09 9:19 ` [PATCH v5 8/9] selftests: livepatch: Add test for state ID conflict across provides Yafang Shao
2026-08-09 9:19 ` Yafang Shao [this message]
2026-08-09 9:49 ` [PATCH v5 9/9] selftests: livepatch: Add test for function " sashiko-bot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260809091954.22930-10-laoar.shao@gmail.com \
--to=laoar.shao@gmail.com \
--cc=jikos@kernel.org \
--cc=joe.lawrence@redhat.com \
--cc=jpoimboe@kernel.org \
--cc=live-patching@vger.kernel.org \
--cc=mbenes@suse.cz \
--cc=pmladek@suse.com \
--cc=song@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.