Live Patching
 help / color / mirror / Atom feed
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 8/9] selftests: livepatch: Add test for state ID conflict across provides
Date: Sun,  9 Aug 2026 17:19:52 +0800	[thread overview]
Message-ID: <20260809091954.22930-9-laoar.shao@gmail.com> (raw)
In-Reply-To: <20260809091954.22930-1-laoar.shao@gmail.com>

Livepatches with different provides ids must not share the same state
id. If a second livepatch attempts to reuse a state id already
registered by a livepatch with a different provides id, the loading
will fail. However, if the second livepatch's obsoletes list includes
the first livepatch's provides id, the second livepatch replaces the
first one and may reuse the same state id.

Add provides and obsoletes module parameters to test_klp_state.c and
test_klp_state2.c (guarded by #ifndef KLP_HAS_REPLACE) so that they
can be loaded with different provides ids and obsoletes ids.

Add a "state id conflict across provides" test scenario to
test-provides.sh:

  - Load test_klp_state with provides=1, which registers state ID 1.
  - Attempt to load test_klp_state2 with provides=2, which reuses the
    same state ID 1. The second livepatch is rejected because
    livepatches with different provides ids must not share the same
    state id.
  - Disable and unload the remaining livepatch.

Add a "taking over system state via obsoletes" test scenario to
test-state.sh:

  - Load test_klp_state with provides=10, which registers state ID 1.
  - Load test_klp_state2 with provides=20 obsoletes=10, which reuses the
    same state ID 1. Although the provides ids differ, the second livepatch
    replaces the first one because its obsoletes list includes the first
    livepatch's provides id (10). The state is taken over successfully.
  - Unload the replaced livepatch, then disable and unload the second
    livepatch.

Assisted-by: Comagic:DeepSeek-V4-Flash
Signed-off-by: Yafang Shao <laoar.shao@gmail.com>
---
 .../livepatch/test-provides-obsoletes.sh      | 86 +++++++++++++++++++
 .../livepatch/test_modules/test_klp_state.c   |  9 ++
 .../livepatch/test_modules/test_klp_state2.c  | 19 ++++
 3 files changed, 114 insertions(+)

diff --git a/tools/testing/selftests/livepatch/test-provides-obsoletes.sh b/tools/testing/selftests/livepatch/test-provides-obsoletes.sh
index c740d463f556..1b2c73bdd50b 100755
--- a/tools/testing/selftests/livepatch/test-provides-obsoletes.sh
+++ b/tools/testing/selftests/livepatch/test-provides-obsoletes.sh
@@ -6,6 +6,8 @@
 
 MOD_ATOMIC=test_klp_atomic_replace
 MOD_LIVEPATCH=test_klp_livepatch
+MOD_STATE=test_klp_state
+MOD_STATE2=test_klp_state2
 
 setup_config
 
@@ -192,4 +194,88 @@ livepatch: '$MOD_ATOMIC': completing unpatching transition
 livepatch: '$MOD_ATOMIC': unpatching complete
 % rmmod $MOD_ATOMIC"
 
+# - load a livepatch with provides=1 that registers state ID 1
+# - try to load another livepatch with provides=2 that reuses the same
+#   state ID. The second one must be rejected because livepatches with
+#   different provides ids must not share the same state id.
+# - disable and unload the remaining livepatch
+
+start_test "state id conflict across provides"
+
+load_lp $MOD_STATE provides=1
+load_failing_mod $MOD_STATE2 provides=2
+
+disable_lp $MOD_STATE
+unload_lp $MOD_STATE
+
+check_result "% insmod test_modules/$MOD_STATE.ko provides=1
+livepatch: enabling patch '$MOD_STATE'
+livepatch: '$MOD_STATE': initializing patching transition
+$MOD_STATE: pre_patch_callback: vmlinux
+$MOD_STATE: allocate_loglevel_state: allocating space to store console_loglevel
+livepatch: '$MOD_STATE': starting patching transition
+livepatch: '$MOD_STATE': completing patching transition
+$MOD_STATE: post_patch_callback: vmlinux
+$MOD_STATE: fix_console_loglevel: fixing console_loglevel
+livepatch: '$MOD_STATE': patching complete
+% insmod test_modules/$MOD_STATE2.ko provides=2
+livepatch: Livepatch patch ($MOD_STATE2) is not compatible with the already installed livepatches.
+insmod: ERROR: could not insert module test_modules/$MOD_STATE2.ko: Invalid parameters
+% echo 0 > $SYSFS_KLP_DIR/$MOD_STATE/enabled
+livepatch: '$MOD_STATE': initializing unpatching transition
+$MOD_STATE: pre_unpatch_callback: vmlinux
+$MOD_STATE: restore_console_loglevel: restoring console_loglevel
+livepatch: '$MOD_STATE': starting unpatching transition
+livepatch: '$MOD_STATE': completing unpatching transition
+$MOD_STATE: post_unpatch_callback: vmlinux
+$MOD_STATE: free_loglevel_state: freeing space for the stored console_loglevel
+livepatch: '$MOD_STATE': unpatching complete
+% rmmod $MOD_STATE"
+
+
+# Take over system state change by a patch that obsoletes the old one.
+# Although the provides IDs are different, the second patch's obsoletes
+# list includes the first patch's provides ID, so it can replace the
+# first patch and reuse the same state ID.
+
+start_test "taking over system state via obsoletes"
+
+load_lp $MOD_STATE provides=10
+load_lp $MOD_STATE2 provides=20 obsoletes=10
+unload_lp $MOD_STATE
+disable_lp $MOD_STATE2
+unload_lp $MOD_STATE2
+
+check_result "% insmod test_modules/$MOD_STATE.ko provides=10
+livepatch: enabling patch '$MOD_STATE'
+livepatch: '$MOD_STATE': initializing patching transition
+$MOD_STATE: pre_patch_callback: vmlinux
+$MOD_STATE: allocate_loglevel_state: allocating space to store console_loglevel
+livepatch: '$MOD_STATE': starting patching transition
+livepatch: '$MOD_STATE': completing patching transition
+$MOD_STATE: post_patch_callback: vmlinux
+$MOD_STATE: fix_console_loglevel: fixing console_loglevel
+livepatch: '$MOD_STATE': patching complete
+% insmod test_modules/$MOD_STATE2.ko provides=20 obsoletes=10
+livepatch: enabling patch '$MOD_STATE2'
+livepatch: '$MOD_STATE2': initializing patching transition
+$MOD_STATE2: pre_patch_callback: vmlinux
+$MOD_STATE2: allocate_loglevel_state: space to store console_loglevel already allocated
+livepatch: '$MOD_STATE2': starting patching transition
+livepatch: '$MOD_STATE2': completing patching transition
+$MOD_STATE2: post_patch_callback: vmlinux
+$MOD_STATE2: fix_console_loglevel: taking over the console_loglevel change
+livepatch: '$MOD_STATE2': patching complete
+% rmmod $MOD_STATE
+% echo 0 > $SYSFS_KLP_DIR/$MOD_STATE2/enabled
+livepatch: '$MOD_STATE2': initializing unpatching transition
+$MOD_STATE2: pre_unpatch_callback: vmlinux
+$MOD_STATE2: restore_console_loglevel: restoring console_loglevel
+livepatch: '$MOD_STATE2': starting unpatching transition
+livepatch: '$MOD_STATE2': completing unpatching transition
+$MOD_STATE2: post_unpatch_callback: vmlinux
+$MOD_STATE2: free_loglevel_state: freeing space for the stored console_loglevel
+livepatch: '$MOD_STATE2': unpatching complete
+% rmmod $MOD_STATE2"
+
 exit 0
diff --git a/tools/testing/selftests/livepatch/test_modules/test_klp_state.c b/tools/testing/selftests/livepatch/test_modules/test_klp_state.c
index 313401a5506e..77a5511d9d69 100644
--- a/tools/testing/selftests/livepatch/test_modules/test_klp_state.c
+++ b/tools/testing/selftests/livepatch/test_modules/test_klp_state.c
@@ -9,6 +9,12 @@
 #include <linux/printk.h>
 #include <linux/livepatch.h>
 
+#ifndef KLP_HAS_REPLACE
+static unsigned int provides;
+module_param(provides, uint, 0644);
+MODULE_PARM_DESC(provides, "provides id (default=0)");
+#endif
+
 #define CONSOLE_LOGLEVEL_STATE 1
 /* Version 1 does not support migration. */
 #define CONSOLE_LOGLEVEL_STATE_VERSION 1
@@ -151,6 +157,9 @@ static struct klp_patch patch = {
 
 static int test_klp_callbacks_demo_init(void)
 {
+#ifndef KLP_HAS_REPLACE
+	patch.provides = provides;
+#endif
 	return klp_enable_patch(&patch);
 }
 
diff --git a/tools/testing/selftests/livepatch/test_modules/test_klp_state2.c b/tools/testing/selftests/livepatch/test_modules/test_klp_state2.c
index 1afc2cabc39d..53ff6e793952 100644
--- a/tools/testing/selftests/livepatch/test_modules/test_klp_state2.c
+++ b/tools/testing/selftests/livepatch/test_modules/test_klp_state2.c
@@ -9,6 +9,18 @@
 #include <linux/printk.h>
 #include <linux/livepatch.h>
 
+#ifndef KLP_HAS_REPLACE
+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
+
 #define CONSOLE_LOGLEVEL_STATE 1
 /* Version 2 supports migration. */
 #define CONSOLE_LOGLEVEL_STATE_VERSION 2
@@ -180,6 +192,13 @@ static struct klp_patch patch = {
 
 static int test_klp_callbacks_demo_init(void)
 {
+#ifndef KLP_HAS_REPLACE
+	patch.provides = provides;
+	if (nr_obsoletes > 0) {
+		patch.obsoletes = obsoletes;
+		patch.nr_obsoletes = nr_obsoletes;
+	}
+#endif
 	return klp_enable_patch(&patch);
 }
 
-- 
2.52.0


  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 ` Yafang Shao [this message]
2026-08-09  9:19 ` [PATCH v5 9/9] selftests: livepatch: Add test for function conflict across provides Yafang Shao
2026-08-09  9:49   ` 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-9-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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox