From: Petr Mladek <pmladek@suse.com>
To: Yafang Shao <laoar.shao@gmail.com>
Cc: jpoimboe@kernel.org, jikos@kernel.org, mbenes@suse.cz,
joe.lawrence@redhat.com, song@kernel.org,
live-patching@vger.kernel.org,
sashiko-bot <sashiko-bot@kernel.org>
Subject: Re: [PATCH v2 2/2] livepatch: Fix UAF of unregistered patch kobjects
Date: Wed, 19 Aug 2026 13:18:36 +0200 [thread overview]
Message-ID: <aoWRDIjvE5jYNR9_@pathway.suse.cz> (raw)
In-Reply-To: <20260816090442.18128-3-laoar.shao@gmail.com>
On Sun 2026-08-16 17:04:42, Yafang Shao wrote:
> When klp_enable_patch() fails after klp_init_patch_early() has run,
> the error path calls klp_free_patch_start() and klp_free_patch_finish().
> The former drops the references of all object and function kobjects via
> klp_free_objects(), the latter drops the patch kobject reference and
> waits for the patch kobject release only:
>
> klp_free_patch_finish():
> kobject_put(&patch->kobj);
> wait_for_completion(&patch->finish);
>
> With CONFIG_DEBUG_KOBJECT_RELEASE enabled, kobject_put() does not
> release the kobject synchronously but schedules a delayed release with
> a random delay of up to 4 seconds (see kobject_release() in
> lib/kobject.c).
Yes.
> Because klp_free_patch_finish() only waits for the
> patch kobject release, it may return while object and function kobject
> releases are still pending. The caller can then unload the livepatch
> module, which frees the klp_object and klp_func structures. The delayed
> kobject release callbacks later access this freed memory in
> kobject_cleanup(), resulting in a use-after-free.
>
> This issue can occur in two scenarios:
>
> 1. The patch kobject was never added to sysfs (e.g., klp_init_patch()
> failed at kobject_add()). All child kobjects were only initialized
> via kobject_init() but never added to sysfs. They do not hold
> references to the patch kobject, so the patch kobject can be
> released independently, unblocking patch->finish before the child
> releases complete.
>
> 2. The patch kobject was added to sysfs, but a subsequent operation
> such as klp_add_nops() or klp_init_object() failed. Some child
> kobjects were initialized but not yet added to sysfs. These
> un-added children do not hold references to the patch kobject
> either, so the same race can occur.
In short, this says that the races might happen when some kobjects
were not added into sysfs. Am I right, please?
I agree. My undestading:
The klp_kobj_release_*() callbacks are called by kobject_cleanup()
which calls kobject_put(parent) as the last step. It should make sure
that:
+ klp_kobj_release_patch() is scheduled/called only when
klp_kobj_release_object() has been called for all patch->objs.
+ klp_kobj_release_object() is scheduled/called only when
klp_kobj_release_func() has been called for all obj->funcs.
But it works only when "kobj->parent" is set and
"parent->kref" has been incremented for each child before.
This is true only when kobject_add() is called for all all used
kobjects. But it is not guaranteed when any klp_init_*() failed.
> Fix this by tracking all static kobject releases with a per-patch
> atomic counter (kobj_pending). klp_free_patch_start() counts the
> patch kobject plus all static object and function kobjects.
> klp_free_patch_finish() waits until kobj_pending reaches zero,
> ensuring all kobject releases have completed before the module is
> unloaded.
I think that we do not need an extra couter. We might use
the existing kobj->kref. We just need to explicitely
increment/decrement it.
I mean something like:
diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c
index 28d15ba58a26..023f666ddcc4 100644
--- a/kernel/livepatch/core.c
+++ b/kernel/livepatch/core.c
@@ -652,6 +652,8 @@ static void klp_kobj_release_object(struct kobject *kobj)
if (obj->dynamic)
klp_free_object_dynamic(obj);
+ else
+ kobject_put(&obj->patch.kobj);
}
static const struct kobj_type klp_ktype_object = {
@@ -668,6 +670,8 @@ static void klp_kobj_release_func(struct kobject *kobj)
if (func->nop)
klp_free_func_nop(func);
+ else
+ kobject_put(&func->obj.kobj);
}
static const struct kobj_type klp_ktype_func = {
@@ -946,6 +950,7 @@ static void klp_init_func_early(struct klp_object *obj,
struct klp_func *func)
{
kobject_init(&func->kobj, &klp_ktype_func);
+ kobject_get(&obj->kobj);
list_add_tail(&func->node, &obj->func_list);
}
@@ -954,6 +959,7 @@ static void klp_init_object_early(struct klp_patch *patch,
{
INIT_LIST_HEAD(&obj->func_list);
kobject_init(&obj->kobj, &klp_ktype_object);
+ kobject_get(&patch->kobj);
list_add_tail(&obj->node, &patch->obj_list);
}
We really would need to add the back references (obj->patch,
func->obj) because we could not rely on kobj->parent. It is
set only when kobject_add() was called...
That said, I doubt that livepatching is the only subsystem using
kobjects in static structures. It might make sense to handle
this on the kobject API level. I mean to add a kobject() API
which would just set kobj->parent and increment kobj->kref
and can't fail. But it seems to be against the existing philosophy
of the kobject API. So, we might need the workaround after all.
Best Regards,
Petr
next prev parent reply other threads:[~2026-08-19 11:18 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-16 9:04 [PATCH v2 0/2] ivepatch: Fix several bugs found during replace set implementation Yafang Shao
2026-08-16 9:04 ` [PATCH v2 1/2] livepatch: Fix wrong index in funcs cleanup error path Yafang Shao
2026-08-16 9:04 ` [PATCH v2 2/2] livepatch: Fix UAF of unregistered patch kobjects Yafang Shao
2026-08-19 11:18 ` Petr Mladek [this message]
2026-08-19 12:37 ` Yafang Shao
2026-08-19 12:59 ` Petr Mladek
2026-08-19 10:24 ` [PATCH v2 0/2] ivepatch: Fix several bugs found during replace set implementation Petr Mladek
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=aoWRDIjvE5jYNR9_@pathway.suse.cz \
--to=pmladek@suse.com \
--cc=jikos@kernel.org \
--cc=joe.lawrence@redhat.com \
--cc=jpoimboe@kernel.org \
--cc=laoar.shao@gmail.com \
--cc=live-patching@vger.kernel.org \
--cc=mbenes@suse.cz \
--cc=sashiko-bot@kernel.org \
--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.