[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date: Tue, 10 Oct 2017 07:12:25 -0700
From: Eric Dumazet <eric.dumazet@...il.com>
To: Alexander Aring <aring@...atatu.com>
Cc: jhs@...atatu.com, xiyou.wangcong@...il.com, jiri@...nulli.us,
netdev@...r.kernel.org, kurup.manish@...il.com, bjb@...atatu.com
Subject: Re: [RFC net 1/1] net: sched: act: fix rcu race in dump
On Tue, 2017-10-10 at 08:32 -0400, Alexander Aring wrote:
> This patch fixes an issue with kfree_rcu which is not protected by RTNL
> lock. It could be that the current assigned rcu pointer will be freed by
> kfree_rcu while dump callback is running.
>
> To prevent this, we call rcu_synchronize at first. Then we are sure all
> latest rcu functions e.g. rcu_assign_pointer and kfree_rcu in init are
> done. After rcu_synchronize we dereference under RTNL lock which is also
> held in init function, which means no other rcu_assign_pointer or
> kfree_rcu will occur.
>
> To call rcu_synchronize will also prevent weird behaviours by doing over
> netlink:
>
> - set params A
> - set params B
> - dump params
> \--> will dump params A
>
> This could be a unlikely case that the last rcu_assign_pointer was not
> happened before dump callback.
>
> Signed-off-by: Alexander Aring <aring@...atatu.com>
> ---
> net/sched/act_skbmod.c | 7 ++++++-
> 1 file changed, 6 insertions(+), 1 deletion(-)
>
> diff --git a/net/sched/act_skbmod.c b/net/sched/act_skbmod.c
> index b642ad3d39dd..231e07bca384 100644
> --- a/net/sched/act_skbmod.c
> +++ b/net/sched/act_skbmod.c
> @@ -198,7 +198,7 @@ static int tcf_skbmod_dump(struct sk_buff *skb, struct tc_action *a,
> {
> struct tcf_skbmod *d = to_skbmod(a);
> unsigned char *b = skb_tail_pointer(skb);
> - struct tcf_skbmod_params *p = rtnl_dereference(d->skbmod_p);
> + struct tcf_skbmod_params *p;
> struct tc_skbmod opt = {
> .index = d->tcf_index,
> .refcnt = d->tcf_refcnt - ref,
> @@ -207,6 +207,11 @@ static int tcf_skbmod_dump(struct sk_buff *skb, struct tc_action *a,
> };
> struct tcf_t t;
>
> + /* wait until last rcu_assign_pointer/kfree_rcu is done */
> + rcu_synchronize();
> + /* RTNL lock prevents another rcu_assign_pointer/kfree_rcu call */
> + p = rtnl_dereference(d->skbmod_p);
> +
> opt.flags = p->flags;
> if (nla_put(skb, TCA_SKBMOD_PARMS, sizeof(opt), &opt))
> goto nla_put_failure;
Sorry but no. This is plainly wrong.
We need to fix this without adding a _very_ expensive rcu_synchronize()
on a path which does not need such thing.
I am confused by this patch, please tell us more what the problem is.
I suspect rcu_read_lock() is what you need, but isn't a writer supposed
to hold RTNL in net/sched/* ???
Powered by blists - more mailing lists