diff mbox series

[mptcp-next] mptcp: free entry when release_work allocation fails

Message ID cba51616ec99f106c50dd7b0560450812adcd581.1628739395.git.geliangtang@xiaomi.com (mailing list archive)
State Superseded, archived
Delegated to: Paolo Abeni
Headers show
Series [mptcp-next] mptcp: free entry when release_work allocation fails | expand

Commit Message

Geliang Tang Aug. 12, 2021, 3:37 a.m. UTC
From: Geliang Tang <geliangtang@xiaomi.com>

This patch fixed this syzkaller error:

 BUG: memory leak
 unreferenced object 0xffff88810680ea00 (size 64):
   comm "syz-executor.6", pid 6191, jiffies 4295756280 (age 24.138s)
   hex dump (first 32 bytes):
     58 75 7d 3c 80 88 ff ff 22 01 00 00 00 00 ad de  Xu}<....".......
     01 00 02 00 00 00 00 00 ac 1e 00 07 00 00 00 00  ................
   backtrace:
     [<0000000072a9f72a>] kmalloc include/linux/slab.h:591 [inline]
     [<0000000072a9f72a>] mptcp_nl_cmd_add_addr+0x287/0x9f0 net/mptcp/pm_netlink.c:1170
     [<00000000f6e931bf>] genl_family_rcv_msg_doit.isra.0+0x225/0x340 net/netlink/genetlink.c:731
     [<00000000f1504a2c>] genl_family_rcv_msg net/netlink/genetlink.c:775 [inline]
     [<00000000f1504a2c>] genl_rcv_msg+0x341/0x5b0 net/netlink/genetlink.c:792
     [<0000000097e76f6a>] netlink_rcv_skb+0x148/0x430 net/netlink/af_netlink.c:2504
     [<00000000ceefa2b8>] genl_rcv+0x24/0x40 net/netlink/genetlink.c:803
     [<000000008ff91aec>] netlink_unicast_kernel net/netlink/af_netlink.c:1314 [inline]
     [<000000008ff91aec>] netlink_unicast+0x537/0x750 net/netlink/af_netlink.c:1340
     [<0000000041682c35>] netlink_sendmsg+0x846/0xd80 net/netlink/af_netlink.c:1929
     [<00000000df3aa8e7>] sock_sendmsg_nosec net/socket.c:704 [inline]
     [<00000000df3aa8e7>] sock_sendmsg+0x14e/0x190 net/socket.c:724
     [<000000002154c54c>] ____sys_sendmsg+0x709/0x870 net/socket.c:2403
     [<000000001aab01d7>] ___sys_sendmsg+0xff/0x170 net/socket.c:2457
     [<00000000fa3b1446>] __sys_sendmsg+0xe5/0x1b0 net/socket.c:2486
     [<00000000db2ee9c7>] do_syscall_x64 arch/x86/entry/common.c:50 [inline]
     [<00000000db2ee9c7>] do_syscall_64+0x38/0x90 arch/x86/entry/common.c:80
     [<000000005873517d>] entry_SYSCALL_64_after_hwframe+0x44/0xae

 BUG: leak checking failed

Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/223
Fixes: 1729cf186d8a5 (mptcp: create the listening socket for new port)
Signed-off-by: Geliang Tang <geliangtang@xiaomi.com>
---
 net/mptcp/pm_netlink.c | 2 ++
 1 file changed, 2 insertions(+)

Comments

Paolo Abeni Aug. 12, 2021, 10:09 a.m. UTC | #1
On Thu, 2021-08-12 at 11:37 +0800, Geliang Tang wrote:
> From: Geliang Tang <geliangtang@xiaomi.com>
> 
> This patch fixed this syzkaller error:

Good catch!

