| From foo@baz Sat Jul 26 10:08:04 PDT 2014 |
| From: Loic Prylli <loicp@google.com> |
| Date: Tue, 1 Jul 2014 21:39:43 -0700 |
| Subject: net: Fix NETDEV_CHANGE notifier usage causing spurious arp flush |
| |
| From: Loic Prylli <loicp@google.com> |
| |
| [ Upstream commit 54951194656e4853e441266fd095f880bc0398f3 ] |
| |
| A bug was introduced in NETDEV_CHANGE notifier sequence causing the |
| arp table to be sometimes spuriously cleared (including manual arp |
| entries marked permanent), upon network link carrier changes. |
| |
| The changed argument for the notifier was applied only to a single |
| caller of NETDEV_CHANGE, missing among others netdev_state_change(). |
| So upon net_carrier events induced by the network, which are |
| triggering a call to netdev_state_change(), arp_netdev_event() would |
| decide whether to clear or not arp cache based on random/junk stack |
| values (a kind of read buffer overflow). |
| |
| Fixes: be9efd365328 ("net: pass changed flags along with NETDEV_CHANGE event") |
| Fixes: 6c8b4e3ff81b ("arp: flush arp cache on IFF_NOARP change") |
| Signed-off-by: Loic Prylli <loicp@google.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| net/core/dev.c | 9 ++++++++- |
| 1 file changed, 8 insertions(+), 1 deletion(-) |
| |
| --- a/net/core/dev.c |
| +++ b/net/core/dev.c |
| @@ -148,6 +148,9 @@ struct list_head ptype_all __read_mostly |
| static struct list_head offload_base __read_mostly; |
| |
| static int netif_rx_internal(struct sk_buff *skb); |
| +static int call_netdevice_notifiers_info(unsigned long val, |
| + struct net_device *dev, |
| + struct netdev_notifier_info *info); |
| |
| /* |
| * The @dev_base_head list is protected by @dev_base_lock and the rtnl |
| @@ -1207,7 +1210,11 @@ EXPORT_SYMBOL(netdev_features_change); |
| void netdev_state_change(struct net_device *dev) |
| { |
| if (dev->flags & IFF_UP) { |
| - call_netdevice_notifiers(NETDEV_CHANGE, dev); |
| + struct netdev_notifier_change_info change_info; |
| + |
| + change_info.flags_changed = 0; |
| + call_netdevice_notifiers_info(NETDEV_CHANGE, dev, |
| + &change_info.info); |
| rtmsg_ifinfo(RTM_NEWLINK, dev, 0, GFP_KERNEL); |
| } |
| } |