linux/net/bridge
Xin Long b1b9d36602 bridge: move bridge multicast cleanup to ndo_uninit
During removing a bridge device, if the bridge is still up, a new mdb entry
still can be added in br_multicast_add_group() after all mdb entries are
removed in br_multicast_dev_del(). Like the path:

  mld_ifc_timer_expire ->
    mld_sendpack -> ...
      br_multicast_rcv ->
        br_multicast_add_group

The new mp's timer will be set up. If the timer expires after the bridge
is freed, it may cause use-after-free panic in br_multicast_group_expired.

BUG: unable to handle kernel NULL pointer dereference at 0000000000000048
IP: [<ffffffffa07ed2c8>] br_multicast_group_expired+0x28/0xb0 [bridge]
Call Trace:
 <IRQ>
 [<ffffffff81094536>] call_timer_fn+0x36/0x110
 [<ffffffffa07ed2a0>] ? br_mdb_free+0x30/0x30 [bridge]
 [<ffffffff81096967>] run_timer_softirq+0x237/0x340
 [<ffffffff8108dcbf>] __do_softirq+0xef/0x280
 [<ffffffff8169889c>] call_softirq+0x1c/0x30
 [<ffffffff8102c275>] do_softirq+0x65/0xa0
 [<ffffffff8108e055>] irq_exit+0x115/0x120
 [<ffffffff81699515>] smp_apic_timer_interrupt+0x45/0x60
 [<ffffffff81697a5d>] apic_timer_interrupt+0x6d/0x80

Nikolay also found it would cause a memory leak - the mdb hash is
reallocated and not freed due to the mdb rehash.

unreferenced object 0xffff8800540ba800 (size 2048):
  backtrace:
    [<ffffffff816e2287>] kmemleak_alloc+0x67/0xc0
    [<ffffffff81260bea>] __kmalloc+0x1ba/0x3e0
    [<ffffffffa05c60ee>] br_mdb_rehash+0x5e/0x340 [bridge]
    [<ffffffffa05c74af>] br_multicast_new_group+0x43f/0x6e0 [bridge]
    [<ffffffffa05c7aa3>] br_multicast_add_group+0x203/0x260 [bridge]
    [<ffffffffa05ca4b5>] br_multicast_rcv+0x945/0x11d0 [bridge]
    [<ffffffffa05b6b10>] br_dev_xmit+0x180/0x470 [bridge]
    [<ffffffff815c781b>] dev_hard_start_xmit+0xbb/0x3d0
    [<ffffffff815c8743>] __dev_queue_xmit+0xb13/0xc10
    [<ffffffff815c8850>] dev_queue_xmit+0x10/0x20
    [<ffffffffa02f8d7a>] ip6_finish_output2+0x5ca/0xac0 [ipv6]
    [<ffffffffa02fbfc6>] ip6_finish_output+0x126/0x2c0 [ipv6]
    [<ffffffffa02fc245>] ip6_output+0xe5/0x390 [ipv6]
    [<ffffffffa032b92c>] NF_HOOK.constprop.44+0x6c/0x240 [ipv6]
    [<ffffffffa032bd16>] mld_sendpack+0x216/0x3e0 [ipv6]
    [<ffffffffa032d5eb>] mld_ifc_timer_expire+0x18b/0x2b0 [ipv6]

This could happen when ip link remove a bridge or destroy a netns with a
bridge device inside.

With Nikolay's suggestion, this patch is to clean up bridge multicast in
ndo_uninit after bridge dev is shutdown, instead of br_dev_delete, so
that netif_running check in br_multicast_add_group can avoid this issue.

v1->v2:
  - fix this issue by moving br_multicast_dev_del to ndo_uninit, instead
    of calling dev_close in br_dev_delete.

(NOTE: Depends upon b6fe0440c6 ("bridge: implement missing ndo_uninit()"))

Fixes: e10177abf8 ("bridge: multicast: fix handling of temp and perm entries")
Reported-by: Jianwen Ji <jiji@redhat.com>
Signed-off-by: Xin Long <lucien.xin@gmail.com>
Reviewed-by: Stephen Hemminger <stephen@networkplumber.org>
Signed-off-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-04-25 14:02:39 -04:00
..
netfilter lib/vsprintf.c: remove %Z support 2017-02-27 18:43:47 -08:00
br_device.c bridge: move bridge multicast cleanup to ndo_uninit 2017-04-25 14:02:39 -04:00
br_fdb.c bridge: resolve a false alarm of lockdep 2017-03-16 21:29:20 -07:00
br_forward.c net: bridge: allow IPv6 when multicast flood is disabled 2017-03-01 20:55:57 -08:00
br_if.c bridge: move bridge multicast cleanup to ndo_uninit 2017-04-25 14:02:39 -04:00
br_input.c bridge: drop netfilter fake rtable unconditionally 2017-03-13 13:01:10 -07:00
br_ioctl.c bridge: move to workqueue gc 2017-02-06 22:53:13 -05:00
br_mdb.c bridge: multicast to unicast 2017-01-24 12:39:52 -05:00
br_multicast.c bridge: implement missing ndo_uninit() 2017-04-11 22:22:44 -04:00
br_netfilter_hooks.c Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf 2017-03-15 15:13:13 -07:00
br_netfilter_ipv6.c Replace <asm/uaccess.h> with <linux/uaccess.h> globally 2016-12-24 11:46:01 -08:00
br_netlink_tunnel.c bridge: vlan tunnel id info range fill size calc cleanups 2017-02-08 14:39:19 -05:00
br_netlink.c bridge: netlink: register netdevice before executing changelink 2017-04-11 22:22:44 -04:00
br_nf_core.c net: Remove protocol from struct dst_ops 2015-03-09 16:06:10 -04:00
br_private_stp.h net: bridge: add helper to set topology change 2016-12-10 21:27:23 -05:00
br_private_tunnel.h bridge: vlan dst_metadata hooks in ingress and egress paths 2017-02-03 15:21:22 -05:00
br_private.h bridge: implement missing ndo_uninit() 2017-04-11 22:22:44 -04:00
br_stp_bpdu.c netfilter: Pass net into okfn 2015-09-17 17:18:37 -07:00
br_stp_if.c bridge: move to workqueue gc 2017-02-06 22:53:13 -05:00
br_stp_timer.c bridge: move to workqueue gc 2017-02-06 22:53:13 -05:00
br_stp.c bridge: move to workqueue gc 2017-02-06 22:53:13 -05:00
br_switchdev.c bridge: switchdev: Add forward mark support for stacked devices 2016-08-26 13:13:36 -07:00
br_sysfs_br.c sched/headers: Prepare to move signal wakeup & sigpending methods from <linux/sched.h> into <linux/sched/signal.h> 2017-03-02 08:42:32 +01:00
br_sysfs_if.c sched/headers: Prepare to move signal wakeup & sigpending methods from <linux/sched.h> into <linux/sched/signal.h> 2017-03-02 08:42:32 +01:00
br_vlan_tunnel.c bridge: vlan_tunnel: explicitly reset metadata attrs to NULL on failure 2017-02-17 13:33:41 -05:00
br_vlan.c bridge: Fix error path in nbp_vlan_init 2017-03-01 14:55:28 -08:00
br.c netfilter: bridge: clarify bridge/netfilter message 2016-10-02 22:44:03 -04:00
Kconfig bridge: Add vlan filtering infrastructure 2013-02-13 19:41:46 -05:00
Makefile bridge: per vlan dst_metadata netlink support 2017-02-03 15:21:22 -05:00