>  BUG: memory leak
>  unreferenced object 0xffff88810680ea00 (size 64):
>    comm "syz-executor.6", pid 6191, jiffies 4295756280 (age 24.138s)
>    hex dump (first 32 bytes):
>      58 75 7d 3c 80 88 ff ff 22 01 00 00 00 00 ad de  Xu}<....".......
>      01 00 02 00 00 00 00 00 ac 1e 00 07 00 00 00 00  ................
>    backtrace:
>      [<0000000072a9f72a>] kmalloc include/linux/slab.h:591 [inline]
>      [<0000000072a9f72a>] mptcp_nl_cmd_add_addr+0x287/0x9f0 net/mptcp/pm_netlink.c:1170
>      [<00000000f6e931bf>] genl_family_rcv_msg_doit.isra.0+0x225/0x340 net/netlink/genetlink.c:731
>      [<00000000f1504a2c>] genl_family_rcv_msg net/netlink/genetlink.c:775 [inline]
>      [<00000000f1504a2c>] genl_rcv_msg+0x341/0x5b0 net/netlink/genetlink.c:792
>      [<0000000097e76f6a>] netlink_rcv_skb+0x148/0x430 net/netlink/af_netlink.c:2504
>      [<00000000ceefa2b8>] genl_rcv+0x24/0x40 net/netlink/genetlink.c:803
>      [<000000008ff91aec>] netlink_unicast_kernel net/netlink/af_netlink.c:1314 [inline]
>      [<000000008ff91aec>] netlink_unicast+0x537/0x750 net/netlink/af_netlink.c:1340
>      [<0000000041682c35>] netlink_sendmsg+0x846/0xd80 net/netlink/af_netlink.c:1929
>      [<00000000df3aa8e7>] sock_sendmsg_nosec net/socket.c:704 [inline]
>      [<00000000df3aa8e7>] sock_sendmsg+0x14e/0x190 net/socket.c:724
>      [<000000002154c54c>] ____sys_sendmsg+0x709/0x870 net/socket.c:2403
>      [<000000001aab01d7>] ___sys_sendmsg+0xff/0x170 net/socket.c:2457
>      [<00000000fa3b1446>] __sys_sendmsg+0xe5/0x1b0 net/socket.c:2486
>      [<00000000db2ee9c7>] do_syscall_x64 arch/x86/entry/common.c:50 [inline]
>      [<00000000db2ee9c7>] do_syscall_64+0x38/0x90 arch/x86/entry/common.c:80
>      [<000000005873517d>] entry_SYSCALL_64_after_hwframe+0x44/0xae
> 
>  BUG: leak checking failed
> 
> Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/223
> Fixes: 1729cf186d8a5 (mptcp: create the listening socket for new port)
> Signed-off-by: Geliang Tang <geliangtang@xiaomi.com>
> ---
>  net/mptcp/pm_netlink.c | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/net/mptcp/pm_netlink.c b/net/mptcp/pm_netlink.c
> index 371607dc6ff7..184a75e1c8ec 100644
> --- a/net/mptcp/pm_netlink.c
> +++ b/net/mptcp/pm_netlink.c
> @@ -1324,6 +1324,8 @@ static void mptcp_pm_free_addr_entry(struct mptcp_pm_addr_entry *entry)
>  		INIT_RCU_WORK(&w->rwork, mptcp_pm_release_addr_entry);
>  		w->entry = entry;
>  		queue_rcu_work(system_wq, &w->rwork);
> +	} else {
> +		kfree(entry);
>  	}
>  }

We can't invoke kfree on pointer a pointer accesed with the RCU schema.

We also should not require an allocation to free a pointer. 

I can't recall why we did not include an rcu list entry
into mptcp_pm_addr_entry, likely to avoid making such pointer too big.

I think we can both fix the leak and avoid the extra allocation with
something alike the following. 

Only build-tested, could you please give it a spin? I can't reproduce
the leak locally ?!?
---
 net/mptcp/pm_netlink.c | 39 ++++++++++++---------------------------
 1 file changed, 12 insertions(+), 27 deletions(-)

diff --git a/net/mptcp/pm_netlink.c b/net/mptcp/pm_netlink.c
index 371607dc6ff7..116009376ed7 100644
--- a/net/mptcp/pm_netlink.c
+++ b/net/mptcp/pm_netlink.c
@@ -1300,31 +1300,12 @@ struct addr_entry_release_work {
 	struct mptcp_pm_addr_entry *entry;
 };
 
