diff mbox series

realtek: fix memory leak in netevent handler

Message ID 20230208215332.1336500-1-jan@3e8.eu
State Accepted
Delegated to: Sander Vanheule
Headers show
Series realtek: fix memory leak in netevent handler | expand

Commit Message

Jan Hoffmann Feb. 8, 2023, 9:53 p.m. UTC
The net_event_work struct is allocated, but only freed in a single case.
Move the allocation to the branch where it is actually needed, and free
it after the work has been done.

Fixes: 03e1d93e0779 ("realtek: add driver support for routing offload")
Signed-off-by: Jan Hoffmann <jan@3e8.eu>
---
I noticed this issue due to increasing memory usage on a HPE 1920-16G.
While I haven't done any long-term testing with this patch yet, using
kmemleak on a HPE 1920-8G no longer shows any leaks in the realtek
drivers.

 .../files-5.10/drivers/net/dsa/rtl83xx/common.c | 17 +++++++++--------
 .../files-5.15/drivers/net/dsa/rtl83xx/common.c | 17 +++++++++--------
 2 files changed, 18 insertions(+), 16 deletions(-)

Comments

Sander Vanheule Feb. 13, 2023, 11:14 a.m. UTC | #1
Hi Jan,

On Wed, 2023-02-08 at 22:53 +0100, Jan Hoffmann wrote:
> The net_event_work struct is allocated, but only freed in a single case.
> Move the allocation to the branch where it is actually needed, and free
> it after the work has been done.
> 
> Fixes: 03e1d93e0779 ("realtek: add driver support for routing offload")
> Signed-off-by: Jan Hoffmann <jan@3e8.eu>
> ---
> I noticed this issue due to increasing memory usage on a HPE 1920-16G.
> While I haven't done any long-term testing with this patch yet, using
> kmemleak on a HPE 1920-8G no longer shows any leaks in the realtek
> drivers.

Thanks for noticing and taking care of fixing it!

