* [Patch net] ipv6: check for ip6_null_entry in __ip6_del_rt_siblings()
@ 2017-02-27 19:07 Cong Wang
2017-02-27 20:34 ` Eric Dumazet
0 siblings, 1 reply; 7+ messages in thread
From: Cong Wang @ 2017-02-27 19:07 UTC (permalink / raw)
To: netdev; +Cc: andreyknvl, Cong Wang
Andrey reported a NULL pointer deref bug in ipv6_route_ioctl()
-> ip6_route_del() -> __ip6_del_rt_siblings() code path. This is
because ip6_null_entry is returned in this path since ip6_null_entry
is kinda default for a ipv6 route table root node. Quote from
David Ahern:
ip6_null_entry is the root of all ipv6 fib tables making it integrated
into the table ...
We should ignore any attempt of trying to delete it, like we do in
__ip6_del_rt() path and several others.
Reported-by: Andrey Konovalov <andreyknvl@google.com>
Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
---
net/ipv6/route.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index f54f426..9da77e9 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -2169,10 +2169,13 @@ int ip6_del_rt(struct rt6_info *rt)
static int __ip6_del_rt_siblings(struct rt6_info *rt, struct fib6_config *cfg)
{
struct nl_info *info = &cfg->fc_nlinfo;
+ struct net *net = info->nl_net;
struct sk_buff *skb = NULL;
struct fib6_table *table;
int err;
+ if (rt == net->ipv6.ip6_null_entry)
+ return -ENOENT;
table = rt->rt6i_table;
write_lock_bh(&table->tb6_lock);
@@ -2184,7 +2187,7 @@ static int __ip6_del_rt_siblings(struct rt6_info *rt, struct fib6_config *cfg)
if (skb) {
u32 seq = info->nlh ? info->nlh->nlmsg_seq : 0;
- if (rt6_fill_node(info->nl_net, skb, rt,
+ if (rt6_fill_node(net, skb, rt,
NULL, NULL, 0, RTM_DELROUTE,
info->portid, seq, 0) < 0) {
kfree_skb(skb);
@@ -2208,7 +2211,7 @@ static int __ip6_del_rt_siblings(struct rt6_info *rt, struct fib6_config *cfg)
ip6_rt_put(rt);
if (skb) {
- rtnl_notify(skb, info->nl_net, info->portid, RTNLGRP_IPV6_ROUTE,
+ rtnl_notify(skb, net, info->portid, RTNLGRP_IPV6_ROUTE,
info->nlh, gfp_any());
}
return err;
--
2.5.5
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [Patch net] ipv6: check for ip6_null_entry in __ip6_del_rt_siblings()
2017-02-27 19:07 [Patch net] ipv6: check for ip6_null_entry in __ip6_del_rt_siblings() Cong Wang
@ 2017-02-27 20:34 ` Eric Dumazet
2017-02-27 20:55 ` Cong Wang
2017-02-27 21:00 ` David Ahern
0 siblings, 2 replies; 7+ messages in thread
From: Eric Dumazet @ 2017-02-27 20:34 UTC (permalink / raw)
To: Cong Wang; +Cc: netdev, andreyknvl
On Mon, 2017-02-27 at 11:07 -0800, Cong Wang wrote:
> Andrey reported a NULL pointer deref bug in ipv6_route_ioctl()
> -> ip6_route_del() -> __ip6_del_rt_siblings() code path. This is
> because ip6_null_entry is returned in this path since ip6_null_entry
> is kinda default for a ipv6 route table root node. Quote from
> David Ahern:
>
> ip6_null_entry is the root of all ipv6 fib tables making it integrated
> into the table ...
>
> We should ignore any attempt of trying to delete it, like we do in
> __ip6_del_rt() path and several others.
>
> Reported-by: Andrey Konovalov <andreyknvl@google.com>
> Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
> ---
> net/ipv6/route.c | 7 +++++--
> 1 file changed, 5 insertions(+), 2 deletions(-)
>
> diff --git a/net/ipv6/route.c b/net/ipv6/route.c
> index f54f426..9da77e9 100644
> --- a/net/ipv6/route.c
> +++ b/net/ipv6/route.c
> @@ -2169,10 +2169,13 @@ int ip6_del_rt(struct rt6_info *rt)
> static int __ip6_del_rt_siblings(struct rt6_info *rt, struct fib6_config *cfg)
> {
> struct nl_info *info = &cfg->fc_nlinfo;
> + struct net *net = info->nl_net;
> struct sk_buff *skb = NULL;
> struct fib6_table *table;
> int err;
>
> + if (rt == net->ipv6.ip6_null_entry)
> + return -ENOENT;
It looks the caller did a dst_hold(&rt->dst);
So this new error path would leave a refcount leak.
Note that I was not able to trigger the crash on old kernels, so it
would be nice to get a precise idea of bug origin.
Thanks.
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [Patch net] ipv6: check for ip6_null_entry in __ip6_del_rt_siblings()
2017-02-27 20:34 ` Eric Dumazet
@ 2017-02-27 20:55 ` Cong Wang
2017-02-27 21:00 ` David Ahern
1 sibling, 0 replies; 7+ messages in thread
From: Cong Wang @ 2017-02-27 20:55 UTC (permalink / raw)
To: Eric Dumazet; +Cc: Linux Kernel Network Developers, Andrey Konovalov
On Mon, Feb 27, 2017 at 12:34 PM, Eric Dumazet <eric.dumazet@gmail.com> wrote:
> On Mon, 2017-02-27 at 11:07 -0800, Cong Wang wrote:
>> Andrey reported a NULL pointer deref bug in ipv6_route_ioctl()
>> -> ip6_route_del() -> __ip6_del_rt_siblings() code path. This is
>> because ip6_null_entry is returned in this path since ip6_null_entry
>> is kinda default for a ipv6 route table root node. Quote from
>> David Ahern:
>>
>> ip6_null_entry is the root of all ipv6 fib tables making it integrated
>> into the table ...
>>
>> We should ignore any attempt of trying to delete it, like we do in
>> __ip6_del_rt() path and several others.
>>
>> Reported-by: Andrey Konovalov <andreyknvl@google.com>
>> Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
>> ---
>> net/ipv6/route.c | 7 +++++--
>> 1 file changed, 5 insertions(+), 2 deletions(-)
>>
>> diff --git a/net/ipv6/route.c b/net/ipv6/route.c
>> index f54f426..9da77e9 100644
>> --- a/net/ipv6/route.c
>> +++ b/net/ipv6/route.c
>> @@ -2169,10 +2169,13 @@ int ip6_del_rt(struct rt6_info *rt)
>> static int __ip6_del_rt_siblings(struct rt6_info *rt, struct fib6_config *cfg)
>> {
>> struct nl_info *info = &cfg->fc_nlinfo;
>> + struct net *net = info->nl_net;
>> struct sk_buff *skb = NULL;
>> struct fib6_table *table;
>> int err;
>>
>> + if (rt == net->ipv6.ip6_null_entry)
>> + return -ENOENT;
>
> It looks the caller did a dst_hold(&rt->dst);
>
> So this new error path would leave a refcount leak.
Interesting, this error path is not new for __ip6_del_rt_siblings()
so the leak was already there before mine, but you are probably
right we have a leak here.
I will send a separate patch to address this leak.
>
> Note that I was not able to trigger the crash on old kernels, so it
> would be nice to get a precise idea of bug origin.
Right, I miss:
Fixes: 0ae8133586ad ("net: ipv6: Allow shorthand delete of all
nexthops in multipath route")
Thanks!
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [Patch net] ipv6: check for ip6_null_entry in __ip6_del_rt_siblings()
2017-02-27 20:34 ` Eric Dumazet
2017-02-27 20:55 ` Cong Wang
@ 2017-02-27 21:00 ` David Ahern
2017-02-27 21:04 ` Cong Wang
1 sibling, 1 reply; 7+ messages in thread
From: David Ahern @ 2017-02-27 21:00 UTC (permalink / raw)
To: Eric Dumazet, Cong Wang; +Cc: netdev, andreyknvl
On 2/27/17 12:34 PM, Eric Dumazet wrote:
> On Mon, 2017-02-27 at 11:07 -0800, Cong Wang wrote:
>> Andrey reported a NULL pointer deref bug in ipv6_route_ioctl()
>> -> ip6_route_del() -> __ip6_del_rt_siblings() code path. This is
>> because ip6_null_entry is returned in this path since ip6_null_entry
>> is kinda default for a ipv6 route table root node. Quote from
>> David Ahern:
>>
>> ip6_null_entry is the root of all ipv6 fib tables making it integrated
>> into the table ...
>>
>> We should ignore any attempt of trying to delete it, like we do in
>> __ip6_del_rt() path and several others.
>>
>> Reported-by: Andrey Konovalov <andreyknvl@google.com>
>> Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
>> ---
>> net/ipv6/route.c | 7 +++++--
>> 1 file changed, 5 insertions(+), 2 deletions(-)
>>
>> diff --git a/net/ipv6/route.c b/net/ipv6/route.c
>> index f54f426..9da77e9 100644
>> --- a/net/ipv6/route.c
>> +++ b/net/ipv6/route.c
>> @@ -2169,10 +2169,13 @@ int ip6_del_rt(struct rt6_info *rt)
>> static int __ip6_del_rt_siblings(struct rt6_info *rt, struct fib6_config *cfg)
>> {
>> struct nl_info *info = &cfg->fc_nlinfo;
>> + struct net *net = info->nl_net;
>> struct sk_buff *skb = NULL;
>> struct fib6_table *table;
>> int err;
>>
>> + if (rt == net->ipv6.ip6_null_entry)
>> + return -ENOENT;
>
> It looks the caller did a dst_hold(&rt->dst);
>
> So this new error path would leave a refcount leak.
>
> Note that I was not able to trigger the crash on old kernels, so it
> would be nice to get a precise idea of bug origin.
>
Cong: do you want to send a v2 catching the null entry in ip6_route_del
before the refcnt?
for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
+ /* do not allow deletion of the null route */
+ if (rt == net->ipv6.ip6_null_entry)
+ continue;
Fixes: 0ae8133586ad net: ipv6: Allow shorthand delete of all nexthops in
multipath route
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [Patch net] ipv6: check for ip6_null_entry in __ip6_del_rt_siblings()
2017-02-27 21:00 ` David Ahern
@ 2017-02-27 21:04 ` Cong Wang
2017-02-27 21:06 ` David Ahern
0 siblings, 1 reply; 7+ messages in thread
From: Cong Wang @ 2017-02-27 21:04 UTC (permalink / raw)
To: David Ahern
Cc: Eric Dumazet, Linux Kernel Network Developers, Andrey Konovalov
On Mon, Feb 27, 2017 at 1:00 PM, David Ahern <dsa@cumulusnetworks.com> wrote:
> On 2/27/17 12:34 PM, Eric Dumazet wrote:
>> On Mon, 2017-02-27 at 11:07 -0800, Cong Wang wrote:
>>> Andrey reported a NULL pointer deref bug in ipv6_route_ioctl()
>>> -> ip6_route_del() -> __ip6_del_rt_siblings() code path. This is
>>> because ip6_null_entry is returned in this path since ip6_null_entry
>>> is kinda default for a ipv6 route table root node. Quote from
>>> David Ahern:
>>>
>>> ip6_null_entry is the root of all ipv6 fib tables making it integrated
>>> into the table ...
>>>
>>> We should ignore any attempt of trying to delete it, like we do in
>>> __ip6_del_rt() path and several others.
>>>
>>> Reported-by: Andrey Konovalov <andreyknvl@google.com>
>>> Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
>>> ---
>>> net/ipv6/route.c | 7 +++++--
>>> 1 file changed, 5 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/net/ipv6/route.c b/net/ipv6/route.c
>>> index f54f426..9da77e9 100644
>>> --- a/net/ipv6/route.c
>>> +++ b/net/ipv6/route.c
>>> @@ -2169,10 +2169,13 @@ int ip6_del_rt(struct rt6_info *rt)
>>> static int __ip6_del_rt_siblings(struct rt6_info *rt, struct fib6_config *cfg)
>>> {
>>> struct nl_info *info = &cfg->fc_nlinfo;
>>> + struct net *net = info->nl_net;
>>> struct sk_buff *skb = NULL;
>>> struct fib6_table *table;
>>> int err;
>>>
>>> + if (rt == net->ipv6.ip6_null_entry)
>>> + return -ENOENT;
>>
>> It looks the caller did a dst_hold(&rt->dst);
>>
>> So this new error path would leave a refcount leak.
>>
>> Note that I was not able to trigger the crash on old kernels, so it
>> would be nice to get a precise idea of bug origin.
>>
>
> Cong: do you want to send a v2 catching the null entry in ip6_route_del
> before the refcnt?
Yeah, actually it is introduced by my patch because there is already
an ip6_rt_put() in __ip6_del_rt_siblings(). So v2 is coming...
>
> for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
> + /* do not allow deletion of the null route */
> + if (rt == net->ipv6.ip6_null_entry)
> + continue;
>
> Fixes: 0ae8133586ad net: ipv6: Allow shorthand delete of all nexthops in
> multipath route
Note, I moved the check into __ip6_del_rt_siblings() because __ip6_del_rt()
has a same check.
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [Patch net] ipv6: check for ip6_null_entry in __ip6_del_rt_siblings()
2017-02-27 21:04 ` Cong Wang
@ 2017-02-27 21:06 ` David Ahern
2017-02-27 21:12 ` Cong Wang
0 siblings, 1 reply; 7+ messages in thread
From: David Ahern @ 2017-02-27 21:06 UTC (permalink / raw)
To: Cong Wang; +Cc: Eric Dumazet, Linux Kernel Network Developers, Andrey Konovalov
On 2/27/17 1:04 PM, Cong Wang wrote:
>>
>> for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
>> + /* do not allow deletion of the null route */
>> + if (rt == net->ipv6.ip6_null_entry)
>> + continue;
>>
>> Fixes: 0ae8133586ad net: ipv6: Allow shorthand delete of all nexthops in
>> multipath route
>
> Note, I moved the check into __ip6_del_rt_siblings() because __ip6_del_rt()
> has a same check.
>
that's b/c __ip6_del_rt has a second call path. __ip6_del_rt_siblings is
new and is not expecting to see the null entry. Catching it before the
dst_hold would be better.
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [Patch net] ipv6: check for ip6_null_entry in __ip6_del_rt_siblings()
2017-02-27 21:06 ` David Ahern
@ 2017-02-27 21:12 ` Cong Wang
0 siblings, 0 replies; 7+ messages in thread
From: Cong Wang @ 2017-02-27 21:12 UTC (permalink / raw)
To: David Ahern
Cc: Eric Dumazet, Linux Kernel Network Developers, Andrey Konovalov
On Mon, Feb 27, 2017 at 1:06 PM, David Ahern <dsa@cumulusnetworks.com> wrote:
> On 2/27/17 1:04 PM, Cong Wang wrote:
>>>
>>> for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
>>> + /* do not allow deletion of the null route */
>>> + if (rt == net->ipv6.ip6_null_entry)
>>> + continue;
>>>
>>> Fixes: 0ae8133586ad net: ipv6: Allow shorthand delete of all nexthops in
>>> multipath route
>>
>> Note, I moved the check into __ip6_del_rt_siblings() because __ip6_del_rt()
>> has a same check.
>>
>
> that's b/c __ip6_del_rt has a second call path. __ip6_del_rt_siblings is
> new and is not expecting to see the null entry. Catching it before the
> dst_hold would be better.
Yeah, but it also depends on if we want to continue after the null entry,
at least __ip6_del_rt () returns an error for null entry, which looks more
correct than continuing to proceed after it.
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2017-02-28 1:31 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-02-27 19:07 [Patch net] ipv6: check for ip6_null_entry in __ip6_del_rt_siblings() Cong Wang
2017-02-27 20:34 ` Eric Dumazet
2017-02-27 20:55 ` Cong Wang
2017-02-27 21:00 ` David Ahern
2017-02-27 21:04 ` Cong Wang
2017-02-27 21:06 ` David Ahern
2017-02-27 21:12 ` Cong Wang
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).