lists.openwall.net | lists / announce owl-users owl-dev john-users john-dev passwdqc-users yescrypt popa3d-users / oss-security kernel-hardening musl sabotage tlsify passwords / crypt-dev xvendor / Bugtraq Full-Disclosure linux-kernel linux-netdev linux-ext4 linux-hardening linux-cve-announce PHC | |
Open Source and information security mailing list archives
| ||
|
Message-ID: <e4e4a347-1102-a9c3-5f44-4b59b467dc22@brocade.com> Date: Fri, 5 May 2017 17:51:30 +0100 From: Mike Manning <mmanning@...cade.com> To: Cong Wang <xiyou.wangcong@...il.com> CC: Linux Kernel Network Developers <netdev@...r.kernel.org>, Andrey Konovalov <andreyknvl@...gle.com>, David Miller <davem@...emloft.net> Subject: Re: [PATCH] net: ipv6: Fix warning of freeing alive inet6 address On 03/05/17 19:24, Mike Manning wrote: > On 03/05/17 18:58, Cong Wang wrote: >> On Tue, May 2, 2017 at 11:30 AM, Mike Manning <mmanning@...cade.com> wrote: >>> While this is not reproducible manually, Andrey's syzkaller program hit >>> the warning "IPv6: Freeing alive inet6 address" with this part trace: >>> >>> inet6_ifa_finish_destroy+0x12e/0x190 c:894 >>> in6_ifa_put ./include/net/addrconf.h:330 >>> addrconf_dad_work+0x4e9/0x1040 net/ipv6/addrconf.c:3963 >>> >>> The fix is to call in6_ifa_put() for the inet6_ifaddr before rather >>> than after calling addrconf_ifdown(), as the latter may remove it from >>> the address hash table. >>> >>> Fixes: 85b51b12115c ("net: ipv6: Remove addresses for failures with strict DAD") >>> Reported-by: Andrey Konovalov <andreyknvl@...gle.com> >>> Signed-off-by: Mike Manning <mmanning@...cade.com> >>> --- >>> net/ipv6/addrconf.c | 6 +++++- >>> 1 file changed, 5 insertions(+), 1 deletion(-) >>> >>> diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c >>> index 80ce478..361993a 100644 >>> --- a/net/ipv6/addrconf.c >>> +++ b/net/ipv6/addrconf.c >>> @@ -3902,8 +3902,11 @@ static void addrconf_dad_work(struct work_struct *w) >>> } else if (action == DAD_ABORT) { >>> in6_ifa_hold(ifp); >>> addrconf_dad_stop(ifp, 1); >>> - if (disable_ipv6) >>> + if (disable_ipv6) { >>> + in6_ifa_put(ifp); >>> addrconf_ifdown(idev->dev, 0); >>> + goto unlock; >>> + } >> >> >> But addrconf_dad_stop() calls ipv6_del_addr() which could unhash >> the addr too... >> Further investigation shows that none of the code block above is at fault. Debugging shows that the problem is happening with DAD_BEGIN and not DAD_ABORT. Follows more detail on the issue, but as I do not have a fix at this stage, I retract this submission altogether. The problem is due to rapidly adding the same address fd00::bb on ip6tnl0, and also without running DAD (accept_dad < 1), so it's an edge case. Typically the call to addrconf_dad_work() starts with an ifp refcnt of 3. Then via addrconf_dad_begin() and addrconf_dad_completed(), the call to addrconf_del_dad_work() results in a dec of the refcnt to 2 due to the call to cancel_delayed_work() returning 1. The 2nd normal case is if the call to addrconf_dad_work() starts with an ifp refcnt of 2, in which case the call to cancel_delayed_work() returns 0 and so no decrement of the refcnt, which correctly stays at 2. The error case is when the call to addrconf_dad_work() starts with an ifp refcnt of 2, but the call to cancel_delayed_work() then also results in a dec of the refcnt to 1, so the final in6_ifa_put() detects that the refcnt is being reduced to 0 for an active address. So the question is whether the interaction of cancel_delayed_work() in addrconf_dad_work(), delayed_work_pending() in addrconf_mod_dad_work() and INIT_DELAYED_WORK in ipv6_add_addr() [along with the handling for this when deleting addresses] needs improving, and if so how?
Powered by blists - more mailing lists