diff options
author | Cong Wang <xiyou.wangcong@gmail.com> | 2019-07-03 20:21:12 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2019-07-05 18:22:27 -0400 |
commit | 619afef01f74f3572b5e9a266c1230dc83761eec (patch) | |
tree | 655b4815bf5014dda535cdc8b4c4527ebf48909a /net/hsr | |
parent | 114b5b355ec0b6e83a6628a5ab5d03e50fd40a31 (diff) |
hsr: fix a memory leak in hsr_del_port()
hsr_del_port() should release all the resources allocated
in hsr_add_port().
As a consequence of this change, hsr_for_each_port() is no
longer safe to work with hsr_del_port(), switch to
list_for_each_entry_safe() as we always hold RTNL lock.
Cc: Arvid Brodin <arvid.brodin@alten.se>
Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/hsr')
-rw-r--r-- | net/hsr/hsr_device.c | 6 | ||||
-rw-r--r-- | net/hsr/hsr_slave.c | 1 |
2 files changed, 5 insertions, 2 deletions
diff --git a/net/hsr/hsr_device.c b/net/hsr/hsr_device.c index 15c72065df79..f48b6a275cf0 100644 --- a/net/hsr/hsr_device.c +++ b/net/hsr/hsr_device.c | |||
@@ -351,13 +351,14 @@ static void hsr_dev_destroy(struct net_device *hsr_dev) | |||
351 | { | 351 | { |
352 | struct hsr_priv *hsr; | 352 | struct hsr_priv *hsr; |
353 | struct hsr_port *port; | 353 | struct hsr_port *port; |
354 | struct hsr_port *tmp; | ||
354 | 355 | ||
355 | hsr = netdev_priv(hsr_dev); | 356 | hsr = netdev_priv(hsr_dev); |
356 | 357 | ||
357 | hsr_debugfs_term(hsr); | 358 | hsr_debugfs_term(hsr); |
358 | 359 | ||
359 | rtnl_lock(); | 360 | rtnl_lock(); |
360 | hsr_for_each_port(hsr, port) | 361 | list_for_each_entry_safe(port, tmp, &hsr->ports, port_list) |
361 | hsr_del_port(port); | 362 | hsr_del_port(port); |
362 | rtnl_unlock(); | 363 | rtnl_unlock(); |
363 | 364 | ||
@@ -428,6 +429,7 @@ int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2], | |||
428 | { | 429 | { |
429 | struct hsr_priv *hsr; | 430 | struct hsr_priv *hsr; |
430 | struct hsr_port *port; | 431 | struct hsr_port *port; |
432 | struct hsr_port *tmp; | ||
431 | int res; | 433 | int res; |
432 | 434 | ||
433 | hsr = netdev_priv(hsr_dev); | 435 | hsr = netdev_priv(hsr_dev); |
@@ -492,7 +494,7 @@ int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2], | |||
492 | return 0; | 494 | return 0; |
493 | 495 | ||
494 | fail: | 496 | fail: |
495 | hsr_for_each_port(hsr, port) | 497 | list_for_each_entry_safe(port, tmp, &hsr->ports, port_list) |
496 | hsr_del_port(port); | 498 | hsr_del_port(port); |
497 | err_add_port: | 499 | err_add_port: |
498 | hsr_del_node(&hsr->self_node_db); | 500 | hsr_del_node(&hsr->self_node_db); |
diff --git a/net/hsr/hsr_slave.c b/net/hsr/hsr_slave.c index 88b6705ded83..ee561297d8a7 100644 --- a/net/hsr/hsr_slave.c +++ b/net/hsr/hsr_slave.c | |||
@@ -193,4 +193,5 @@ void hsr_del_port(struct hsr_port *port) | |||
193 | 193 | ||
194 | if (port != master) | 194 | if (port != master) |
195 | dev_put(port->dev); | 195 | dev_put(port->dev); |
196 | kfree(port); | ||
196 | } | 197 | } |