From: Josh Poimboeuf <jpoimboe@redhat.com>
To: Petr Mladek <pmladek@suse.com>
Cc: Joe Lawrence <joe.lawrence@redhat.com>,
live-patching@vger.kernel.org, linux-kernel@vger.kernel.org,
Jessica Yu <jeyu@redhat.com>, Jiri Kosina <jikos@kernel.org>,
Miroslav Benes <mbenes@suse.cz>
Subject: Re: [PATCH 3/3] livepatch: add shadow variable sample program
Date: Wed, 14 Jun 2017 09:57:56 -0500 [thread overview]
Message-ID: <20170614145756.gom3zf6uv7ua423h@treble> (raw)
In-Reply-To: <20170614142102.GA2583@pathway.suse.cz>
On Wed, Jun 14, 2017 at 04:21:02PM +0200, Petr Mladek wrote:
> On Thu 2017-06-01 14:25:26, Joe Lawrence wrote:
> > Modify the sample livepatch to demonstrate the shadow variable API.
> >
> > Signed-off-by: Joe Lawrence <joe.lawrence@redhat.com>
> > ---
> > samples/livepatch/livepatch-sample.c | 39 +++++++++++++++++++++++++++++++++++-
> > 1 file changed, 38 insertions(+), 1 deletion(-)
> >
> > diff --git a/samples/livepatch/livepatch-sample.c b/samples/livepatch/livepatch-sample.c
> > index 84795223f15f..e0236750cefb 100644
> > --- a/samples/livepatch/livepatch-sample.c
> > +++ b/samples/livepatch/livepatch-sample.c
> > @@ -25,26 +25,57 @@
> >
> > /*
> > * This (dumb) live patch overrides the function that prints the
> > - * kernel boot cmdline when /proc/cmdline is read.
> > + * kernel boot cmdline when /proc/cmdline is read. It also
> > + * demonstrates a contrived shadow-variable usage.
> > *
> > * Example:
> > *
> > * $ cat /proc/cmdline
> > * <your cmdline>
> > + * current=<current task pointer> count=<shadow variable counter>
> > *
> > * $ insmod livepatch-sample.ko
> > * $ cat /proc/cmdline
> > * this has been live patched
> > + * current=ffff8800331c9540 count=1
> > + * $ cat /proc/cmdline
> > + * this has been live patched
> > + * current=ffff8800331c9540 count=2
> > *
> > * $ echo 0 > /sys/kernel/livepatch/livepatch_sample/enabled
> > * $ cat /proc/cmdline
> > * <your cmdline>
> > */
> >
> > +static LIST_HEAD(shadow_list);
> > +
> > +struct task_ctr {
> > + struct list_head list;
> > + int count;
> > +};
> > +
> > #include <linux/seq_file.h>
> > +#include <linux/slab.h>
> > static int livepatch_cmdline_proc_show(struct seq_file *m, void *v)
> > {
> > + struct task_ctr *nd;
> > +
> > + nd = klp_shadow_get(current, "task_ctr");
> > + if (!nd) {
> > + nd = kzalloc(sizeof(*nd), GFP_KERNEL);
> > + if (nd) {
> > + list_add(&nd->list, &shadow_list);
> > + klp_shadow_attach(current, "task_ctr", GFP_KERNEL, nd);
> > + }
> > + }
>
> Hmm, this looks racy:
>
> CPU0 CPU1
>
> klp_shadow_get() klp_shadow_get()
> # returns NULL # returns NULL
> if (!nd) { if (!nd) {
> nd = kzalloc(); nd = kzalloc();
> list_add(&nd->list, list_add(&nd->list,
> &shadow_list); &shadow_list);
>
> BANG: This is one race. We add items into the shared shadow_list
> in parallel. The question is if we need it. IMHO, the API
> could help here, see the comments for livepatch_exit() below.
>
> klp_shadow_attach(); klp_shadow_attach();
>
> WARNING: This is fine because the shadow objects are for
> different objects. I mean that "current" must point
> to different processes on the two CPUs.
>
> But it is racy in general. The question is if the API
> could help here. A possibility might be to allow to
> define a callback function that would create the shadow
> structure when it does not exist. I mean something like
>
> typedef void (*klp_shadow_create_obj_func_t)(void * obj);
>
> void *klp_shadow_get_or_create(void *obj, int key, gfp_t gfp,
> klp_shadow_create_obj_fun_t *create)
> {
> struct klp_shadow *shadow;
>
> shadow = klp_shadow_get(obj, key);
>
> if (!shadow && create) {
> void *shadow_obj;
>
> spin_lock_irqsave(&klp_shadow_lock, flags);
> shadow = klp_shadow_get(obj, key);
> if (shadow)
> goto out;
>
> shadow_obj = create(obj);
> shadow = __klp_shadow_attach(obj, key, gfp,
> shadow_obj);
> out:
> spin_unlock_irqrestore(&klp_shadow_lock, flags);
> }
>
> return shadow;
> }
>
> I do not know. Maybe it is too ugly. Or will it safe a duplicated code
> in many cases?
I think this sample module is confusing because it uses the API in a
contrived way. In reality, we use it more like the API documentation
describes: klp_shadow_attach() is called right after the parent struct
is allocated and klp_shadow_detach() is called right before the parent
struct is freed. So the above race wouldn't normally exist.
I think Joe implemented it this way in order to keep it simple, so it
wouldn't have to use kallsyms to do manual relocations, etc. But maybe
a more realistic example would be better since it represents how things
should really be done in the absence of out-of-tree tooling like
kpatch-build or klp-convert.
> > seq_printf(m, "%s\n", "this has been live patched");
> > +
> > + if (nd) {
> > + nd->count++;
> > + seq_printf(m, "current=%p count=%d\n", current, nd->count);
> > + }
> > +
> > return 0;
> > }
> >
> > @@ -99,6 +130,12 @@ static int livepatch_init(void)
> >
> > static void livepatch_exit(void)
> > {
> > + struct task_ctr *nd, *tmp;
> > +
> > + list_for_each_entry_safe(nd, tmp, &shadow_list, list) {
> > + list_del(&nd->list);
> > + kfree(nd);
>
> I think that this will be a rather common operation. Do we need
> the extra list? It might be enough to delete all entries
> in the hash table with a given key. Well, we might need
> a callback again:
>
> typedef void (*klp_shadow_free_obj_func_t)(void *shadow_obj);
>
> void klp_shadow_free_all(int key, klp_shadow_free_obj_fun_t *shadow_free)
> {
> int i;
> struct klp_shadow *shadow;
>
> spin_lock_irqsave(&klp_shadow_lock, flags);
>
> hash_for_each(klp_shadow_hash, i, shadow, node) {
> hash_del_rcu(&shadow->node);
> /* patch and shadow data are not longer used. */
> shadow_free(shadow->shadow_obj);
> /*
> * shadow structure might still be traversed
> * by someone
> */
> kfree_rcu(shadow, rcu_head);
> }
> }
>
> spin_unlocklock_irqrestore(&klp_shadow_lock, flags);
> }
I often wonder whether it's really a good idea to even allow the
unloading of patch modules at all. It adds complexity to the livepatch
code. Is it worth it? I don't have an answer but I'd be interested in
other people's opinion.
--
Josh
next prev parent reply other threads:[~2017-06-14 14:58 UTC|newest]
Thread overview: 34+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-06-01 18:25 [PATCH 0/3] livepatch: add shadow variable API Joe Lawrence
2017-06-01 18:25 ` [PATCH 1/3] livepatch: introduce " Joe Lawrence
2017-06-08 16:49 ` Josh Poimboeuf
2017-06-09 15:36 ` Joe Lawrence
2017-06-09 18:34 ` Josh Poimboeuf
2017-06-12 13:49 ` Joe Lawrence
2017-06-14 12:59 ` Petr Mladek
2017-06-14 13:17 ` Josh Poimboeuf
2017-06-14 14:26 ` Petr Mladek
2017-06-19 16:09 ` Miroslav Benes
2017-06-01 18:25 ` [PATCH 2/3] livepatch: add shadow variable documentation Joe Lawrence
2017-06-14 13:10 ` Petr Mladek
2017-06-01 18:25 ` [PATCH 3/3] livepatch: add shadow variable sample program Joe Lawrence
2017-06-09 18:38 ` Josh Poimboeuf
2017-06-09 19:05 ` Joe Lawrence
2017-06-13 11:00 ` Miroslav Benes
2017-06-13 17:32 ` Joe Lawrence
2017-06-14 7:45 ` Miroslav Benes
2017-06-14 14:21 ` Petr Mladek
2017-06-14 14:57 ` Josh Poimboeuf [this message]
2017-06-15 10:59 ` Petr Mladek
2017-06-15 13:49 ` Josh Poimboeuf
[not found] ` <20170615143800.d6f5p5bdm4ueecly@redhat.com>
2017-06-15 15:23 ` Josh Poimboeuf
2017-06-19 16:56 ` Miroslav Benes
2017-06-30 20:32 ` Josh Poimboeuf
2017-07-01 6:53 ` Miroslav Benes
2017-06-14 15:15 ` Joe Lawrence
2017-06-19 16:43 ` Miroslav Benes
2017-06-01 20:05 ` [PATCH 0/3] livepatch: add shadow variable API Jiri Kosina
2017-06-01 20:23 ` Joe Lawrence
2017-06-01 20:32 ` Jiri Kosina
2017-06-13 10:19 ` Miroslav Benes
2017-06-13 17:29 ` Joe Lawrence
2017-06-14 8:02 ` Miroslav Benes
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=20170614145756.gom3zf6uv7ua423h@treble \
--to=jpoimboe@redhat.com \
--cc=jeyu@redhat.com \
--cc=jikos@kernel.org \
--cc=joe.lawrence@redhat.com \
--cc=linux-kernel@vger.kernel.org \
--cc=live-patching@vger.kernel.org \
--cc=mbenes@suse.cz \
--cc=pmladek@suse.com \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®