[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <6b4b7165-5438-df65-3a43-7dcb576dab93@huawei.com>
Date: Tue, 3 Aug 2021 10:11:18 +0800
From: Kefeng Wang <wangkefeng.wang@...wei.com>
To: <linux-kernel@...r.kernel.org>, <netdev@...r.kernel.org>
CC: Hannes Frederic Sowa <hannes@...essinduktion.org>,
Daniel Borkmann <daniel@...earbox.net>,
"David S . Miller" <davem@...emloft.net>,
"Eric Dumazet" <edumazet@...gle.com>,
Minmin chen <chenmingmin@...wei.com>,
"Jakub Kicinski" <kuba@...nel.org>,
Greg Kroah-Hartman <gregkh@...uxfoundation.org>,
Andrew Morton <akpm@...ux-foundation.org>
Subject: Re: [PATCH] once: Fix panic when module unload
Hi ALL, I don't know who maintain the lib/once.c, add Greg and Andrew too,
Hi David, I check the history, the lib/once.c is from net/core/utils.c
since
commit 46234253b9363894a254844a6550b4cc5f3edfe8
Author: Hannes Frederic Sowa <hannes@...essinduktion.org>
Date: Thu Oct 8 01:20:35 2015 +0200
net: move net_get_random_once to lib
This bug is found in our product test, we want to make sure that whether
this solution
is correct or not, so could David or any others help to review this patch.
Many thinks.
On 2021/6/22 10:21, Kefeng Wang wrote:
> DO_ONCE
> DEFINE_STATIC_KEY_TRUE(___once_key);
> __do_once_done
> once_disable_jump(once_key);
> INIT_WORK(&w->work, once_deferred);
> struct once_work *w;
> w->key = key;
> schedule_work(&w->work); module unload
> //*the key is destroy*
> process_one_work
> once_deferred
> BUG_ON(!static_key_enabled(work->key));
> static_key_count((struct static_key *)x) //*access key, crash*
>
> When module uses DO_ONCE mechanism, it could crash due to the above
> concurrency problem, we could reproduce it with link[1].
>
> Fix it by add/put module refcount in the once work process.
>
> [1]
> https://lore.kernel.org/netdev/eaa6c371-465e-57eb-6be9-f4b16b9d7cbf@huawei.com/
>
> Cc: Hannes Frederic Sowa <hannes@...essinduktion.org>
> Cc: Daniel Borkmann <daniel@...earbox.net>
> Cc: David S. Miller <davem@...emloft.net>
> Cc: Eric Dumazet <edumazet@...gle.com>
> Reported-by: Minmin chen <chenmingmin@...wei.com>
> Signed-off-by: Kefeng Wang <wangkefeng.wang@...wei.com>
> ---
> lib/once.c | 17 +++++++++++++++++
> 1 file changed, 17 insertions(+)
>
> diff --git a/lib/once.c b/lib/once.c
> index 8b7d6235217e..959f8db41ccf 100644
> --- a/lib/once.c
> +++ b/lib/once.c
> @@ -3,10 +3,12 @@
> #include <linux/spinlock.h>
> #include <linux/once.h>
> #include <linux/random.h>
> +#include <linux/module.h>
>
> struct once_work {
> struct work_struct work;
> struct static_key_true *key;
> + struct module *module;
> };
>
> static void once_deferred(struct work_struct *w)
> @@ -16,11 +18,24 @@ static void once_deferred(struct work_struct *w)
> work = container_of(w, struct once_work, work);
> BUG_ON(!static_key_enabled(work->key));
> static_branch_disable(work->key);
> + module_put(work->module);
> kfree(work);
> }
>
> +static struct module *find_module_by_key(struct static_key_true *key)
> +{
> + struct module *mod;
> +
> + preempt_disable();
> + mod = __module_address((unsigned long)key);
> + preempt_enable();
> +
> + return mod;
> +}
> +
> static void once_disable_jump(struct static_key_true *key)
> {
> + struct module *mod = find_module_by_key(key);
> struct once_work *w;
>
> w = kmalloc(sizeof(*w), GFP_ATOMIC);
> @@ -29,6 +44,8 @@ static void once_disable_jump(struct static_key_true *key)
>
> INIT_WORK(&w->work, once_deferred);
> w->key = key;
> + w->module = mod;
> + __module_get(mod);
> schedule_work(&w->work);
> }
>
Powered by blists - more mailing lists