-static void mptcp_pm_release_addr_entry(struct work_struct *work)
+/* caller must ensure the RCU grace period is already elapsed */
+static void __mptcp_pm_release_addr_entry(struct mptcp_pm_addr_entry
*entry)
 {
-	struct addr_entry_release_work *w;
-	struct mptcp_pm_addr_entry *entry;
-
-	w = container_of(to_rcu_work(work), struct
addr_entry_release_work, rwork);
-	entry = w->entry;
-	if (entry) {
-		if (entry->lsk)
-			sock_release(entry->lsk);
-		kfree(entry);
-	}
-	kfree(w);
-}
-
-static void mptcp_pm_free_addr_entry(struct mptcp_pm_addr_entry
*entry)
-{
-	struct addr_entry_release_work *w;
-
-	w = kmalloc(sizeof(*w), GFP_ATOMIC);
-	if (w) {
-		INIT_RCU_WORK(&w->rwork, mptcp_pm_release_addr_entry);
-		w->entry = entry;
-		queue_rcu_work(system_wq, &w->rwork);
-	}
+	if (entry->lsk)
+		sock_release(entry->lsk);
+	kfree(entry);
 }
 
 static int mptcp_nl_remove_id_zero_address(struct net *net,
@@ -1404,7 +1385,8 @@ static int mptcp_nl_cmd_del_addr(struct sk_buff
*skb, struct genl_info *info)
 	spin_unlock_bh(&pernet->lock);
 
 	mptcp_nl_remove_subflow_and_signal_addr(sock_net(skb->sk),
&entry->addr);
-	mptcp_pm_free_addr_entry(entry);
+	synchronize_rcu();
+	__mptcp_pm_release_addr_entry(entry);
 
 	return ret;
 }
@@ -1457,6 +1439,7 @@ static void mptcp_nl_remove_addrs_list(struct net
*net,
 	}
 }
 
+/* caller must ensure the RCU grace period is already elapsed */
 static void __flush_addrs(struct list_head *list)
 {
 	while (!list_empty(list)) {
@@ -1465,7 +1448,7 @@ static void __flush_addrs(struct list_head *list)
 		cur = list_entry(list->next,
 				 struct mptcp_pm_addr_entry, list);
 		list_del_rcu(&cur->list);
-		mptcp_pm_free_addr_entry(cur);
+		__mptcp_pm_release_addr_entry(cur);
 	}
 }
 
@@ -1489,6 +1472,7 @@ static int mptcp_nl_cmd_flush_addrs(struct
sk_buff *skb, struct genl_info *info)
 	bitmap_zero(pernet->id_bitmap, MAX_ADDR_ID + 1);
 	spin_unlock_bh(&pernet->lock);
 	mptcp_nl_remove_addrs_list(sock_net(skb->sk), &free_list);
+	synchronize_rcu();
 	__flush_addrs(&free_list);
 	return 0;
 }
@@ -2100,7 +2084,8 @@ static void __net_exit pm_nl_exit_net(struct
list_head *net_list)
 		struct pm_nl_pernet *pernet = net_generic(net,
pm_nl_pernet_id);
 
 		/* net is removed from namespace list, can't race with
-		 * other modifiers
+		 * other modifiers, also netns core already waited for
a
+		 * RCU grace period.
 		 */
 		__flush_addrs(&pernet->local_addr_list);
 	}
Geliang Tang Aug. 12, 2021, 12:24 p.m. UTC | #2
Hi Paolo,