> 
>  .../files-5.10/drivers/net/dsa/rtl83xx/common.c | 17 +++++++++--------
>  .../files-5.15/drivers/net/dsa/rtl83xx/common.c | 17 +++++++++--------
>  2 files changed, 18 insertions(+), 16 deletions(-)
> 
> diff --git a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/common.c
> b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/common.c
> index 15e6ed092696..d2d677230010 100644
> --- a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/common.c
> +++ b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/common.c
> @@ -1286,6 +1286,8 @@ static void rtl83xx_net_event_work_do(struct work_struct *work)
>         struct rtl838x_switch_priv *priv = net_work->priv;
>  
>         rtl83xx_l3_nexthop_update(priv, net_work->gw_addr, net_work->mac);
> +
> +       kfree(net_work);
>  }
>  
>  static int rtl83xx_netevent_event(struct notifier_block *this,
> @@ -1299,13 +1301,6 @@ static int rtl83xx_netevent_event(struct notifier_block *this,
>  
>         priv = container_of(this, struct rtl838x_switch_priv, ne_nb);
>  
> -       net_work = kzalloc(sizeof(*net_work), GFP_ATOMIC);
> -       if (!net_work)
> -               return NOTIFY_BAD;
> -
> -       INIT_WORK(&net_work->work, rtl83xx_net_event_work_do);
> -       net_work->priv = priv;
> -
>         switch (event) {
>         case NETEVENT_NEIGH_UPDATE:
>                 if (n->tbl != &arp_tbl)
> @@ -1314,10 +1309,16 @@ static int rtl83xx_netevent_event(struct notifier_block *this,
>                 port = rtl83xx_port_dev_lower_find(dev, priv);
>                 if (port < 0 || !(n->nud_state & NUD_VALID)) {
>                         pr_debug("%s: Neigbour invalid, not updating\n", __func__);
> -                       kfree(net_work);
>                         return NOTIFY_DONE;
>                 }
>  
> +               net_work = kzalloc(sizeof(*net_work), GFP_ATOMIC);
> +               if (!net_work)
> +                       return NOTIFY_BAD;
> +
> +               INIT_WORK(&net_work->work, rtl83xx_net_event_work_do);
> +               net_work->priv = priv;
> +
>                 net_work->mac = ether_addr_to_u64(n->ha);
>                 net_work->gw_addr = *(__be32 *) n->primary_key;

rtl83xx_netevent_event() has a variable err which isn't ever assigned, so I think there's
a bit of dead code at the end. Otherwise I think this change is good, and err could be
removed in another patch.

Best,
Sander
diff mbox series

Patch

diff --git a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/common.c b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/common.c
index 15e6ed092696..d2d677230010 100644
--- a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/common.c
+++ b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/common.c
@@ -1286,6 +1286,8 @@  static void rtl83xx_net_event_work_do(struct work_struct *work)
 	struct rtl838x_switch_priv *priv = net_work->priv;
 
 	rtl83xx_l3_nexthop_update(priv, net_work->gw_addr, net_work->mac);
+
+	kfree(net_work);
 }
 
 static int rtl83xx_netevent_event(struct notifier_block *this,
@@ -1299,13 +1301,6 @@  static int rtl83xx_netevent_event(struct notifier_block *this,
 
 	priv = container_of(this, struct rtl838x_switch_priv, ne_nb);
 
-	net_work = kzalloc(sizeof(*net_work), GFP_ATOMIC);
-	if (!net_work)
-		return NOTIFY_BAD;
-
-	INIT_WORK(&net_work->work, rtl83xx_net_event_work_do);
-	net_work->priv = priv;
-
 	switch (event) {
 	case NETEVENT_NEIGH_UPDATE:
 		if (n->tbl != &arp_tbl)
@@ -1314,10 +1309,16 @@  static int rtl83xx_netevent_event(struct notifier_block *this,
 		port = rtl83xx_port_dev_lower_find(dev, priv);
 		if (port < 0 || !(n->nud_state & NUD_VALID)) {
 			pr_debug("%s: Neigbour invalid, not updating\n", __func__);
-			kfree(net_work);
 			return NOTIFY_DONE;
 		}
 
+		net_work = kzalloc(sizeof(*net_work), GFP_ATOMIC);
+		if (!net_work)
+			return NOTIFY_BAD;
+
+		INIT_WORK(&net_work->work, rtl83xx_net_event_work_do);
+		net_work->priv = priv;
+
 		net_work->mac = ether_addr_to_u64(n->ha);
 		net_work->gw_addr = *(__be32 *) n->primary_key;
 
diff --git a/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/common.c b/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/common.c
index 1fa92ae220e0..3216d7eb835f 100644
--- a/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/common.c
+++ b/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/common.c
@@ -1282,6 +1282,8 @@  static void rtl83xx_net_event_work_do(struct work_struct *work)
 	struct rtl838x_switch_priv *priv = net_work->priv;
 
 	rtl83xx_l3_nexthop_update(priv, net_work->gw_addr, net_work->mac);
+
+	kfree(net_work);
 }
 
 static int rtl83xx_netevent_event(struct notifier_block *this,
@@ -1295,13 +1297,6 @@  static int rtl83xx_netevent_event(struct notifier_block *this,
 
 	priv = container_of(this, struct rtl838x_switch_priv, ne_nb);
 
-	net_work = kzalloc(sizeof(*net_work), GFP_ATOMIC);
-	if (!net_work)
-		return NOTIFY_BAD;
-
-	INIT_WORK(&net_work->work, rtl83xx_net_event_work_do);
-	net_work->priv = priv;
-
 	switch (event) {
 	case NETEVENT_NEIGH_UPDATE:
 		if (n->tbl != &arp_tbl)
@@ -1310,10 +1305,16 @@  static int rtl83xx_netevent_event(struct notifier_block *this,
 		port = rtl83xx_port_dev_lower_find(dev, priv);
 		if (port < 0 || !(n->nud_state & NUD_VALID)) {
 			pr_debug("%s: Neigbour invalid, not updating\n", __func__);
-			kfree(net_work);
 			return NOTIFY_DONE;
 		}
 
+		net_work = kzalloc(sizeof(*net_work), GFP_ATOMIC);
+		if (!net_work)
+			return NOTIFY_BAD;
+
+		INIT_WORK(&net_work->work, rtl83xx_net_event_work_do);
+		net_work->priv = priv;
+
 		net_work->mac = ether_addr_to_u64(n->ha);
 		net_work->gw_addr = *(__be32 *) n->primary_key;