On Tue 2026-04-07 17:45:31, Yafang Shao wrote:
> On Tue, Apr 7, 2026 at 11:16 AM Yafang Shao <[email protected]> wrote:
> >
> > On Tue, Apr 7, 2026 at 10:54 AM Song Liu <[email protected]> wrote:
> > >
> > > On Mon, Apr 6, 2026 at 2:12 PM Joe Lawrence <[email protected]> 
> > > wrote:
> > > [...]
> > > > > > > - The regular livepatches are cumulative, have the replace flag; 
> > > > > > > and
> > > > > > >   are replaceable.
> > > > > > > - The occasional "off-band" livepatches do not have the replace 
> > > > > > > flag,
> > > > > > >   and are not replaceable.
> > > > > > >
> > > > > > > With this setup, for systems with off-band livepatches loaded, we 
> > > > > > > can
> > > > > > > still release a cumulative livepatch to replace the previous 
> > > > > > > cumulative
> > > > > > > livepatch. Is this the expected use case?
> > > > > >
> > > > > > That matches our expected use case.
> > > > >
> > > > > If we really want to serve use cases like this, I think we can 
> > > > > introduce
> > > > > some replace tag concept: Each livepatch will have a tag, u32 number.
> > > > > Newly loaded livepatch will only replace existing livepatch with the
> > > > > same tag. We can even reuse the existing "bool replace" in klp_patch,
> > > > > and make it u32: replace=0 means no replace; replace > 0 are the
> > > > > replace tag.
> > > > >
> > > > > For current users of cumulative patches, all the livepatch will have 
> > > > > the
> > > > > same tag, say 1. For your use case, you can assign each user a
> > > > > unique tag. Then all these users can do atomic upgrades of their
> > > > > own livepatches.
> > > > >
> > > > > We may also need to check whether two livepatches of different tags
> > > > > touch the same kernel function. When that happens, the later
> > > > > livepatch should fail to load.

I still think how to make the hybrid mode more secure:

    + The isolated sets of livepatched functions look like a good rule.
    + What about isolating the shadow variables/states as well?

> > That sounds like a viable solution. I'll look into it and see how we
> > can implement it.
> 
> Does the following change look good to you ?
> 
> Subject: [PATCH] livepatch: Support scoped atomic replace using replace tags
> 
> Extend the replace attribute from a boolean to a u32 to act as a replace
> tag. This introduces the following semantics:
> 
>   replace = 0: Atomic replace is disabled. However, this patch remains
>                eligible to be superseded by others.
>   replace > 0: Enables tagged replace (default is 1). A newly loaded
>                livepatch will only replace existing patches that share the
>                same tag.
> 
> To maintain backward compatibility, a patch with replace == 0 does not
> trigger an outgoing atomic replace, but remains eligible to be superseded
> by any incoming patch with a valid replace tag.
> 
> diff --git a/include/linux/livepatch.h b/include/linux/livepatch.h
> index ba9e3988c07c..417c67a17b99 100644
> --- a/include/linux/livepatch.h
> +++ b/include/linux/livepatch.h
> @@ -123,7 +123,11 @@ 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:   replace tag:
> + *             = 0: Atomic replace is disabled; however, this patch remains
> + *                  eligible to be superseded by others.

This is weird semantic. Which livepatch tag would be allowed to
supersede it, please?

Do we still need this category?

> + *             > 0: Atomic replace is enabled. Only existing patches with a
> + *                  matching replace tag will be superseded.
>   * @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 +141,7 @@ struct klp_patch {
>         struct module *mod;
>         struct klp_object *objs;
>         struct klp_state *states;
> -       bool replace;
> +       unsigned int replace;

This already breaks the backward compatibility by changing the type
and semantic of this field. I would also change the name to better
match the new semantic. What about using:


  * @replace_set: Livepatch using the same @replace_set will get
                atomically replaced, see also conflicts[*].

        unsigned int replace_set;

[*] A livepatch module, livepatching an already livepatches function,
    can be loaded only when it has the same @replace_set number.

    By other words, two livepatches conflict when they have a different
    @replace_set number and have at least one livepatched version
    in common.

> 
>         /* internal */
>         struct list_head list;
> diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c
> index 28d15ba58a26..e4e5c03b0724 100644
> --- a/kernel/livepatch/core.c
> +++ b/kernel/livepatch/core.c
> @@ -793,6 +793,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 && old_patch->replace !=
> new_patch->replace)
> +                       continue;
>                 klp_free_patch_async(old_patch);
>         }
>  }
> @@ -1194,6 +1196,8 @@ void klp_unpatch_replaced_patches(struct
> klp_patch *new_patch)
>         klp_for_each_patch(old_patch) {
>                 if (old_patch == new_patch)
>                         return;
> +               if (old_patch->replace && old_patch->replace !=
> new_patch->replace)
> +                       continue;
> 
>                 old_patch->enabled = false;
>                 klp_unpatch_objects(old_patch);

This handles only the freeing part. More changes will be
necessary:

   + klp_is_patch_compatible() must check also conflicts
     between livepatches with different @replace_set.
     The conflicts might be in the lists of:

        + livepatched functions
        + state IDs (aka callbacks and shadow variables IDs)

   + klp_add_nops() must skip livepatches with another @replace_set

   + klp_unpatch_replaced_patches() should unpatch only
     patches with the same @replace_set

Finally, we would need to update existing selftests
plus add new selftests.

It is possible that I have missed something.

Anyway, you should wait for more feedback before you do too much
coding, especially the selftests are not needed at RFC stage.

Best Regards,
Petr

Reply via email to