Paolo Abeni <pabeni@redhat.com> 于2021年8月12日周四 下午6:09写道:
>
> On Thu, 2021-08-12 at 11:37 +0800, Geliang Tang wrote:
> > From: Geliang Tang <geliangtang@xiaomi.com>
> >
> > This patch fixed this syzkaller error:
>
> Good catch!
>
> >  BUG: memory leak
> >  unreferenced object 0xffff88810680ea00 (size 64):
> >    comm "syz-executor.6", pid 6191, jiffies 4295756280 (age 24.138s)
> >    hex dump (first 32 bytes):
> >      58 75 7d 3c 80 88 ff ff 22 01 00 00 00 00 ad de  Xu}<....".......
> >      01 00 02 00 00 00 00 00 ac 1e 00 07 00 00 00 00  ................
> >    backtrace:
> >      [<0000000072a9f72a>] kmalloc include/linux/slab.h:591 [inline]
> >      [<0000000072a9f72a>] mptcp_nl_cmd_add_addr+0x287/0x9f0 net/mptcp/pm_netlink.c:1170
> >      [<00000000f6e931bf>] genl_family_rcv_msg_doit.isra.0+0x225/0x340 net/netlink/genetlink.c:731
> >      [<00000000f1504a2c>] genl_family_rcv_msg net/netlink/genetlink.c:775 [inline]
> >      [<00000000f1504a2c>] genl_rcv_msg+0x341/0x5b0 net/netlink/genetlink.c:792
> >      [<0000000097e76f6a>] netlink_rcv_skb+0x148/0x430 net/netlink/af_netlink.c:2504
> >      [<00000000ceefa2b8>] genl_rcv+0x24/0x40 net/netlink/genetlink.c:803
> >      [<000000008ff91aec>] netlink_unicast_kernel net/netlink/af_netlink.c:1314 [inline]
> >      [<000000008ff91aec>] netlink_unicast+0x537/0x750 net/netlink/af_netlink.c:1340
> >      [<0000000041682c35>] netlink_sendmsg+0x846/0xd80 net/netlink/af_netlink.c:1929
> >      [<00000000df3aa8e7>] sock_sendmsg_nosec net/socket.c:704 [inline]
> >      [<00000000df3aa8e7>] sock_sendmsg+0x14e/0x190 net/socket.c:724
> >      [<000000002154c54c>] ____sys_sendmsg+0x709/0x870 net/socket.c:2403
> >      [<000000001aab01d7>] ___sys_sendmsg+0xff/0x170 net/socket.c:2457
> >      [<00000000fa3b1446>] __sys_sendmsg+0xe5/0x1b0 net/socket.c:2486
> >      [<00000000db2ee9c7>] do_syscall_x64 arch/x86/entry/common.c:50 [inline]
> >      [<00000000db2ee9c7>] do_syscall_64+0x38/0x90 arch/x86/entry/common.c:80
> >      [<000000005873517d>] entry_SYSCALL_64_after_hwframe+0x44/0xae
> >
> >  BUG: leak checking failed
> >
> > Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/223
> > Fixes: 1729cf186d8a5 (mptcp: create the listening socket for new port)
> > Signed-off-by: Geliang Tang <geliangtang@xiaomi.com>
> > ---
> >  net/mptcp/pm_netlink.c | 2 ++
> >  1 file changed, 2 insertions(+)
> >
> > diff --git a/net/mptcp/pm_netlink.c b/net/mptcp/pm_netlink.c
> > index 371607dc6ff7..184a75e1c8ec 100644
> > --- a/net/mptcp/pm_netlink.c
> > +++ b/net/mptcp/pm_netlink.c
> > @@ -1324,6 +1324,8 @@ static void mptcp_pm_free_addr_entry(struct mptcp_pm_addr_entry *entry)
> >               INIT_RCU_WORK(&w->rwork, mptcp_pm_release_addr_entry);
> >               w->entry = entry;
> >               queue_rcu_work(system_wq, &w->rwork);
> > +     } else {
> > +             kfree(entry);
> >       }
> >  }
>
> We can't invoke kfree on pointer a pointer accesed with the RCU schema.
>
> We also should not require an allocation to free a pointer.
>
> I can't recall why we did not include an rcu list entry
> into mptcp_pm_addr_entry, likely to avoid making such pointer too big.
>
> I think we can both fix the leak and avoid the extra allocation with
> something alike the following.
>
> Only build-tested, could you please give it a spin? I can't reproduce
> the leak locally ?!?

I tested your patch, no memory leak anymore. I think it works. But I got
some oom errors in the log. I'm not sure whether it's a normal output. The
full log is in the attachment.

Thanks,
-Geliang

