From: Cong Wang <hidden> Date: 2017-02-27 19:16:21
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 <redacted>
Signed-off-by: Cong Wang <redacted>
---
net/ipv6/route.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
From: Eric Dumazet <hidden> Date: 2017-02-27 20:42:03
On Mon, 2017-02-27 at 11:07 -0800, Cong Wang wrote:
quoted hunk
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 <redacted>
Signed-off-by: Cong Wang <redacted>
---
net/ipv6/route.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
@@ -2169,10 +2169,13 @@ int ip6_del_rt(struct rt6_info *rt)staticint__ip6_del_rt_siblings(structrt6_info*rt,structfib6_config*cfg){structnl_info*info=&cfg->fc_nlinfo;+structnet*net=info->nl_net;structsk_buff*skb=NULL;structfib6_table*table;interr;+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.
From: Cong Wang <hidden> Date: 2017-02-27 20:57:00
On Mon, Feb 27, 2017 at 12:34 PM, Eric Dumazet [off-list ref] wrote:
On Mon, 2017-02-27 at 11:07 -0800, Cong Wang wrote:
quoted
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 <redacted>
Signed-off-by: Cong Wang <redacted>
---
net/ipv6/route.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
@@ -2169,10 +2169,13 @@ int ip6_del_rt(struct rt6_info *rt)staticint__ip6_del_rt_siblings(structrt6_info*rt,structfib6_config*cfg){structnl_info*info=&cfg->fc_nlinfo;+structnet*net=info->nl_net;structsk_buff*skb=NULL;structfib6_table*table;interr;+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!
From: David Ahern <hidden> Date: 2017-02-27 21:01:07
On 2/27/17 12:34 PM, Eric Dumazet wrote:
On Mon, 2017-02-27 at 11:07 -0800, Cong Wang wrote:
quoted
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 <redacted>
Signed-off-by: Cong Wang <redacted>
---
net/ipv6/route.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
@@ -2169,10 +2169,13 @@ int ip6_del_rt(struct rt6_info *rt)staticint__ip6_del_rt_siblings(structrt6_info*rt,structfib6_config*cfg){structnl_info*info=&cfg->fc_nlinfo;+structnet*net=info->nl_net;structsk_buff*skb=NULL;structfib6_table*table;interr;+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
From: Cong Wang <hidden> Date: 2017-02-27 21:34:55
On Mon, Feb 27, 2017 at 1:00 PM, David Ahern [off-list ref] wrote:
On 2/27/17 12:34 PM, Eric Dumazet wrote:
quoted
On Mon, 2017-02-27 at 11:07 -0800, Cong Wang wrote:
quoted
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 <redacted>
Signed-off-by: Cong Wang <redacted>
---
net/ipv6/route.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
@@ -2169,10 +2169,13 @@ int ip6_del_rt(struct rt6_info *rt)staticint__ip6_del_rt_siblings(structrt6_info*rt,structfib6_config*cfg){structnl_info*info=&cfg->fc_nlinfo;+structnet*net=info->nl_net;structsk_buff*skb=NULL;structfib6_table*table;interr;+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.
From: David Ahern <hidden> Date: 2017-02-27 22:10:18
On 2/27/17 1:04 PM, Cong Wang wrote:
quoted
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.
From: Cong Wang <hidden> Date: 2017-02-28 01:31:37
On Mon, Feb 27, 2017 at 1:06 PM, David Ahern [off-list ref] wrote:
On 2/27/17 1:04 PM, Cong Wang wrote:
quoted
quoted
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.