[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20150722131603.GA22351@t440s.lenovo>
Date: Wed, 22 Jul 2015 21:17:22 +0800
From: Minfei Huang <mnfhuang@...il.com>
To: Minfei Huang <mhuang@...hat.com>
Cc: jpoimboe@...hat.com, sjenning@...hat.com, jkosina@...e.cz,
vojtech@...e.cz, live-patching@...r.kernel.org,
linux-kernel@...r.kernel.org
Subject: Re: [PATCH] livepatch: Fix the issue to make livepatch
enable/disable patch correctly
Could someone help to review this patch?
Thanks
Minfei
On 07/15/15 at 04:55pm, Minfei Huang wrote:
> From: Minfei Huang <mnfhuang@...il.com>
>
> Livepatch will obey the stacking rule to enable/disable the patch. It
> only allows to enable the patch, when it is the fist disabled patch,
> disable the patch, when it is the last enabled patch.
>
> In the livepatch code, it uses list to gather the all of the patches.
> And we do not know whether the previous/next patch is patched to the
> same modules or vmlinux in that way.
>
> According to above rule, livepatch will make incorrect decision to
> enable/disable the patch. Following is an example to show how livepatch
> does.
>
> - install the livepatch example module which is in samples/livepatch.
> - install the third part kernel module
> - install the livepatch module which is patched to the third part module
> - disable the livepatch example module
>
> We can find that we can not disable livepatch example module, although
> it is the last enabled patch.
>
> To fix this issue, we will find the corresponding patch which is patched
> to the same modules or vmlinux, when we enable/disable the patch.
>
> Signed-off-by: Minfei Huang <mnfhuang@...il.com>
> ---
> kernel/livepatch/core.c | 55 +++++++++++++++++++++++++++++++++++++++++++++----
> 1 file changed, 51 insertions(+), 4 deletions(-)
>
> diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c
> index 6e53441..d59aec7 100644
> --- a/kernel/livepatch/core.c
> +++ b/kernel/livepatch/core.c
> @@ -429,6 +429,27 @@ err:
> return ret;
> }
>
> +static bool is_patched_to_same(struct klp_patch *p1, struct klp_patch *p2)
> +{
> + struct klp_object *obj1, *obj2;
> + bool is_mod1, is_mod2;
> +
> + klp_for_each_object(p1, obj1) {
> + klp_for_each_object(p2, obj2) {
> + is_mod1 = !!klp_is_module(obj1);
> + is_mod2 = !!klp_is_module(obj2);
> +
> + if (is_mod1 && is_mod2) {
> + if (!strcmp(obj1->name, obj2->name))
> + return true;
> + } else if (!is_mod1 && !is_mod2)
> + return true;
> + }
> + }
> +
> + return false;
> +}
> +
> static void klp_disable_object(struct klp_object *obj)
> {
> struct klp_func *func;
> @@ -463,13 +484,26 @@ static int klp_enable_object(struct klp_object *obj)
> return 0;
> }
>
> +struct klp_patch *get_next_patch(struct klp_patch *patch)
> +{
> + struct klp_patch *p = patch;
> +
> + list_for_each_entry_continue(p, &klp_patches, list) {
> + if (is_patched_to_same(p, patch))
> + return p;
> + }
> +
> + return NULL;
> +}
> +
> static int __klp_disable_patch(struct klp_patch *patch)
> {
> + struct klp_patch *p;
> struct klp_object *obj;
>
> /* enforce stacking: only the last enabled patch can be disabled */
> - if (!list_is_last(&patch->list, &klp_patches) &&
> - list_next_entry(patch, list)->state == KLP_ENABLED)
> + p = get_next_patch(patch);
> + if (p && (p->state == KLP_ENABLED))
> return -EBUSY;
>
> pr_notice("disabling patch '%s'\n", patch->mod->name);
> @@ -516,8 +550,21 @@ err:
> }
> EXPORT_SYMBOL_GPL(klp_disable_patch);
>
> +struct klp_patch *get_prev_patch(struct klp_patch *patch)
> +{
> + struct klp_patch *p = patch;
> +
> + list_for_each_entry_continue_reverse(p, &klp_patches, list) {
> + if (is_patched_to_same(p, patch))
> + return p;
> + }
> +
> + return NULL;
> +}
> +
> static int __klp_enable_patch(struct klp_patch *patch)
> {
> + struct klp_patch *p;
> struct klp_object *obj;
> int ret;
>
> @@ -525,8 +572,8 @@ static int __klp_enable_patch(struct klp_patch *patch)
> return -EINVAL;
>
> /* enforce stacking: only the first disabled patch can be enabled */
> - if (patch->list.prev != &klp_patches &&
> - list_prev_entry(patch, list)->state == KLP_DISABLED)
> + p = get_prev_patch(patch);
> + if (p && (p->state == KLP_DISABLED))
> return -EBUSY;
>
> pr_notice_once("tainting kernel with TAINT_LIVEPATCH\n");
> --
> 2.2.2
>
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists