Re: [PATCH v3 1/7] livepatch: Fix NULL pointer dereference in klp_find_func()
Yafang Shao <[email protected]> Tue, 23 Jun 2026 14:50:26 +0800
| Newsgroups | org.kernel.vger.live-patching |
|---|---|
| Message-ID | <CALOAHbAVZtmqHUpixhBx2295+cQUFGjW3cD_2o4H4eAvYpdOOw@mail.gmail.com> |
On Mon, Jun 22, 2026 at 10:21 PM Miroslav Benes <[email protected]> wrote: > > On 2026-06-09 15:27:18+02:00, Petr Mladek wrote: > > On Sun 2026-06-07 21:16:53, Yafang Shao wrote: > > > > > 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) > > > > > > --- a/kernel/livepatch/core.c > > > +++ b/kernel/livepatch/core.c > > > @@ -92,7 +92,7 @@ static struct klp_func *klp_find_func(struct klp_object *obj, > > > * Besides identical old_sympos, also consider old_sympos > > > * of 0 and 1 are identical. > > > */ > > > - if ((strcmp(old_func->old_name, func->old_name) == 0) && > > > + if ((func->old_name && strcmp(old_func->old_name, func->old_name) == 0) && > > > > I do not have a good feeling about this solution because it quietly > > ignores a problem. As a result, klp_add_object_nops() would > > call klp_alloc_func_nop() even though it does not make much sense. > > > > A livepatch where any func->oldname is not defined should get > > rejected. It will actually happen but _later_ in: > > > > + klp_init_patch() > > + klp_init_object() > > + klp_init_func() > > > > I see three better possibilities. > > > > 1. We could move/add the sanity checks into klp_init_patch_early() > > and return broken livepatches earlier. > > > > 2. We could move/add the sanity check into a new klp_check_patch() > > which will be called even before klp_init_patch_early(). > > > > 3. We could allow klp_find_func() to return ERR_PTR(-EINVAL). > > klp_add_object_nops() should then return the error as well. > > If you change it to do so. > > > My preference: > > > > I would do the 3rd variant because it is much easier than > > adding/moving all consistency checks between klp_init_*() and > > klp_init_*_early() or klp_check_*() functions. > > Interesting issue. If I remember correctly, klp_init_*() path is meant > for the initial checking originally (among others). That is why > klp_init_func() has it right at the beginning. It got a lot complicated > later. We introduced atomic replace feature which added klp_add_nops() > and is called earlier. Then there was the kobject issue which introduced > early init path. Both forgot about the check and that is what we have > now. I would prefer it to fix cleanly. klp_init_patch_early() is not > enough because klp_is_patch_compatible() is called even earlier. So your > option 2 sounds best to me. On the other hand, it might be difficult to > disentangle it all. > > Anyway, could you send the fix separately since it is an existing issue, > please? Does the following change look good to you ? diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c index 28d15ba58a26..317a3c866c76 100644 --- a/kernel/livepatch/core.c +++ b/kernel/livepatch/core.c @@ -799,9 +799,6 @@ void klp_free_replaced_patches_async(struct klp_patch *new_patch) static int klp_init_func(struct klp_object *obj, struct klp_func *func) { - if (!func->old_name) - return -EINVAL; - /* * NOPs get the address later. The patched module must be loaded, * see klp_init_object_loaded(). @@ -1107,8 +1104,9 @@ static int __klp_enable_patch(struct klp_patch *patch) */ int klp_enable_patch(struct klp_patch *patch) { - int ret; struct klp_object *obj; + struct klp_func *func; + int ret; if (!patch || !patch->mod || !patch->objs) return -EINVAL; @@ -1116,9 +1114,12 @@ int klp_enable_patch(struct klp_patch *patch) klp_for_each_object_static(patch, obj) { if (!obj->funcs) return -EINVAL; + klp_for_each_func_static(obj, func) { + if (!func->old_name) + return -EINVAL; + } } - if (!is_livepatch_module(patch->mod)) { pr_err("module %s is not marked as a livepatch module\n", patch->mod->name); -- Regards Yafang