提交 56b08fdc 编写于 作者: A Arvid Brodin 提交者: David S. Miller

net/hsr: Fix NULL pointer dereference and refcnt bugs when deleting a HSR interface.

To repeat:

$ sudo ip link del hsr0
BUG: unable to handle kernel NULL pointer dereference at 0000000000000018
IP: [<ffffffff8187f495>] hsr_del_port+0x15/0xa0
etc...

Bug description:

As part of the hsr master device destruction, hsr_del_port() is called for each of
the hsr ports. At each such call, the master device is updated regarding features
and mtu. When the master device is freed before the slave interfaces, master will
be NULL in hsr_del_port(), which led to a NULL pointer dereference.

Additionally, dev_put() was called on the master device itself in hsr_del_port(),
causing a refcnt error.

A third bug in the same code path was that the rtnl lock was not taken before
hsr_del_port() was called as part of hsr_dev_destroy().

The reporter (Nicolas Dichtel) also said: "hsr_netdev_notify() supposes that the
port will always be available when the notification is for an hsr interface. It's
wrong. For example, netdev_wait_allrefs() may resend NETDEV_UNREGISTER.". As a
precaution against this, a check for port == NULL was added in hsr_dev_notify().
Reported-by: NNicolas Dichtel <nicolas.dichtel@6wind.com>
Fixes: 51f3c605 ("net/hsr: Move slave init to hsr_slave.c.")
Signed-off-by: NArvid Brodin <arvid.brodin@alten.se>
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
上级 187d6785
master alk-4.19.24 alk-4.19.30 alk-4.19.34 alk-4.19.36 alk-4.19.43 alk-4.19.48 alk-4.19.57 ck-4.19.67 ck-4.19.81 ck-4.19.91 github/fork/deepanshu1422/fix-typo-in-comment github/fork/haosdent/fix-typo linux-next v4.19.91 v4.19.90 v4.19.89 v4.19.88 v4.19.87 v4.19.86 v4.19.85 v4.19.84 v4.19.83 v4.19.82 v4.19.81 v4.19.80 v4.19.79 v4.19.78 v4.19.77 v4.19.76 v4.19.75 v4.19.74 v4.19.73 v4.19.72 v4.19.71 v4.19.70 v4.19.69 v4.19.68 v4.19.67 v4.19.66 v4.19.65 v4.19.64 v4.19.63 v4.19.62 v4.19.61 v4.19.60 v4.19.59 v4.19.58 v4.19.57 v4.19.56 v4.19.55 v4.19.54 v4.19.53 v4.19.52 v4.19.51 v4.19.50 v4.19.49 v4.19.48 v4.19.47 v4.19.46 v4.19.45 v4.19.44 v4.19.43 v4.19.42 v4.19.41 v4.19.40 v4.19.39 v4.19.38 v4.19.37 v4.19.36 v4.19.35 v4.19.34 v4.19.33 v4.19.32 v4.19.31 v4.19.30 v4.19.29 v4.19.28 v4.19.27 v4.19.26 v4.19.25 v4.19.24 v4.19.23 v4.19.22 v4.19.21 v4.19.20 v4.19.19 v4.19.18 v4.19.17 v4.19.16 v4.19.15 v4.19.14 v4.19.13 v4.19.12 v4.19.11 v4.19.10 v4.19.9 v4.19.8 v4.19.7 v4.19.6 v4.19.5 v4.19.4 v4.19.3 v4.19.2 v4.19.1 v4.19 v4.19-rc8 v4.19-rc7 v4.19-rc6 v4.19-rc5 v4.19-rc4 v4.19-rc3 v4.19-rc2 v4.19-rc1 ck-release-21 ck-release-20 ck-release-19.2 ck-release-19.1 ck-release-19 ck-release-18 ck-release-17.2 ck-release-17.1 ck-release-17 ck-release-16 ck-release-15.1 ck-release-15 ck-release-14 ck-release-13.2 ck-release-13 ck-release-12 ck-release-11 ck-release-10 ck-release-9 ck-release-7 alk-release-15 alk-release-14 alk-release-13.2 alk-release-13 alk-release-12 alk-release-11 alk-release-10 alk-release-9 alk-release-7
无相关合并请求
...@@ -359,8 +359,11 @@ static void hsr_dev_destroy(struct net_device *hsr_dev) ...@@ -359,8 +359,11 @@ static void hsr_dev_destroy(struct net_device *hsr_dev)
struct hsr_port *port; struct hsr_port *port;
hsr = netdev_priv(hsr_dev); hsr = netdev_priv(hsr_dev);
rtnl_lock();
hsr_for_each_port(hsr, port) hsr_for_each_port(hsr, port)
hsr_del_port(port); hsr_del_port(port);
rtnl_unlock();
del_timer_sync(&hsr->prune_timer); del_timer_sync(&hsr->prune_timer);
del_timer_sync(&hsr->announce_timer); del_timer_sync(&hsr->announce_timer);
......
...@@ -36,6 +36,10 @@ static int hsr_netdev_notify(struct notifier_block *nb, unsigned long event, ...@@ -36,6 +36,10 @@ static int hsr_netdev_notify(struct notifier_block *nb, unsigned long event,
return NOTIFY_DONE; /* Not an HSR device */ return NOTIFY_DONE; /* Not an HSR device */
hsr = netdev_priv(dev); hsr = netdev_priv(dev);
port = hsr_port_get_hsr(hsr, HSR_PT_MASTER); port = hsr_port_get_hsr(hsr, HSR_PT_MASTER);
if (port == NULL) {
/* Resend of notification concerning removed device? */
return NOTIFY_DONE;
}
} else { } else {
hsr = port->hsr; hsr = port->hsr;
} }
......
...@@ -181,8 +181,10 @@ void hsr_del_port(struct hsr_port *port) ...@@ -181,8 +181,10 @@ void hsr_del_port(struct hsr_port *port)
list_del_rcu(&port->port_list); list_del_rcu(&port->port_list);
if (port != master) { if (port != master) {
netdev_update_features(master->dev); if (master != NULL) {
dev_set_mtu(master->dev, hsr_get_max_mtu(hsr)); netdev_update_features(master->dev);
dev_set_mtu(master->dev, hsr_get_max_mtu(hsr));
}
netdev_rx_handler_unregister(port->dev); netdev_rx_handler_unregister(port->dev);
dev_set_promiscuity(port->dev, -1); dev_set_promiscuity(port->dev, -1);
} }
...@@ -192,5 +194,7 @@ void hsr_del_port(struct hsr_port *port) ...@@ -192,5 +194,7 @@ void hsr_del_port(struct hsr_port *port)
*/ */
synchronize_rcu(); synchronize_rcu();
dev_put(port->dev);
if (port != master)
dev_put(port->dev);
} }
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册