| From foo@baz Fri Nov 7 11:36:50 PST 2014 |
| From: Eric Dumazet <edumazet@google.com> |
| Date: Wed, 22 Oct 2014 19:43:46 -0700 |
| Subject: macvlan: fix a race on port dismantle and possible skb leaks |
| |
| From: Eric Dumazet <edumazet@google.com> |
| |
| [ Upstream commit fe0ca7328d03d36aafecebb3af650e1bb2841c20 ] |
| |
| We need to cancel the work queue after rcu grace period, |
| otherwise it can be rescheduled by incoming packets. |
| |
| We need to purge queue if some skbs are still in it. |
| |
| We can use __skb_queue_head_init() variant in |
| macvlan_process_broadcast() |
| |
| Signed-off-by: Eric Dumazet <edumazet@google.com> |
| Fixes: 412ca1550cbec ("macvlan: Move broadcasts into a work queue") |
| Cc: Herbert Xu <herbert@gondor.apana.org.au> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/net/macvlan.c | 10 ++++++++-- |
| 1 file changed, 8 insertions(+), 2 deletions(-) |
| |
| --- a/drivers/net/macvlan.c |
| +++ b/drivers/net/macvlan.c |
| @@ -201,7 +201,7 @@ static void macvlan_process_broadcast(st |
| struct sk_buff *skb; |
| struct sk_buff_head list; |
| |
| - skb_queue_head_init(&list); |
| + __skb_queue_head_init(&list); |
| |
| spin_lock_bh(&port->bc_queue.lock); |
| skb_queue_splice_tail_init(&port->bc_queue, &list); |
| @@ -941,9 +941,15 @@ static void macvlan_port_destroy(struct |
| { |
| struct macvlan_port *port = macvlan_port_get_rtnl(dev); |
| |
| - cancel_work_sync(&port->bc_work); |
| dev->priv_flags &= ~IFF_MACVLAN_PORT; |
| netdev_rx_handler_unregister(dev); |
| + |
| + /* After this point, no packet can schedule bc_work anymore, |
| + * but we need to cancel it and purge left skbs if any. |
| + */ |
| + cancel_work_sync(&port->bc_work); |
| + __skb_queue_purge(&port->bc_queue); |
| + |
| kfree_rcu(port, rcu); |
| } |
| |