* [PATCH v2 1/4] livepatch: Make klp_find_func() non-static
2026-05-29 3:45 [PATCH v2 0/4] livepatch: Introduce replace set support Yafang Shao
@ 2026-05-29 3:45 ` Yafang Shao
2026-05-29 4:01 ` sashiko-bot
2026-05-29 3:45 ` [PATCH v2 2/4] livepatch: Support scoped atomic replace using replace_set Yafang Shao
` (2 subsequent siblings)
3 siblings, 1 reply; 13+ messages in thread
From: Yafang Shao @ 2026-05-29 3:45 UTC (permalink / raw)
To: jpoimboe, jikos, mbenes, pmladek, joe.lawrence, song
Cc: live-patching, Yafang Shao
Move klp_find_func() out of the static scope to make it available
outside of core.c. It will be reused by the upcoming patch.
Signed-off-by: Yafang Shao <laoar.shao@gmail.com>
---
include/linux/livepatch.h | 4 ++++
kernel/livepatch/core.c | 4 ++--
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/include/linux/livepatch.h b/include/linux/livepatch.h
index ba9e3988c07c..70854f542c33 100644
--- a/include/linux/livepatch.h
+++ b/include/linux/livepatch.h
@@ -215,6 +215,10 @@ int klp_apply_section_relocs(struct module *pmod, Elf_Shdr *sechdrs,
unsigned int symindex, unsigned int secindex,
const char *objname);
+struct klp_func *klp_find_func(struct klp_object *obj,
+ struct klp_func *old_func);
+
+
#else /* !CONFIG_LIVEPATCH */
static inline int klp_module_coming(struct module *mod) { return 0; }
diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c
index 28d15ba58a26..e97df3e59057 100644
--- a/kernel/livepatch/core.c
+++ b/kernel/livepatch/core.c
@@ -82,8 +82,8 @@ static bool klp_initialized(void)
return !!klp_root_kobj;
}
-static struct klp_func *klp_find_func(struct klp_object *obj,
- struct klp_func *old_func)
+struct klp_func *klp_find_func(struct klp_object *obj,
+ struct klp_func *old_func)
{
struct klp_func *func;
--
2.47.3
^ permalink raw reply related [flat|nested] 13+ messages in thread* Re: [PATCH v2 1/4] livepatch: Make klp_find_func() non-static
2026-05-29 3:45 ` [PATCH v2 1/4] livepatch: Make klp_find_func() non-static Yafang Shao
@ 2026-05-29 4:01 ` sashiko-bot
2026-05-29 9:07 ` Yafang Shao
0 siblings, 1 reply; 13+ messages in thread
From: sashiko-bot @ 2026-05-29 4:01 UTC (permalink / raw)
To: jikos, joe.lawrence, song, mbenes, jpoimboe, pmladek
Cc: live-patching, Yafang Shao
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
New issues:
- [Low] klp_find_func() is improperly exposed in the global public header, breaking encapsulation and introducing potential build/linkage errors.
Pre-existing issues:
- [High] klp_find_func() lacks input validation, exacerbating a pre-existing NULL pointer dereference vulnerability during livepatch loading.
--
commit 0b93025e6e1dd48057bb98e4d5e13741daab118e
Author: Yafang Shao <laoar.shao@gmail.com>
livepatch: Make klp_find_func() non-static
This commit exposes klp_find_func() by moving it out of the static scope
to make it available outside of core.c for reuse in upcoming patches.
> diff --git a/include/linux/livepatch.h b/include/linux/livepatch.h
> index ba9e3988c07c3..70854f542c33e 100644
> --- a/include/linux/livepatch.h
> +++ b/include/linux/livepatch.h
> @@ -215,6 +215,10 @@ int klp_apply_section_relocs(struct module *pmod, Elf_Shdr *sechdrs,
> unsigned int symindex, unsigned int secindex,
> const char *objname);
>
> +struct klp_func *klp_find_func(struct klp_object *obj,
> + struct klp_func *old_func);
> +
[Severity: Low]
Does this declaration belong in kernel/livepatch/core.h instead? It lacks
an EXPORT_SYMBOL_GPL() and a stub for when !CONFIG_LIVEPATCH is set.
[ ... ]
> diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c
> index 28d15ba58a26d..e97df3e59057b 100644
> --- a/kernel/livepatch/core.c
> +++ b/kernel/livepatch/core.c
> @@ -82,8 +82,8 @@ static bool klp_initialized(void)
> return !!klp_root_kobj;
> }
>
> -static struct klp_func *klp_find_func(struct klp_object *obj,
> - struct klp_func *old_func)
> +struct klp_func *klp_find_func(struct klp_object *obj,
> + struct klp_func *old_func)
> {
> struct klp_func *func;
[Severity: High]
This is a pre-existing issue, but does this function dereference a NULL
pointer if old_name is NULL?
If a newly loaded livepatch provides a function entry with a NULL old_name,
func->old_name will be NULL when evaluated in strcmp():
klp_init_patch()
klp_add_nops()
klp_find_func()
strcmp(old_func->old_name, func->old_name)
Could a check be added for NULL before calling strcmp()?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260529034542.68766-1-laoar.shao@gmail.com?part=1
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: [PATCH v2 1/4] livepatch: Make klp_find_func() non-static
2026-05-29 4:01 ` sashiko-bot
@ 2026-05-29 9:07 ` Yafang Shao
0 siblings, 0 replies; 13+ messages in thread
From: Yafang Shao @ 2026-05-29 9:07 UTC (permalink / raw)
To: sashiko-reviews
Cc: jikos, joe.lawrence, song, mbenes, jpoimboe, pmladek,
live-patching
On Fri, May 29, 2026 at 12:01 PM <sashiko-bot@kernel.org> wrote:
>
> Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
>
> New issues:
> - [Low] klp_find_func() is improperly exposed in the global public header, breaking encapsulation and introducing potential build/linkage errors.
I will update it.
>
> Pre-existing issues:
> - [High] klp_find_func() lacks input validation, exacerbating a pre-existing NULL pointer dereference vulnerability during livepatch loading.
Valid. will fix this issue.
--
Regards
Yafang
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH v2 2/4] livepatch: Support scoped atomic replace using replace_set
2026-05-29 3:45 [PATCH v2 0/4] livepatch: Introduce replace set support Yafang Shao
2026-05-29 3:45 ` [PATCH v2 1/4] livepatch: Make klp_find_func() non-static Yafang Shao
@ 2026-05-29 3:45 ` Yafang Shao
2026-05-29 4:32 ` sashiko-bot
2026-05-29 3:45 ` [PATCH v2 3/4] livepatch: deprecate stack_order Yafang Shao
2026-05-29 3:45 ` [PATCH v2 4/4] selftests/livepatch: Update tests for replace_set Yafang Shao
3 siblings, 1 reply; 13+ messages in thread
From: Yafang Shao @ 2026-05-29 3:45 UTC (permalink / raw)
To: jpoimboe, jikos, mbenes, pmladek, joe.lawrence, song
Cc: live-patching, Yafang Shao
Convert the replace attribute from a boolean to a u32 to function as a
"replace set." A newly loaded livepatch will now atomically replace any
existing patch belonging to the same set. There can only ever be one active
livepatch for a given replace_set number.
This change currently supports function replacement only. Livepatches that
belong to different replace sets cannot modify the same function. If a new
livepatch attempts to modify a function already modified by an older
livepatch from a different replace_set, the loading of the new livepatch
will be refused.
Similarly, for the KLP state, livepatches belonging to different replace
sets cannot use the same state ID. The system will refuse to load a new
livepatch if it uses a state ID already in use by an older livepatch from
a different replace_set.
For the KLP shadow variable mechanism, developers must assign unique shadow
IDs to livepatches that belong to different replace sets.
Support for replace_set compatibility with KLP state and shadow variables
will be implemented after Petr's KLP state transfer work is completed [0].
Other user-visible changes include:
- The non-replace model is now deprecated
- /sys/kernel/livepatch/livepatch_XXX/replace attribute is replaced by
/sys/kernel/livepatch/livepatch_XXX/replace_set
Link: https://github.com/pmladek/linux/tree/klp-state-transfer-v1-iter12 [0]
Suggested-by: Song Liu <song@kernel.org>
Suggested-by: Petr Mladek <pmladek@suse.com>
Signed-off-by: Yafang Shao <laoar.shao@gmail.com>
---
.../ABI/testing/sysfs-kernel-livepatch | 5 +-
.../livepatch/cumulative-patches.rst | 23 ++++++---
Documentation/livepatch/livepatch.rst | 21 ++++----
include/linux/livepatch.h | 6 +--
kernel/livepatch/core.c | 24 +++++----
kernel/livepatch/state.c | 51 +++++++++++++++----
kernel/livepatch/transition.c | 11 ++--
scripts/livepatch/init.c | 6 +--
scripts/livepatch/klp-build | 16 +++---
9 files changed, 104 insertions(+), 59 deletions(-)
diff --git a/Documentation/ABI/testing/sysfs-kernel-livepatch b/Documentation/ABI/testing/sysfs-kernel-livepatch
index 3c3f36b32b57..6d75235a6a2e 100644
--- a/Documentation/ABI/testing/sysfs-kernel-livepatch
+++ b/Documentation/ABI/testing/sysfs-kernel-livepatch
@@ -47,13 +47,12 @@ Description:
disabled when the feature is used. See
Documentation/livepatch/livepatch.rst for more information.
-What: /sys/kernel/livepatch/<patch>/replace
+What: /sys/kernel/livepatch/<patch>/replace_set
Date: Jun 2024
KernelVersion: 6.11.0
Contact: live-patching@vger.kernel.org
Description:
- An attribute which indicates whether the patch supports
- atomic-replace.
+ An attribute to show the replace_set of this livepatch.
What: /sys/kernel/livepatch/<patch>/stack_order
Date: Jan 2025
diff --git a/Documentation/livepatch/cumulative-patches.rst b/Documentation/livepatch/cumulative-patches.rst
index 1931f318976a..0361adb12f6d 100644
--- a/Documentation/livepatch/cumulative-patches.rst
+++ b/Documentation/livepatch/cumulative-patches.rst
@@ -17,18 +17,20 @@ from all older livepatches and completely replace them in one transition.
Usage
-----
-The atomic replace can be enabled by setting "replace" flag in struct klp_patch,
-for example::
+The "replace_set" attribute in ``struct klp_patch`` acts as a **replace_set**,
+defining the scope of the replacement. By default, the replace_set is 0.
+
+For example::
static struct klp_patch patch = {
.mod = THIS_MODULE,
.objs = objs,
- .replace = true,
+ .replace_set = 0,
};
All processes are then migrated to use the code only from the new patch.
-Once the transition is finished, all older patches are automatically
-disabled.
+Once the transition is finished, all older patches with the same replace
+set are automatically disabled. Patches with different tags remain active.
Ftrace handlers are transparently removed from functions that are no
longer modified by the new cumulative patch.
@@ -62,9 +64,14 @@ Limitations:
------------
- Once the operation finishes, there is no straightforward way
- to reverse it and restore the replaced patches atomically.
-
- A good practice is to set .replace flag in any released livepatch.
+ to reverse it and restore the replaced patches (with the same set)
+ atomically.
+
+ A good practice is to use only one (default) "replace_set". It
+ makes sure that there always will be only one enabled livepatch
+ on the system. The consistency model will ensure a safe update
+ between two versions. It prevents potential problems with installing
+ two livepatches doing incompatible functional changes.
Then re-adding an older livepatch is equivalent to downgrading
to that patch. This is safe as long as the livepatches do _not_ do
extra modifications in (un)patching callbacks or in the module_init()
diff --git a/Documentation/livepatch/livepatch.rst b/Documentation/livepatch/livepatch.rst
index acb90164929e..221d8f1e91c4 100644
--- a/Documentation/livepatch/livepatch.rst
+++ b/Documentation/livepatch/livepatch.rst
@@ -347,15 +347,18 @@ to '0'.
5.3. Replacing
--------------
-All enabled patches might get replaced by a cumulative patch that
-has the .replace flag set.
-
-Once the new patch is enabled and the 'transition' finishes then
-all the functions (struct klp_func) associated with the replaced
-patches are removed from the corresponding struct klp_ops. Also
-the ftrace handler is unregistered and the struct klp_ops is
-freed when the related function is not modified by the new patch
-and func_stack list becomes empty.
+There always can be only one livepatch with a given "replace_set" number.
+They always replace each other.
+
+Once the transition is complete, all functions (``struct klp_func``)
+associated with the matching replaced patches are removed from the
+corresponding ``struct klp_ops``. If a function is no longer modified by
+the new patch and its ``func_stack`` list becomes empty, the ftrace
+handler is unregistered and the ``struct klp_ops`` is freed.
+
+Patches with a different replace set are not affected by this process
+and remain active. This allows for the independent management and
+stacking of multiple, non-conflicting livepatch sets.
See Documentation/livepatch/cumulative-patches.rst for more details.
diff --git a/include/linux/livepatch.h b/include/linux/livepatch.h
index 70854f542c33..ab8cb3f77891 100644
--- a/include/linux/livepatch.h
+++ b/include/linux/livepatch.h
@@ -123,7 +123,8 @@ struct klp_state {
* @mod: reference to the live patch module
* @objs: object entries for kernel objects to be patched
* @states: system states that can get modified
- * @replace: replace all actively used patches
+ * @replace_set:Livepatch using the same @replace_set will get atomically
+ * replaced.
* @list: list node for global list of actively used patches
* @kobj: kobject for sysfs resources
* @obj_list: dynamic list of the object entries
@@ -137,7 +138,7 @@ struct klp_patch {
struct module *mod;
struct klp_object *objs;
struct klp_state *states;
- bool replace;
+ unsigned int replace_set;
/* internal */
struct list_head list;
@@ -218,7 +219,6 @@ int klp_apply_section_relocs(struct module *pmod, Elf_Shdr *sechdrs,
struct klp_func *klp_find_func(struct klp_object *obj,
struct klp_func *old_func);
-
#else /* !CONFIG_LIVEPATCH */
static inline int klp_module_coming(struct module *mod) { return 0; }
diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c
index e97df3e59057..969fea2a9263 100644
--- a/kernel/livepatch/core.c
+++ b/kernel/livepatch/core.c
@@ -350,7 +350,7 @@ int klp_apply_section_relocs(struct module *pmod, Elf_Shdr *sechdrs,
* /sys/kernel/livepatch/<patch>/enabled
* /sys/kernel/livepatch/<patch>/transition
* /sys/kernel/livepatch/<patch>/force
- * /sys/kernel/livepatch/<patch>/replace
+ * /sys/kernel/livepatch/<patch>/replace_set
* /sys/kernel/livepatch/<patch>/stack_order
* /sys/kernel/livepatch/<patch>/<object>
* /sys/kernel/livepatch/<patch>/<object>/patched
@@ -448,13 +448,13 @@ static ssize_t force_store(struct kobject *kobj, struct kobj_attribute *attr,
return count;
}
-static ssize_t replace_show(struct kobject *kobj,
+static ssize_t replace_set_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
struct klp_patch *patch;
patch = container_of(kobj, struct klp_patch, kobj);
- return sysfs_emit(buf, "%d\n", patch->replace);
+ return sysfs_emit(buf, "%u\n", patch->replace_set);
}
static ssize_t stack_order_show(struct kobject *kobj,
@@ -481,13 +481,13 @@ static ssize_t stack_order_show(struct kobject *kobj,
static struct kobj_attribute enabled_kobj_attr = __ATTR_RW(enabled);
static struct kobj_attribute transition_kobj_attr = __ATTR_RO(transition);
static struct kobj_attribute force_kobj_attr = __ATTR_WO(force);
-static struct kobj_attribute replace_kobj_attr = __ATTR_RO(replace);
+static struct kobj_attribute replace_set_kobj_attr = __ATTR_RO(replace_set);
static struct kobj_attribute stack_order_kobj_attr = __ATTR_RO(stack_order);
static struct attribute *klp_patch_attrs[] = {
&enabled_kobj_attr.attr,
&transition_kobj_attr.attr,
&force_kobj_attr.attr,
- &replace_kobj_attr.attr,
+ &replace_set_kobj_attr.attr,
&stack_order_kobj_attr.attr,
NULL
};
@@ -621,6 +621,8 @@ static int klp_add_nops(struct klp_patch *patch)
klp_for_each_object(old_patch, old_obj) {
int err;
+ if (patch->replace_set != old_patch->replace_set)
+ continue;
err = klp_add_object_nops(patch, old_obj);
if (err)
return err;
@@ -793,6 +795,8 @@ void klp_free_replaced_patches_async(struct klp_patch *new_patch)
klp_for_each_patch_safe(old_patch, tmp_patch) {
if (old_patch == new_patch)
return;
+ if (old_patch->replace_set != new_patch->replace_set)
+ continue;
klp_free_patch_async(old_patch);
}
}
@@ -988,11 +992,9 @@ static int klp_init_patch(struct klp_patch *patch)
if (ret)
return ret;
- if (patch->replace) {
- ret = klp_add_nops(patch);
- if (ret)
- return ret;
- }
+ ret = klp_add_nops(patch);
+ if (ret)
+ return ret;
klp_for_each_object(patch, obj) {
ret = klp_init_object(patch, obj);
@@ -1195,6 +1197,8 @@ void klp_unpatch_replaced_patches(struct klp_patch *new_patch)
if (old_patch == new_patch)
return;
+ if (old_patch->replace_set != new_patch->replace_set)
+ continue;
old_patch->enabled = false;
klp_unpatch_objects(old_patch);
}
diff --git a/kernel/livepatch/state.c b/kernel/livepatch/state.c
index 2565d039ade0..a1ac46637336 100644
--- a/kernel/livepatch/state.c
+++ b/kernel/livepatch/state.c
@@ -85,34 +85,65 @@ EXPORT_SYMBOL_GPL(klp_get_prev_state);
/* Check if the patch is able to deal with the existing system state. */
static bool klp_is_state_compatible(struct klp_patch *patch,
+ struct klp_patch *old_patch,
struct klp_state *old_state)
{
struct klp_state *state;
state = klp_get_state(patch, old_state->id);
+ if (patch->replace_set == old_patch->replace_set) {
+ /*
+ * If the new livepatch shares a state set with an existing
+ * one, it must maintain compatibility with all states
+ * modified by the old patch.
+ */
+ if (!state)
+ return false;
+ return state->version >= old_state->version;
- /* A cumulative livepatch must handle all already modified states. */
- if (!state)
- return !patch->replace;
+ }
- return state->version >= old_state->version;
+ /*
+ * Two livepatches with a different "replace_set" must _not_ use
+ * the same "state->id.
+ */
+ return !state;
}
-/*
- * Check that the new livepatch will not break the existing system states.
- * Cumulative patches must handle all already modified states.
- * Non-cumulative patches can touch already modified states.
- */
+/* Check that the new livepatch will not break the existing system states. */
bool klp_is_patch_compatible(struct klp_patch *patch)
{
+ struct klp_object *obj, *old_obj;
struct klp_patch *old_patch;
struct klp_state *old_state;
+ struct klp_func *func;
klp_for_each_patch(old_patch) {
klp_for_each_state(old_patch, old_state) {
- if (!klp_is_state_compatible(patch, old_state))
+ if (!klp_is_state_compatible(patch, old_patch, old_state))
return false;
}
+
+ if (old_patch->replace_set == patch->replace_set)
+ continue;
+
+ /*
+ * Refuse loading a livepatch which would want to modify a
+ * function which is already livepatched with the livepatch
+ * with another "replace_set".
+ */
+ klp_for_each_object_static(patch, obj) {
+ klp_for_each_object(old_patch, old_obj) {
+ if (!!obj->name != !!old_obj->name)
+ continue;
+ if (obj->name && strcmp(obj->name, old_obj->name))
+ continue;
+ klp_for_each_func_static(obj, func) {
+ if (klp_find_func(old_obj, func))
+ return false;
+ }
+ }
+ }
}
return true;
diff --git a/kernel/livepatch/transition.c b/kernel/livepatch/transition.c
index 2351a19ac2a9..8b756dbaa57e 100644
--- a/kernel/livepatch/transition.c
+++ b/kernel/livepatch/transition.c
@@ -89,7 +89,7 @@ static void klp_complete_transition(void)
klp_transition_patch->mod->name,
klp_target_state == KLP_TRANSITION_PATCHED ? "patching" : "unpatching");
- if (klp_transition_patch->replace && klp_target_state == KLP_TRANSITION_PATCHED) {
+ if (klp_target_state == KLP_TRANSITION_PATCHED) {
klp_unpatch_replaced_patches(klp_transition_patch);
klp_discard_nops(klp_transition_patch);
}
@@ -498,7 +498,7 @@ void klp_try_complete_transition(void)
*/
if (!patch->enabled)
klp_free_patch_async(patch);
- else if (patch->replace)
+ else
klp_free_replaced_patches_async(patch);
}
@@ -720,11 +720,12 @@ void klp_force_transition(void)
klp_update_patch_state(idle_task(cpu));
/* Set forced flag for patches being removed. */
- if (klp_target_state == KLP_TRANSITION_UNPATCHED)
+ if (klp_target_state == KLP_TRANSITION_UNPATCHED) {
klp_transition_patch->forced = true;
- else if (klp_transition_patch->replace) {
+ } else {
klp_for_each_patch(patch) {
- if (patch != klp_transition_patch)
+ if (patch != klp_transition_patch &&
+ patch->replace_set == klp_transition_patch->replace_set)
patch->forced = true;
}
}
diff --git a/scripts/livepatch/init.c b/scripts/livepatch/init.c
index f14d8c8fb35f..df4fbcaf4c12 100644
--- a/scripts/livepatch/init.c
+++ b/scripts/livepatch/init.c
@@ -72,10 +72,10 @@ static int __init livepatch_mod_init(void)
/* TODO patch->states */
-#ifdef KLP_NO_REPLACE
- patch->replace = false;
+#ifdef KLP_REPLACE_SET
+ patch->replace_set = KLP_REPLACE_SET;
#else
- patch->replace = true;
+ patch->replace_set = 0;
#endif
return klp_enable_patch(patch);
diff --git a/scripts/livepatch/klp-build b/scripts/livepatch/klp-build
index 0ad7e6631314..1c6c1c4f3190 100755
--- a/scripts/livepatch/klp-build
+++ b/scripts/livepatch/klp-build
@@ -22,7 +22,7 @@ shopt -s lastpipe
unset DEBUG_CLONE DIFF_CHECKSUM SKIP_CLEANUP XTRACE
-REPLACE=1
+REPLACE_SET=0
SHORT_CIRCUIT=0
JOBS="$(getconf _NPROCESSORS_ONLN)"
VERBOSE="-s"
@@ -134,7 +134,7 @@ Options:
-f, --show-first-changed Show address of first changed instruction
-j, --jobs=<jobs> Build jobs to run simultaneously [default: $JOBS]
-o, --output=<file.ko> Output file [default: livepatch-<patch-name>.ko]
- --no-replace Disable livepatch atomic replace
+ -s, --replace-set=<set> Set the atomic replace set for this livepatch
-v, --verbose Pass V=1 to kernel/module builds
Advanced Options:
@@ -159,8 +159,8 @@ process_args() {
local long
local args
- short="hfj:o:vdS:T"
- long="help,show-first-changed,jobs:,output:,no-replace,verbose,debug,short-circuit:,keep-tmp"
+ short="hfj:o:s:vdS:T"
+ long="help,show-first-changed,jobs:,output:,replace-set:,verbose,debug,short-circuit:,keep-tmp"
args=$(getopt --options "$short" --longoptions "$long" -- "$@") || {
echo; usage; exit
@@ -189,9 +189,9 @@ process_args() {
NAME="$(module_name_string "$NAME")"
shift 2
;;
- --no-replace)
- REPLACE=0
- shift
+ -s | --replace-set)
+ REPLACE_SET="$2"
+ shift 2
;;
-v | --verbose)
VERBOSE="V=1"
@@ -777,7 +777,7 @@ build_patch_module() {
cflags=("-ffunction-sections")
cflags+=("-fdata-sections")
- [[ $REPLACE -eq 0 ]] && cflags+=("-DKLP_NO_REPLACE")
+ cflags+=("-DKLP_REPLACE_SET=$REPLACE_SET")
cmd=("make")
cmd+=("$VERBOSE")
--
2.47.3
^ permalink raw reply related [flat|nested] 13+ messages in thread* Re: [PATCH v2 2/4] livepatch: Support scoped atomic replace using replace_set
2026-05-29 3:45 ` [PATCH v2 2/4] livepatch: Support scoped atomic replace using replace_set Yafang Shao
@ 2026-05-29 4:32 ` sashiko-bot
2026-05-29 9:11 ` Yafang Shao
0 siblings, 1 reply; 13+ messages in thread
From: sashiko-bot @ 2026-05-29 4:32 UTC (permalink / raw)
To: jikos, pmladek, song, mbenes, jpoimboe, joe.lawrence
Cc: Yafang Shao, live-patching
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] A malformed livepatch module with a missing function `old_name` will cause a kernel panic during patch compatibility checking.
--
commit 48dd0b716d1f70f13c1e96b75bf54e1aba77be18
Author: Yafang Shao <laoar.shao@gmail.com>
livepatch: Support scoped atomic replace using replace_set
Convert the replace attribute from a boolean to a u32 to function as a
"replace set." A newly loaded livepatch will now atomically replace any
existing patch belonging to the same set. There can only ever be one active
livepatch for a given replace_set number.
Link: https://github.com/pmladek/linux/tree/klp-state-transfer-v1-iter12 [0]
> diff --git a/kernel/livepatch/state.c b/kernel/livepatch/state.c
> index 2565d039ade0a..a1ac466373360 100644
> --- a/kernel/livepatch/state.c
> +++ b/kernel/livepatch/state.c
[ ... ]
> @@ -85,34 +85,65 @@ EXPORT_SYMBOL_GPL(klp_get_prev_state);
[ ... ]
> + klp_for_each_object_static(patch, obj) {
> + klp_for_each_object(old_patch, old_obj) {
> + if (!!obj->name != !!old_obj->name)
> + continue;
> + if (obj->name && strcmp(obj->name, old_obj->name))
> + continue;
> + klp_for_each_func_static(obj, func) {
> + if (klp_find_func(old_obj, func))
> + return false;
> + }
> + }
> + }
[Severity: High]
Could a malformed livepatch module cause a kernel panic here during patch
compatibility checking?
Since klp_is_patch_compatible() is called in klp_enable_patch() before
klp_init_patch() validates the incoming patch structures, a malformed patch
might have func->old_name set to NULL but func->new_func populated.
In that scenario, klp_for_each_func_static() would still process the function
and pass it to klp_find_func(), where it is used as old_func:
kernel/livepatch/core.c:klp_find_func() {
...
klp_for_each_func(obj, func) {
if ((strcmp(old_func->old_name, func->old_name) == 0) &&
...
}
Would this result in a NULL pointer dereference when klp_find_func() attempts
to call strcmp() on the unvalidated function's old_name? While livepatch
modules are loaded by root, should they fail validation gracefully instead of
crashing the kernel?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260529034542.68766-1-laoar.shao@gmail.com?part=2
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: [PATCH v2 2/4] livepatch: Support scoped atomic replace using replace_set
2026-05-29 4:32 ` sashiko-bot
@ 2026-05-29 9:11 ` Yafang Shao
0 siblings, 0 replies; 13+ messages in thread
From: Yafang Shao @ 2026-05-29 9:11 UTC (permalink / raw)
To: sashiko-reviews
Cc: jikos, pmladek, song, mbenes, jpoimboe, joe.lawrence,
live-patching
On Fri, May 29, 2026 at 12:32 PM <sashiko-bot@kernel.org> wrote:
>
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
> - [High] A malformed livepatch module with a missing function `old_name` will cause a kernel panic during patch compatibility checking.
The same issue with Patch #1.
--
Regards
Yafang
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH v2 3/4] livepatch: deprecate stack_order
2026-05-29 3:45 [PATCH v2 0/4] livepatch: Introduce replace set support Yafang Shao
2026-05-29 3:45 ` [PATCH v2 1/4] livepatch: Make klp_find_func() non-static Yafang Shao
2026-05-29 3:45 ` [PATCH v2 2/4] livepatch: Support scoped atomic replace using replace_set Yafang Shao
@ 2026-05-29 3:45 ` Yafang Shao
2026-05-29 4:54 ` sashiko-bot
2026-05-29 3:45 ` [PATCH v2 4/4] selftests/livepatch: Update tests for replace_set Yafang Shao
3 siblings, 1 reply; 13+ messages in thread
From: Yafang Shao @ 2026-05-29 3:45 UTC (permalink / raw)
To: jpoimboe, jikos, mbenes, pmladek, joe.lawrence, song
Cc: live-patching, Yafang Shao
stack_order is no longer needed for atomic-replace livepatches, as a
single function can only be modified by a unique replace_set.
Signed-off-by: Yafang Shao <laoar.shao@gmail.com>
---
.../ABI/testing/sysfs-kernel-livepatch | 1 +
kernel/livepatch/core.c | 24 -------
.../testing/selftests/livepatch/test-sysfs.sh | 69 -------------------
3 files changed, 1 insertion(+), 93 deletions(-)
diff --git a/Documentation/ABI/testing/sysfs-kernel-livepatch b/Documentation/ABI/testing/sysfs-kernel-livepatch
index 6d75235a6a2e..fddad93dba79 100644
--- a/Documentation/ABI/testing/sysfs-kernel-livepatch
+++ b/Documentation/ABI/testing/sysfs-kernel-livepatch
@@ -62,6 +62,7 @@ Description:
are applied to the system. If multiple live patches modify the same
function, the implementation with the biggest 'stack_order' number
is used, unless a transition is currently in progress.
+ <deprecated>
What: /sys/kernel/livepatch/<patch>/<object>
Date: Nov 2014
diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c
index 969fea2a9263..6d65f839f442 100644
--- a/kernel/livepatch/core.c
+++ b/kernel/livepatch/core.c
@@ -351,7 +351,6 @@ int klp_apply_section_relocs(struct module *pmod, Elf_Shdr *sechdrs,
* /sys/kernel/livepatch/<patch>/transition
* /sys/kernel/livepatch/<patch>/force
* /sys/kernel/livepatch/<patch>/replace_set
- * /sys/kernel/livepatch/<patch>/stack_order
* /sys/kernel/livepatch/<patch>/<object>
* /sys/kernel/livepatch/<patch>/<object>/patched
* /sys/kernel/livepatch/<patch>/<object>/<function,sympos>
@@ -457,38 +456,15 @@ static ssize_t replace_set_show(struct kobject *kobj,
return sysfs_emit(buf, "%u\n", patch->replace_set);
}
-static ssize_t stack_order_show(struct kobject *kobj,
- struct kobj_attribute *attr, char *buf)
-{
- struct klp_patch *patch, *this_patch;
- int stack_order = 0;
-
- this_patch = container_of(kobj, struct klp_patch, kobj);
-
- mutex_lock(&klp_mutex);
-
- klp_for_each_patch(patch) {
- stack_order++;
- if (patch == this_patch)
- break;
- }
-
- mutex_unlock(&klp_mutex);
-
- return sysfs_emit(buf, "%d\n", stack_order);
-}
-
static struct kobj_attribute enabled_kobj_attr = __ATTR_RW(enabled);
static struct kobj_attribute transition_kobj_attr = __ATTR_RO(transition);
static struct kobj_attribute force_kobj_attr = __ATTR_WO(force);
static struct kobj_attribute replace_set_kobj_attr = __ATTR_RO(replace_set);
-static struct kobj_attribute stack_order_kobj_attr = __ATTR_RO(stack_order);
static struct attribute *klp_patch_attrs[] = {
&enabled_kobj_attr.attr,
&transition_kobj_attr.attr,
&force_kobj_attr.attr,
&replace_set_kobj_attr.attr,
- &stack_order_kobj_attr.attr,
NULL
};
ATTRIBUTE_GROUPS(klp_patch);
diff --git a/tools/testing/selftests/livepatch/test-sysfs.sh b/tools/testing/selftests/livepatch/test-sysfs.sh
index 58fe1d96997c..0c31759f34f6 100755
--- a/tools/testing/selftests/livepatch/test-sysfs.sh
+++ b/tools/testing/selftests/livepatch/test-sysfs.sh
@@ -21,8 +21,6 @@ check_sysfs_rights "$MOD_LIVEPATCH" "enabled" "-rw-r--r--"
check_sysfs_value "$MOD_LIVEPATCH" "enabled" "1"
check_sysfs_rights "$MOD_LIVEPATCH" "force" "--w-------"
check_sysfs_rights "$MOD_LIVEPATCH" "replace" "-r--r--r--"
-check_sysfs_rights "$MOD_LIVEPATCH" "stack_order" "-r--r--r--"
-check_sysfs_value "$MOD_LIVEPATCH" "stack_order" "1"
check_sysfs_rights "$MOD_LIVEPATCH" "transition" "-r--r--r--"
check_sysfs_value "$MOD_LIVEPATCH" "transition" "0"
check_sysfs_rights "$MOD_LIVEPATCH" "vmlinux/patched" "-r--r--r--"
@@ -135,71 +133,4 @@ livepatch: '$MOD_LIVEPATCH': completing unpatching transition
livepatch: '$MOD_LIVEPATCH': unpatching complete
% rmmod $MOD_LIVEPATCH"
-start_test "sysfs test stack_order value"
-
-load_lp $MOD_LIVEPATCH
-
-check_sysfs_value "$MOD_LIVEPATCH" "stack_order" "1"
-
-load_lp $MOD_LIVEPATCH2
-
-check_sysfs_value "$MOD_LIVEPATCH2" "stack_order" "2"
-
-load_lp $MOD_LIVEPATCH3
-
-check_sysfs_value "$MOD_LIVEPATCH3" "stack_order" "3"
-
-disable_lp $MOD_LIVEPATCH2
-unload_lp $MOD_LIVEPATCH2
-
-check_sysfs_value "$MOD_LIVEPATCH" "stack_order" "1"
-check_sysfs_value "$MOD_LIVEPATCH3" "stack_order" "2"
-
-disable_lp $MOD_LIVEPATCH3
-unload_lp $MOD_LIVEPATCH3
-
-disable_lp $MOD_LIVEPATCH
-unload_lp $MOD_LIVEPATCH
-
-check_result "% 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
-% insmod test_modules/$MOD_LIVEPATCH2.ko
-livepatch: enabling patch '$MOD_LIVEPATCH2'
-livepatch: '$MOD_LIVEPATCH2': initializing patching transition
-$MOD_LIVEPATCH2: pre_patch_callback: vmlinux
-livepatch: '$MOD_LIVEPATCH2': starting patching transition
-livepatch: '$MOD_LIVEPATCH2': completing patching transition
-$MOD_LIVEPATCH2: post_patch_callback: vmlinux
-livepatch: '$MOD_LIVEPATCH2': patching complete
-% insmod test_modules/$MOD_LIVEPATCH3.ko
-livepatch: enabling patch '$MOD_LIVEPATCH3'
-livepatch: '$MOD_LIVEPATCH3': initializing patching transition
-livepatch: '$MOD_LIVEPATCH3': starting patching transition
-livepatch: '$MOD_LIVEPATCH3': completing patching transition
-livepatch: '$MOD_LIVEPATCH3': patching complete
-% echo 0 > $SYSFS_KLP_DIR/$MOD_LIVEPATCH2/enabled
-livepatch: '$MOD_LIVEPATCH2': initializing unpatching transition
-$MOD_LIVEPATCH2: pre_unpatch_callback: vmlinux
-livepatch: '$MOD_LIVEPATCH2': starting unpatching transition
-livepatch: '$MOD_LIVEPATCH2': completing unpatching transition
-$MOD_LIVEPATCH2: post_unpatch_callback: vmlinux
-livepatch: '$MOD_LIVEPATCH2': unpatching complete
-% rmmod $MOD_LIVEPATCH2
-% echo 0 > $SYSFS_KLP_DIR/$MOD_LIVEPATCH3/enabled
-livepatch: '$MOD_LIVEPATCH3': initializing unpatching transition
-livepatch: '$MOD_LIVEPATCH3': starting unpatching transition
-livepatch: '$MOD_LIVEPATCH3': completing unpatching transition
-livepatch: '$MOD_LIVEPATCH3': unpatching complete
-% rmmod $MOD_LIVEPATCH3
-% echo 0 > $SYSFS_KLP_DIR/$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"
-
exit 0
--
2.47.3
^ permalink raw reply related [flat|nested] 13+ messages in thread* Re: [PATCH v2 3/4] livepatch: deprecate stack_order
2026-05-29 3:45 ` [PATCH v2 3/4] livepatch: deprecate stack_order Yafang Shao
@ 2026-05-29 4:54 ` sashiko-bot
2026-05-29 9:13 ` Yafang Shao
0 siblings, 1 reply; 13+ messages in thread
From: sashiko-bot @ 2026-05-29 4:54 UTC (permalink / raw)
To: song, jpoimboe, joe.lawrence, jikos, mbenes, pmladek
Cc: live-patching, Yafang Shao
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Critical] The commit entirely removes the `stack_order` sysfs attribute while only marking it as `<deprecated>` in the ABI documentation, causing immediate backwards compatibility breakage and contradicting documentation guidelines.
--
commit 041b2dbba1a7397626104dd773fc1f37228d382c
Author: Yafang Shao <laoar.shao@gmail.com>
livepatch: deprecate stack_order
This commit deprecates the stack_order sysfs attribute for atomic-replace
livepatches, since a single function can only be modified by a unique
replace_set.
> diff --git a/Documentation/ABI/testing/sysfs-kernel-livepatch b/Documentation/ABI/testing/sysfs-kernel-livepatch
> index 6d75235a6a2e4..fddad93dba797 100644
> --- a/Documentation/ABI/testing/sysfs-kernel-livepatch
> +++ b/Documentation/ABI/testing/sysfs-kernel-livepatch
> @@ -62,6 +62,7 @@ Description:
> are applied to the system. If multiple live patches modify the same
> function, the implementation with the biggest 'stack_order' number
> is used, unless a transition is currently in progress.
> + <deprecated>
[ ... ]
> diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c
> index 969fea2a92631..6d65f839f4420 100644
> --- a/kernel/livepatch/core.c
> +++ b/kernel/livepatch/core.c
[ ... ]
> @@ -457,38 +456,15 @@ static ssize_t replace_set_show(struct kobject *kobj,
> return sysfs_emit(buf, "%u\n", patch->replace_set);
> }
>
> -static ssize_t stack_order_show(struct kobject *kobj,
> - struct kobj_attribute *attr, char *buf)
> -{
> - struct klp_patch *patch, *this_patch;
> - int stack_order = 0;
> -
> - this_patch = container_of(kobj, struct klp_patch, kobj);
> -
> - mutex_lock(&klp_mutex);
> -
> - klp_for_each_patch(patch) {
> - stack_order++;
> - if (patch == this_patch)
> - break;
> - }
> -
> - mutex_unlock(&klp_mutex);
> -
> - return sysfs_emit(buf, "%d\n", stack_order);
> -}
> -
> static struct kobj_attribute enabled_kobj_attr = __ATTR_RW(enabled);
> static struct kobj_attribute transition_kobj_attr = __ATTR_RO(transition);
> static struct kobj_attribute force_kobj_attr = __ATTR_WO(force);
> static struct kobj_attribute replace_set_kobj_attr = __ATTR_RO(replace_set);
> -static struct kobj_attribute stack_order_kobj_attr = __ATTR_RO(stack_order);
> static struct attribute *klp_patch_attrs[] = {
> &enabled_kobj_attr.attr,
> &transition_kobj_attr.attr,
> &force_kobj_attr.attr,
> &replace_set_kobj_attr.attr,
> - &stack_order_kobj_attr.attr,
> NULL
> };
[Severity: Critical]
The commit message and documentation state that the stack_order attribute
is being deprecated, but this code completely removes the attribute. Does
this abruptly break ABI compatibility for userspace tools that expect this
sysfs file to exist?
Normally, deprecating an interface requires keeping it around for a
transition period (perhaps returning a dummy value) rather than deleting
it immediately. Also, if it were actually removed, shouldn't the ABI
documentation be moved to the removed/ directory instead of just appending
<deprecated> to the existing entry?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260529034542.68766-1-laoar.shao@gmail.com?part=3
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: [PATCH v2 3/4] livepatch: deprecate stack_order
2026-05-29 4:54 ` sashiko-bot
@ 2026-05-29 9:13 ` Yafang Shao
0 siblings, 0 replies; 13+ messages in thread
From: Yafang Shao @ 2026-05-29 9:13 UTC (permalink / raw)
To: sashiko-reviews
Cc: song, jpoimboe, joe.lawrence, jikos, mbenes, pmladek,
live-patching
On Fri, May 29, 2026 at 12:54 PM <sashiko-bot@kernel.org> wrote:
>
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
> - [Critical] The commit entirely removes the `stack_order` sysfs attribute while only marking it as `<deprecated>` in the ABI documentation, causing immediate backwards compatibility breakage and contradicting documentation guidelines.
> --
>
> commit 041b2dbba1a7397626104dd773fc1f37228d382c
> Author: Yafang Shao <laoar.shao@gmail.com>
>
> livepatch: deprecate stack_order
>
> This commit deprecates the stack_order sysfs attribute for atomic-replace
> livepatches, since a single function can only be modified by a unique
> replace_set.
>
> > diff --git a/Documentation/ABI/testing/sysfs-kernel-livepatch b/Documentation/ABI/testing/sysfs-kernel-livepatch
> > index 6d75235a6a2e4..fddad93dba797 100644
> > --- a/Documentation/ABI/testing/sysfs-kernel-livepatch
> > +++ b/Documentation/ABI/testing/sysfs-kernel-livepatch
> > @@ -62,6 +62,7 @@ Description:
> > are applied to the system. If multiple live patches modify the same
> > function, the implementation with the biggest 'stack_order' number
> > is used, unless a transition is currently in progress.
> > + <deprecated>
>
> [ ... ]
>
> > diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c
> > index 969fea2a92631..6d65f839f4420 100644
> > --- a/kernel/livepatch/core.c
> > +++ b/kernel/livepatch/core.c
> [ ... ]
> > @@ -457,38 +456,15 @@ static ssize_t replace_set_show(struct kobject *kobj,
> > return sysfs_emit(buf, "%u\n", patch->replace_set);
> > }
> >
> > -static ssize_t stack_order_show(struct kobject *kobj,
> > - struct kobj_attribute *attr, char *buf)
> > -{
> > - struct klp_patch *patch, *this_patch;
> > - int stack_order = 0;
> > -
> > - this_patch = container_of(kobj, struct klp_patch, kobj);
> > -
> > - mutex_lock(&klp_mutex);
> > -
> > - klp_for_each_patch(patch) {
> > - stack_order++;
> > - if (patch == this_patch)
> > - break;
> > - }
> > -
> > - mutex_unlock(&klp_mutex);
> > -
> > - return sysfs_emit(buf, "%d\n", stack_order);
> > -}
> > -
> > static struct kobj_attribute enabled_kobj_attr = __ATTR_RW(enabled);
> > static struct kobj_attribute transition_kobj_attr = __ATTR_RO(transition);
> > static struct kobj_attribute force_kobj_attr = __ATTR_WO(force);
> > static struct kobj_attribute replace_set_kobj_attr = __ATTR_RO(replace_set);
> > -static struct kobj_attribute stack_order_kobj_attr = __ATTR_RO(stack_order);
> > static struct attribute *klp_patch_attrs[] = {
> > &enabled_kobj_attr.attr,
> > &transition_kobj_attr.attr,
> > &force_kobj_attr.attr,
> > &replace_set_kobj_attr.attr,
> > - &stack_order_kobj_attr.attr,
> > NULL
> > };
>
> [Severity: Critical]
> The commit message and documentation state that the stack_order attribute
> is being deprecated, but this code completely removes the attribute. Does
> this abruptly break ABI compatibility for userspace tools that expect this
> sysfs file to exist?
>
> Normally, deprecating an interface requires keeping it around for a
> transition period (perhaps returning a dummy value) rather than deleting
> it immediately. Also, if it were actually removed, shouldn't the ABI
> documentation be moved to the removed/ directory instead of just appending
> <deprecated> to the existing entry?
I will wait for the feedback from the maintainers.
--
Regards
Yafang
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH v2 4/4] selftests/livepatch: Update tests for replace_set
2026-05-29 3:45 [PATCH v2 0/4] livepatch: Introduce replace set support Yafang Shao
` (2 preceding siblings ...)
2026-05-29 3:45 ` [PATCH v2 3/4] livepatch: deprecate stack_order Yafang Shao
@ 2026-05-29 3:45 ` Yafang Shao
2026-05-29 5:16 ` sashiko-bot
3 siblings, 1 reply; 13+ messages in thread
From: Yafang Shao @ 2026-05-29 3:45 UTC (permalink / raw)
To: jpoimboe, jikos, mbenes, pmladek, joe.lawrence, song
Cc: live-patching, Yafang Shao
The changes are as follows:
- Replace "replace" with "replace_set"
- For atomic-replace test cases, we configure two different livepatches
that share the same replace_set.
- For non-atomic-replace test cases, we configure multiple livepatches,
each with a different replace_set.
The result are as follows,
$ ./test-callbacks.sh
TEST: target module before livepatch ... ok
TEST: module_coming notifier ... ok
TEST: module_going notifier ... ok
TEST: module_coming and module_going notifiers ... ok
TEST: target module not present ... ok
TEST: pre-patch callback -ENODEV ... ok
TEST: module_coming + pre-patch callback -ENODEV ... ok
TEST: multiple target modules ... ok
TEST: busy target module ... ok
TEST: multiple livepatches ... ok
TEST: atomic replace ... ok
$ ./test-ftrace.sh
TEST: livepatch interaction with ftrace_enabled sysctl ... ok
TEST: trace livepatched function and check that the live patch remains in effect ... ok
TEST: livepatch a traced function and check that the live patch remains in effect ... ok
$ ./test-kprobe.sh
TEST: livepatch interaction with kprobed function with post_handler ... ok
TEST: livepatch interaction with kprobed function without post_handler ... ok
$ ./test-livepatch.sh
TEST: basic function patching ... ok
TEST: multiple livepatches ... ok
TEST: module function patching ... ok
TEST: module function patching (livepatch first) ... ok
$ ./test-shadow-vars.sh
TEST: basic shadow variable API ... ok
$ ./test-state.sh
TEST: system state modification ... ok
TEST: taking over system state modification ... ok
TEST: compatible cumulative livepatches ... ok
TEST: incompatible cumulative livepatches ... ok
$ ./test-syscall.sh
TEST: patch getpid syscall while being heavily hammered ... ok
Signed-off-by: Yafang Shao <laoar.shao@gmail.com>
---
.../selftests/livepatch/test-callbacks.sh | 33 +++----
.../selftests/livepatch/test-livepatch.sh | 98 +------------------
.../testing/selftests/livepatch/test-sysfs.sh | 22 ++---
.../test_modules/test_klp_atomic_replace.c | 10 +-
.../test_modules/test_klp_callbacks_demo.c | 6 ++
.../test_modules/test_klp_callbacks_demo2.c | 10 +-
.../test_modules/test_klp_livepatch.c | 6 ++
.../livepatch/test_modules/test_klp_state.c | 2 +-
.../livepatch/test_modules/test_klp_state2.c | 2 +-
9 files changed, 55 insertions(+), 134 deletions(-)
diff --git a/tools/testing/selftests/livepatch/test-callbacks.sh b/tools/testing/selftests/livepatch/test-callbacks.sh
index 2a03deb26a12..692da8ea4c25 100755
--- a/tools/testing/selftests/livepatch/test-callbacks.sh
+++ b/tools/testing/selftests/livepatch/test-callbacks.sh
@@ -451,8 +451,8 @@ $MOD_TARGET_BUSY: busymod_work_func exit
$MOD_TARGET_BUSY: ${MOD_TARGET_BUSY}_exit"
-# Test loading multiple livepatches. This test-case is mainly for comparing
-# with the next test-case.
+# Test loading multiple livepatches sharing different replace_set.
+# This test-case is mainly for comparing with the next test-case.
#
# - Load and unload two livepatches, pre and post (un)patch callbacks
# execute as each patch progresses through its (un)patching
@@ -460,14 +460,14 @@ $MOD_TARGET_BUSY: ${MOD_TARGET_BUSY}_exit"
start_test "multiple livepatches"
-load_lp $MOD_LIVEPATCH
-load_lp $MOD_LIVEPATCH2
+load_lp $MOD_LIVEPATCH replace_set=0
+load_lp $MOD_LIVEPATCH2 replace_set=1
disable_lp $MOD_LIVEPATCH2
disable_lp $MOD_LIVEPATCH
unload_lp $MOD_LIVEPATCH2
unload_lp $MOD_LIVEPATCH
-check_result "% insmod test_modules/$MOD_LIVEPATCH.ko
+check_result "% insmod test_modules/$MOD_LIVEPATCH.ko replace_set=0
livepatch: enabling patch '$MOD_LIVEPATCH'
livepatch: '$MOD_LIVEPATCH': initializing patching transition
$MOD_LIVEPATCH: pre_patch_callback: vmlinux
@@ -475,7 +475,7 @@ livepatch: '$MOD_LIVEPATCH': starting patching transition
livepatch: '$MOD_LIVEPATCH': completing patching transition
$MOD_LIVEPATCH: post_patch_callback: vmlinux
livepatch: '$MOD_LIVEPATCH': patching complete
-% insmod test_modules/$MOD_LIVEPATCH2.ko
+% insmod test_modules/$MOD_LIVEPATCH2.ko replace_set=1
livepatch: enabling patch '$MOD_LIVEPATCH2'
livepatch: '$MOD_LIVEPATCH2': initializing patching transition
$MOD_LIVEPATCH2: pre_patch_callback: vmlinux
@@ -501,14 +501,13 @@ livepatch: '$MOD_LIVEPATCH': unpatching complete
% rmmod $MOD_LIVEPATCH"
-# Load multiple livepatches, but the second as an 'atomic-replace'
-# patch. When the latter loads, the original livepatch should be
-# disabled and *none* of its pre/post-unpatch callbacks executed. On
-# the other hand, when the atomic-replace livepatch is disabled, its
-# pre/post-unpatch callbacks *should* be executed.
+# Load multiple livepatches sharing the same replace_set.
+# When the latter loads, the original livepatch should be disabled and
+# *none* of its pre/post-unpatch callbacks executed. On the other hand,
+# when the atomic-replace livepatch is disabled, its pre/post-unpatch
+# callbacks *should* be executed.
#
-# - Load and unload two livepatches, the second of which has its
-# .replace flag set true.
+# - Load and unload two livepatches sharing the same replace_set
#
# - Pre and post patch callbacks are executed for both livepatches.
#
@@ -517,13 +516,13 @@ livepatch: '$MOD_LIVEPATCH': unpatching complete
start_test "atomic replace"
-load_lp $MOD_LIVEPATCH
-load_lp $MOD_LIVEPATCH2 replace=1
+load_lp $MOD_LIVEPATCH replace_set=0
+load_lp $MOD_LIVEPATCH2 replace_set=0
disable_lp $MOD_LIVEPATCH2
unload_lp $MOD_LIVEPATCH2
unload_lp $MOD_LIVEPATCH
-check_result "% insmod test_modules/$MOD_LIVEPATCH.ko
+check_result "% insmod test_modules/$MOD_LIVEPATCH.ko replace_set=0
livepatch: enabling patch '$MOD_LIVEPATCH'
livepatch: '$MOD_LIVEPATCH': initializing patching transition
$MOD_LIVEPATCH: pre_patch_callback: vmlinux
@@ -531,7 +530,7 @@ livepatch: '$MOD_LIVEPATCH': starting patching transition
livepatch: '$MOD_LIVEPATCH': completing patching transition
$MOD_LIVEPATCH: post_patch_callback: vmlinux
livepatch: '$MOD_LIVEPATCH': patching complete
-% insmod test_modules/$MOD_LIVEPATCH2.ko replace=1
+% insmod test_modules/$MOD_LIVEPATCH2.ko replace_set=0
livepatch: enabling patch '$MOD_LIVEPATCH2'
livepatch: '$MOD_LIVEPATCH2': initializing patching transition
$MOD_LIVEPATCH2: pre_patch_callback: vmlinux
diff --git a/tools/testing/selftests/livepatch/test-livepatch.sh b/tools/testing/selftests/livepatch/test-livepatch.sh
index c44c5341a2f1..042999856267 100755
--- a/tools/testing/selftests/livepatch/test-livepatch.sh
+++ b/tools/testing/selftests/livepatch/test-livepatch.sh
@@ -57,12 +57,12 @@ livepatch: '$MOD_LIVEPATCH1': unpatching complete
start_test "multiple livepatches"
-load_lp $MOD_LIVEPATCH1
+load_lp $MOD_LIVEPATCH1 replace_set=0
grep 'live patched' /proc/cmdline > /dev/kmsg
grep 'live patched' /proc/meminfo > /dev/kmsg
-load_lp $MOD_REPLACE replace=0
+load_lp $MOD_REPLACE replace_set=1
grep 'live patched' /proc/cmdline > /dev/kmsg
grep 'live patched' /proc/meminfo > /dev/kmsg
@@ -79,14 +79,14 @@ unload_lp $MOD_LIVEPATCH1
grep 'live patched' /proc/cmdline > /dev/kmsg
grep 'live patched' /proc/meminfo > /dev/kmsg
-check_result "% insmod test_modules/$MOD_LIVEPATCH1.ko
+check_result "% insmod test_modules/$MOD_LIVEPATCH1.ko replace_set=0
livepatch: enabling patch '$MOD_LIVEPATCH1'
livepatch: '$MOD_LIVEPATCH1': initializing patching transition
livepatch: '$MOD_LIVEPATCH1': starting patching transition
livepatch: '$MOD_LIVEPATCH1': completing patching transition
livepatch: '$MOD_LIVEPATCH1': patching complete
$MOD_LIVEPATCH1: this has been live patched
-% insmod test_modules/$MOD_REPLACE.ko replace=0
+% insmod test_modules/$MOD_REPLACE.ko replace_set=1
livepatch: enabling patch '$MOD_REPLACE'
livepatch: '$MOD_REPLACE': initializing patching transition
livepatch: '$MOD_REPLACE': starting patching transition
@@ -108,96 +108,6 @@ livepatch: '$MOD_LIVEPATCH1': completing unpatching transition
livepatch: '$MOD_LIVEPATCH1': unpatching complete
% rmmod $MOD_LIVEPATCH1"
-
-# - load a livepatch that modifies the output from /proc/cmdline and
-# verify correct behavior
-# - load two additional livepatches and check the number of livepatch modules
-# applied
-# - load an atomic replace livepatch and check that the other three modules were
-# disabled
-# - remove all livepatches besides the atomic replace one and verify that the
-# atomic replace livepatch is still active
-# - remove the atomic replace livepatch and verify that none are active
-
-start_test "atomic replace livepatch"
-
-load_lp $MOD_LIVEPATCH1
-
-grep 'live patched' /proc/cmdline > /dev/kmsg
-grep 'live patched' /proc/meminfo > /dev/kmsg
-
-for mod in $MOD_LIVEPATCH2 $MOD_LIVEPATCH3; do
- load_lp "$mod"
-done
-
-mods=($SYSFS_KLP_DIR/*)
-nmods=${#mods[@]}
-if [ "$nmods" -ne 3 ]; then
- die "Expecting three modules listed, found $nmods"
-fi
-
-load_lp $MOD_REPLACE replace=1
-
-grep 'live patched' /proc/cmdline > /dev/kmsg
-grep 'live patched' /proc/meminfo > /dev/kmsg
-
-loop_until 'mods=($SYSFS_KLP_DIR/*); nmods=${#mods[@]}; [[ "$nmods" -eq 1 ]]' ||
- die "Expecting only one moduled listed, found $nmods"
-
-# These modules were disabled by the atomic replace
-for mod in $MOD_LIVEPATCH3 $MOD_LIVEPATCH2 $MOD_LIVEPATCH1; do
- unload_lp "$mod"
-done
-
-grep 'live patched' /proc/cmdline > /dev/kmsg
-grep 'live patched' /proc/meminfo > /dev/kmsg
-
-disable_lp $MOD_REPLACE
-unload_lp $MOD_REPLACE
-
-grep 'live patched' /proc/cmdline > /dev/kmsg
-grep 'live patched' /proc/meminfo > /dev/kmsg
-
-check_result "% insmod test_modules/$MOD_LIVEPATCH1.ko
-livepatch: enabling patch '$MOD_LIVEPATCH1'
-livepatch: '$MOD_LIVEPATCH1': initializing patching transition
-livepatch: '$MOD_LIVEPATCH1': starting patching transition
-livepatch: '$MOD_LIVEPATCH1': completing patching transition
-livepatch: '$MOD_LIVEPATCH1': patching complete
-$MOD_LIVEPATCH1: this has been live patched
-% insmod test_modules/$MOD_LIVEPATCH2.ko
-livepatch: enabling patch '$MOD_LIVEPATCH2'
-livepatch: '$MOD_LIVEPATCH2': initializing patching transition
-livepatch: '$MOD_LIVEPATCH2': starting patching transition
-livepatch: '$MOD_LIVEPATCH2': completing patching transition
-livepatch: '$MOD_LIVEPATCH2': patching complete
-% insmod test_modules/$MOD_LIVEPATCH3.ko
-livepatch: enabling patch '$MOD_LIVEPATCH3'
-livepatch: '$MOD_LIVEPATCH3': initializing patching transition
-$MOD_LIVEPATCH3: pre_patch_callback: vmlinux
-livepatch: '$MOD_LIVEPATCH3': starting patching transition
-livepatch: '$MOD_LIVEPATCH3': completing patching transition
-$MOD_LIVEPATCH3: post_patch_callback: vmlinux
-livepatch: '$MOD_LIVEPATCH3': patching complete
-% insmod test_modules/$MOD_REPLACE.ko replace=1
-livepatch: enabling patch '$MOD_REPLACE'
-livepatch: '$MOD_REPLACE': initializing patching transition
-livepatch: '$MOD_REPLACE': starting patching transition
-livepatch: '$MOD_REPLACE': completing patching transition
-livepatch: '$MOD_REPLACE': patching complete
-$MOD_REPLACE: this has been live patched
-% rmmod $MOD_LIVEPATCH3
-% rmmod $MOD_LIVEPATCH2
-% rmmod $MOD_LIVEPATCH1
-$MOD_REPLACE: this has been live patched
-% echo 0 > $SYSFS_KLP_DIR/$MOD_REPLACE/enabled
-livepatch: '$MOD_REPLACE': initializing unpatching transition
-livepatch: '$MOD_REPLACE': starting unpatching transition
-livepatch: '$MOD_REPLACE': completing unpatching transition
-livepatch: '$MOD_REPLACE': unpatching complete
-% rmmod $MOD_REPLACE"
-
-
# - load a target module that provides /proc/test_klp_mod_target with
# original output
# - load a livepatch that patches the target module's show function
diff --git a/tools/testing/selftests/livepatch/test-sysfs.sh b/tools/testing/selftests/livepatch/test-sysfs.sh
index 0c31759f34f6..37425ad89f58 100755
--- a/tools/testing/selftests/livepatch/test-sysfs.sh
+++ b/tools/testing/selftests/livepatch/test-sysfs.sh
@@ -20,7 +20,7 @@ check_sysfs_rights "$MOD_LIVEPATCH" "" "drwxr-xr-x"
check_sysfs_rights "$MOD_LIVEPATCH" "enabled" "-rw-r--r--"
check_sysfs_value "$MOD_LIVEPATCH" "enabled" "1"
check_sysfs_rights "$MOD_LIVEPATCH" "force" "--w-------"
-check_sysfs_rights "$MOD_LIVEPATCH" "replace" "-r--r--r--"
+check_sysfs_rights "$MOD_LIVEPATCH" "replace_set" "-r--r--r--"
check_sysfs_rights "$MOD_LIVEPATCH" "transition" "-r--r--r--"
check_sysfs_value "$MOD_LIVEPATCH" "transition" "0"
check_sysfs_rights "$MOD_LIVEPATCH" "vmlinux/patched" "-r--r--r--"
@@ -86,18 +86,18 @@ test_klp_callbacks_demo: post_unpatch_callback: vmlinux
livepatch: 'test_klp_callbacks_demo': unpatching complete
% rmmod test_klp_callbacks_demo"
-start_test "sysfs test replace enabled"
+start_test "sysfs test replace_set 0"
MOD_LIVEPATCH=test_klp_atomic_replace
-load_lp $MOD_LIVEPATCH replace=1
+load_lp $MOD_LIVEPATCH replace_set=0
-check_sysfs_rights "$MOD_LIVEPATCH" "replace" "-r--r--r--"
-check_sysfs_value "$MOD_LIVEPATCH" "replace" "1"
+check_sysfs_rights "$MOD_LIVEPATCH" "replace_set" "-r--r--r--"
+check_sysfs_value "$MOD_LIVEPATCH" "replace_set" "0"
disable_lp $MOD_LIVEPATCH
unload_lp $MOD_LIVEPATCH
-check_result "% insmod test_modules/$MOD_LIVEPATCH.ko replace=1
+check_result "% insmod test_modules/$MOD_LIVEPATCH.ko replace_set=0
livepatch: enabling patch '$MOD_LIVEPATCH'
livepatch: '$MOD_LIVEPATCH': initializing patching transition
livepatch: '$MOD_LIVEPATCH': starting patching transition
@@ -110,17 +110,17 @@ livepatch: '$MOD_LIVEPATCH': completing unpatching transition
livepatch: '$MOD_LIVEPATCH': unpatching complete
% rmmod $MOD_LIVEPATCH"
-start_test "sysfs test replace disabled"
+start_test "sysfs test replace_set 1234"
-load_lp $MOD_LIVEPATCH replace=0
+load_lp $MOD_LIVEPATCH replace_set=1234
-check_sysfs_rights "$MOD_LIVEPATCH" "replace" "-r--r--r--"
-check_sysfs_value "$MOD_LIVEPATCH" "replace" "0"
+check_sysfs_rights "$MOD_LIVEPATCH" "replace_set" "-r--r--r--"
+check_sysfs_value "$MOD_LIVEPATCH" "replace_set" "1234"
disable_lp $MOD_LIVEPATCH
unload_lp $MOD_LIVEPATCH
-check_result "% insmod test_modules/$MOD_LIVEPATCH.ko replace=0
+check_result "% insmod test_modules/$MOD_LIVEPATCH.ko replace_set=1234
livepatch: enabling patch '$MOD_LIVEPATCH'
livepatch: '$MOD_LIVEPATCH': initializing patching transition
livepatch: '$MOD_LIVEPATCH': starting patching transition
diff --git a/tools/testing/selftests/livepatch/test_modules/test_klp_atomic_replace.c b/tools/testing/selftests/livepatch/test_modules/test_klp_atomic_replace.c
index 5af7093ca00c..5333503f193a 100644
--- a/tools/testing/selftests/livepatch/test_modules/test_klp_atomic_replace.c
+++ b/tools/testing/selftests/livepatch/test_modules/test_klp_atomic_replace.c
@@ -7,9 +7,9 @@
#include <linux/kernel.h>
#include <linux/livepatch.h>
-static int replace;
-module_param(replace, int, 0644);
-MODULE_PARM_DESC(replace, "replace (default=0)");
+static int replace_set;
+module_param(replace_set, int, 0644);
+MODULE_PARM_DESC(replace_set, "replace_set (default=0)");
#include <linux/seq_file.h>
static int livepatch_meminfo_proc_show(struct seq_file *m, void *v)
@@ -36,12 +36,12 @@ static struct klp_object objs[] = {
static struct klp_patch patch = {
.mod = THIS_MODULE,
.objs = objs,
- /* set .replace in the init function below for demo purposes */
+ /* set .replace_set in the init function below for demo purposes */
};
static int test_klp_atomic_replace_init(void)
{
- patch.replace = replace;
+ patch.replace_set = replace_set;
return klp_enable_patch(&patch);
}
diff --git a/tools/testing/selftests/livepatch/test_modules/test_klp_callbacks_demo.c b/tools/testing/selftests/livepatch/test_modules/test_klp_callbacks_demo.c
index 3fd8fe1cd1cc..5c3324aa4d75 100644
--- a/tools/testing/selftests/livepatch/test_modules/test_klp_callbacks_demo.c
+++ b/tools/testing/selftests/livepatch/test_modules/test_klp_callbacks_demo.c
@@ -7,6 +7,10 @@
#include <linux/kernel.h>
#include <linux/livepatch.h>
+static int replace_set;
+module_param(replace_set, int, 0644);
+MODULE_PARM_DESC(replace_set, "replace_set (default=0)");
+
static int pre_patch_ret;
module_param(pre_patch_ret, int, 0644);
MODULE_PARM_DESC(pre_patch_ret, "pre_patch_ret (default=0)");
@@ -102,10 +106,12 @@ static struct klp_object objs[] = {
static struct klp_patch patch = {
.mod = THIS_MODULE,
.objs = objs,
+ /* set .replace_set in the init function below for demo purposes */
};
static int test_klp_callbacks_demo_init(void)
{
+ patch.replace_set = replace_set;
return klp_enable_patch(&patch);
}
diff --git a/tools/testing/selftests/livepatch/test_modules/test_klp_callbacks_demo2.c b/tools/testing/selftests/livepatch/test_modules/test_klp_callbacks_demo2.c
index 5417573e80af..31347e2131a7 100644
--- a/tools/testing/selftests/livepatch/test_modules/test_klp_callbacks_demo2.c
+++ b/tools/testing/selftests/livepatch/test_modules/test_klp_callbacks_demo2.c
@@ -7,9 +7,9 @@
#include <linux/kernel.h>
#include <linux/livepatch.h>
-static int replace;
-module_param(replace, int, 0644);
-MODULE_PARM_DESC(replace, "replace (default=0)");
+static int replace_set;
+module_param(replace_set, int, 0644);
+MODULE_PARM_DESC(replace_set, "replace_set (default=0)");
static const char *const module_state[] = {
[MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state",
@@ -72,12 +72,12 @@ static struct klp_object objs[] = {
static struct klp_patch patch = {
.mod = THIS_MODULE,
.objs = objs,
- /* set .replace in the init function below for demo purposes */
+ /* set .replace_set in the init function below for demo purposes */
};
static int test_klp_callbacks_demo2_init(void)
{
- patch.replace = replace;
+ patch.replace_set = replace_set;
return klp_enable_patch(&patch);
}
diff --git a/tools/testing/selftests/livepatch/test_modules/test_klp_livepatch.c b/tools/testing/selftests/livepatch/test_modules/test_klp_livepatch.c
index aff08199de71..fedd2494d187 100644
--- a/tools/testing/selftests/livepatch/test_modules/test_klp_livepatch.c
+++ b/tools/testing/selftests/livepatch/test_modules/test_klp_livepatch.c
@@ -15,6 +15,10 @@ static int livepatch_cmdline_proc_show(struct seq_file *m, void *v)
return 0;
}
+static int replace_set;
+module_param(replace_set, int, 0644);
+MODULE_PARM_DESC(replace_set, "replace_set (default=0)");
+
static struct klp_func funcs[] = {
{
.old_name = "cmdline_proc_show",
@@ -32,10 +36,12 @@ static struct klp_object objs[] = {
static struct klp_patch patch = {
.mod = THIS_MODULE,
.objs = objs,
+ /* set .replace_set in the init function below for demo purposes */
};
static int test_klp_livepatch_init(void)
{
+ patch.replace_set = replace_set;
return klp_enable_patch(&patch);
}
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 57a4253acb01..8c8829c3ec43 100644
--- a/tools/testing/selftests/livepatch/test_modules/test_klp_state.c
+++ b/tools/testing/selftests/livepatch/test_modules/test_klp_state.c
@@ -142,7 +142,7 @@ static struct klp_patch patch = {
.mod = THIS_MODULE,
.objs = objs,
.states = states,
- .replace = true,
+ .replace_set = 0,
};
static int test_klp_callbacks_demo_init(void)
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 c978ea4d5e67..8a79d7dcce33 100644
--- a/tools/testing/selftests/livepatch/test_modules/test_klp_state2.c
+++ b/tools/testing/selftests/livepatch/test_modules/test_klp_state2.c
@@ -171,7 +171,7 @@ static struct klp_patch patch = {
.mod = THIS_MODULE,
.objs = objs,
.states = states,
- .replace = true,
+ .replace_set = 0,
};
static int test_klp_callbacks_demo_init(void)
--
2.47.3
^ permalink raw reply related [flat|nested] 13+ messages in thread* Re: [PATCH v2 4/4] selftests/livepatch: Update tests for replace_set
2026-05-29 3:45 ` [PATCH v2 4/4] selftests/livepatch: Update tests for replace_set Yafang Shao
@ 2026-05-29 5:16 ` sashiko-bot
2026-05-29 9:12 ` Yafang Shao
0 siblings, 1 reply; 13+ messages in thread
From: sashiko-bot @ 2026-05-29 5:16 UTC (permalink / raw)
To: jikos, mbenes, song, joe.lawrence, pmladek, jpoimboe
Cc: Yafang Shao, live-patching
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] The 'atomic replace livepatch' test case in test-livepatch.sh was completely removed instead of being updated, resulting in lost test coverage and leaving behind dead variables.
--
commit 99bb60c2ba8319ec21289c482f1ea304e282396c
Author: Yafang Shao <laoar.shao@gmail.com>
selftests/livepatch: Update tests for replace_set
This commit updates the livepatch selftests to use "replace_set" instead
of "replace". It configures different livepatches to share or have different
replace_sets to test atomic and non-atomic replace behaviors.
> diff --git a/tools/testing/selftests/livepatch/test-livepatch.sh b/tools/testing/selftests/livepatch/test-livepatch.sh
> index c44c5341a2f1e..042999856267f 100755
> --- a/tools/testing/selftests/livepatch/test-livepatch.sh
> +++ b/tools/testing/selftests/livepatch/test-livepatch.sh
[ ... ]
> @@ -108,96 +108,6 @@ livepatch: '$MOD_LIVEPATCH1': completing unpatching transition
> livepatch: '$MOD_LIVEPATCH1': unpatching complete
> % rmmod $MOD_LIVEPATCH1"
>
> -
> -# - load a livepatch that modifies the output from /proc/cmdline and
> -# verify correct behavior
> -# - load two additional livepatches and check the number of livepatch modules
> -# applied
> -# - load an atomic replace livepatch and check that the other three modules were
> -# disabled
> -# - remove all livepatches besides the atomic replace one and verify that the
> -# atomic replace livepatch is still active
> -# - remove the atomic replace livepatch and verify that none are active
> -
> -start_test "atomic replace livepatch"
> -
> -load_lp $MOD_LIVEPATCH1
[Severity: Medium]
Was this test case intentionally removed completely instead of being updated for
the new replace_set semantics?
The commit message does not mention removing this test. This removal causes a
loss of test coverage that previously verified an atomic replace successfully
disables multiple existing livepatches.
Additionally, removing this test leaves the script variables MOD_LIVEPATCH2
and MOD_LIVEPATCH3 unused in test-livepatch.sh. Could this test be adapted
to use replace_set instead?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260529034542.68766-1-laoar.shao@gmail.com?part=4
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v2 4/4] selftests/livepatch: Update tests for replace_set
2026-05-29 5:16 ` sashiko-bot
@ 2026-05-29 9:12 ` Yafang Shao
0 siblings, 0 replies; 13+ messages in thread
From: Yafang Shao @ 2026-05-29 9:12 UTC (permalink / raw)
To: sashiko-reviews
Cc: jikos, mbenes, song, joe.lawrence, pmladek, jpoimboe,
live-patching
On Fri, May 29, 2026 at 1:17 PM <sashiko-bot@kernel.org> wrote:
>
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
> - [Medium] The 'atomic replace livepatch' test case in test-livepatch.sh was completely removed instead of being updated, resulting in lost test coverage and leaving behind dead variables.
> --
>
> commit 99bb60c2ba8319ec21289c482f1ea304e282396c
> Author: Yafang Shao <laoar.shao@gmail.com>
>
> selftests/livepatch: Update tests for replace_set
>
> This commit updates the livepatch selftests to use "replace_set" instead
> of "replace". It configures different livepatches to share or have different
> replace_sets to test atomic and non-atomic replace behaviors.
>
> > diff --git a/tools/testing/selftests/livepatch/test-livepatch.sh b/tools/testing/selftests/livepatch/test-livepatch.sh
> > index c44c5341a2f1e..042999856267f 100755
> > --- a/tools/testing/selftests/livepatch/test-livepatch.sh
> > +++ b/tools/testing/selftests/livepatch/test-livepatch.sh
> [ ... ]
> > @@ -108,96 +108,6 @@ livepatch: '$MOD_LIVEPATCH1': completing unpatching transition
> > livepatch: '$MOD_LIVEPATCH1': unpatching complete
> > % rmmod $MOD_LIVEPATCH1"
> >
> > -
> > -# - load a livepatch that modifies the output from /proc/cmdline and
> > -# verify correct behavior
> > -# - load two additional livepatches and check the number of livepatch modules
> > -# applied
> > -# - load an atomic replace livepatch and check that the other three modules were
> > -# disabled
> > -# - remove all livepatches besides the atomic replace one and verify that the
> > -# atomic replace livepatch is still active
> > -# - remove the atomic replace livepatch and verify that none are active
> > -
> > -start_test "atomic replace livepatch"
> > -
> > -load_lp $MOD_LIVEPATCH1
>
> [Severity: Medium]
> Was this test case intentionally removed completely instead of being updated for
> the new replace_set semantics?
>
> The commit message does not mention removing this test. This removal causes a
> loss of test coverage that previously verified an atomic replace successfully
> disables multiple existing livepatches.
This test case is invalid for the replace_set, since only one
livepatch will be replaced.
>
> Additionally, removing this test leaves the script variables MOD_LIVEPATCH2
> and MOD_LIVEPATCH3 unused in test-livepatch.sh. Could this test be adapted
> to use replace_set instead?
I will update it.
--
Regards
Yafang
^ permalink raw reply [flat|nested] 13+ messages in thread