> ---
>  net/mptcp/pm_netlink.c | 39 ++++++++++++---------------------------
>  1 file changed, 12 insertions(+), 27 deletions(-)
>
> diff --git a/net/mptcp/pm_netlink.c b/net/mptcp/pm_netlink.c
> index 371607dc6ff7..116009376ed7 100644
> --- a/net/mptcp/pm_netlink.c
> +++ b/net/mptcp/pm_netlink.c
> @@ -1300,31 +1300,12 @@ struct addr_entry_release_work {
>         struct mptcp_pm_addr_entry *entry;
>  };
>
> -static void mptcp_pm_release_addr_entry(struct work_struct *work)
> +/* caller must ensure the RCU grace period is already elapsed */
> +static void __mptcp_pm_release_addr_entry(struct mptcp_pm_addr_entry
> *entry)
>  {
> -       struct addr_entry_release_work *w;
> -       struct mptcp_pm_addr_entry *entry;
> -
> -       w = container_of(to_rcu_work(work), struct
> addr_entry_release_work, rwork);
> -       entry = w->entry;
> -       if (entry) {
> -               if (entry->lsk)
> -                       sock_release(entry->lsk);
> -               kfree(entry);
> -       }
> -       kfree(w);
> -}
> -
> -static void mptcp_pm_free_addr_entry(struct mptcp_pm_addr_entry
> *entry)
> -{
> -       struct addr_entry_release_work *w;
> -
> -       w = kmalloc(sizeof(*w), GFP_ATOMIC);
> -       if (w) {
> -               INIT_RCU_WORK(&w->rwork, mptcp_pm_release_addr_entry);
> -               w->entry = entry;
> -               queue_rcu_work(system_wq, &w->rwork);
> -       }
> +       if (entry->lsk)
> +               sock_release(entry->lsk);
> +       kfree(entry);
>  }
>
>  static int mptcp_nl_remove_id_zero_address(struct net *net,
> @@ -1404,7 +1385,8 @@ static int mptcp_nl_cmd_del_addr(struct sk_buff
> *skb, struct genl_info *info)
>         spin_unlock_bh(&pernet->lock);
>
>         mptcp_nl_remove_subflow_and_signal_addr(sock_net(skb->sk),
> &entry->addr);
> -       mptcp_pm_free_addr_entry(entry);
> +       synchronize_rcu();
> +       __mptcp_pm_release_addr_entry(entry);
>
>         return ret;
>  }
> @@ -1457,6 +1439,7 @@ static void mptcp_nl_remove_addrs_list(struct net
> *net,
>         }
>  }
>
> +/* caller must ensure the RCU grace period is already elapsed */
>  static void __flush_addrs(struct list_head *list)
>  {
>         while (!list_empty(list)) {
> @@ -1465,7 +1448,7 @@ static void __flush_addrs(struct list_head *list)
>                 cur = list_entry(list->next,
>                                  struct mptcp_pm_addr_entry, list);
>                 list_del_rcu(&cur->list);
> -               mptcp_pm_free_addr_entry(cur);
> +               __mptcp_pm_release_addr_entry(cur);
>         }
>  }
>
> @@ -1489,6 +1472,7 @@ static int mptcp_nl_cmd_flush_addrs(struct
> sk_buff *skb, struct genl_info *info)
>         bitmap_zero(pernet->id_bitmap, MAX_ADDR_ID + 1);
>         spin_unlock_bh(&pernet->lock);
>         mptcp_nl_remove_addrs_list(sock_net(skb->sk), &free_list);
> +       synchronize_rcu();
>         __flush_addrs(&free_list);
>         return 0;
>  }
> @@ -2100,7 +2084,8 @@ static void __net_exit pm_nl_exit_net(struct
> list_head *net_list)
>                 struct pm_nl_pernet *pernet = net_generic(net,
> pm_nl_pernet_id);
>
>                 /* net is removed from namespace list, can't race with
> -                * other modifiers
> +                * other modifiers, also netns core already waited for
> a
> +                * RCU grace period.
>                  */
>                 __flush_addrs(&pernet->local_addr_list);
>         }
>
>
diff mbox series

Patch

diff --git a/net/mptcp/pm_netlink.c b/net/mptcp/pm_netlink.c
index 371607dc6ff7..184a75e1c8ec 100644
--- a/net/mptcp/pm_netlink.c
+++ b/net/mptcp/pm_netlink.c
@@ -1324,6 +1324,8 @@  static void mptcp_pm_free_addr_entry(struct mptcp_pm_addr_entry *entry)
 		INIT_RCU_WORK(&w->rwork, mptcp_pm_release_addr_entry);
 		w->entry = entry;
 		queue_rcu_work(system_wq, &w->rwork);
+	} else {
+		kfree(entry);
 	}
 }