linux-stable/net/tipc
Xin Long 68a37dc77e tipc: call tipc_lxc_xmit without holding node_read_lock
commit 88956177db upstream.

When sending packets between nodes in netns, it calls tipc_lxc_xmit() for
peer node to receive the packets where tipc_sk_mcast_rcv()/tipc_sk_rcv()
might be called, and it's pretty much like in tipc_rcv().

Currently the local 'node rw lock' is held during calling tipc_lxc_xmit()
to protect the peer_net not being freed by another thread. However, when
receiving these packets, tipc_node_add_conn() might be called where the
peer 'node rw lock' is acquired. Then a dead lock warning is triggered by
lockdep detector, although it is not a real dead lock:

    WARNING: possible recursive locking detected
    --------------------------------------------
    conn_server/1086 is trying to acquire lock:
    ffff8880065cb020 (&n->lock#2){++--}-{2:2}, \
                     at: tipc_node_add_conn.cold.76+0xaa/0x211 [tipc]

    but task is already holding lock:
    ffff8880065cd020 (&n->lock#2){++--}-{2:2}, \
                     at: tipc_node_xmit+0x285/0xb30 [tipc]

    other info that might help us debug this:
     Possible unsafe locking scenario:

           CPU0
           ----
      lock(&n->lock#2);
      lock(&n->lock#2);

     *** DEADLOCK ***

     May be due to missing lock nesting notation

    4 locks held by conn_server/1086:
     #0: ffff8880036d1e40 (sk_lock-AF_TIPC){+.+.}-{0:0}, \
                          at: tipc_accept+0x9c0/0x10b0 [tipc]
     #1: ffff8880036d5f80 (sk_lock-AF_TIPC/1){+.+.}-{0:0}, \
                          at: tipc_accept+0x363/0x10b0 [tipc]
     #2: ffff8880065cd020 (&n->lock#2){++--}-{2:2}, \
                          at: tipc_node_xmit+0x285/0xb30 [tipc]
     #3: ffff888012e13370 (slock-AF_TIPC){+...}-{2:2}, \
                          at: tipc_sk_rcv+0x2da/0x1b40 [tipc]

    Call Trace:
     <TASK>
     dump_stack_lvl+0x44/0x5b
     __lock_acquire.cold.77+0x1f2/0x3d7
     lock_acquire+0x1d2/0x610
     _raw_write_lock_bh+0x38/0x80
     tipc_node_add_conn.cold.76+0xaa/0x211 [tipc]
     tipc_sk_finish_conn+0x21e/0x640 [tipc]
     tipc_sk_filter_rcv+0x147b/0x3030 [tipc]
     tipc_sk_rcv+0xbb4/0x1b40 [tipc]
     tipc_lxc_xmit+0x225/0x26b [tipc]
     tipc_node_xmit.cold.82+0x4a/0x102 [tipc]
     __tipc_sendstream+0x879/0xff0 [tipc]
     tipc_accept+0x966/0x10b0 [tipc]
     do_accept+0x37d/0x590

This patch avoids this warning by not holding the 'node rw lock' before
calling tipc_lxc_xmit(). As to protect the 'peer_net', rcu_read_lock()
should be enough, as in cleanup_net() when freeing the netns, it calls
synchronize_rcu() before the free is continued.

Also since tipc_lxc_xmit() is like the RX path in tipc_rcv(), it makes
sense to call it under rcu_read_lock(). Note that the right lock order
must be:

   rcu_read_lock();
   tipc_node_read_lock(n);
   tipc_node_read_unlock(n);
   tipc_lxc_xmit();
   rcu_read_unlock();

instead of:

   tipc_node_read_lock(n);
   rcu_read_lock();
   tipc_node_read_unlock(n);
   tipc_lxc_xmit();
   rcu_read_unlock();

and we have to call tipc_node_read_lock/unlock() twice in
tipc_node_xmit().

Fixes: f73b12812a ("tipc: improve throughput between nodes in netns")
Reported-by: Shuang Li <shuali@redhat.com>
Signed-off-by: Xin Long <lucien.xin@gmail.com>
Link: https://lore.kernel.org/r/5bdd1f8fee9db695cfff4528a48c9b9d0523fb00.1670110641.git.lucien.xin@gmail.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2023-01-18 11:42:06 +01:00
..
addr.c
addr.h
bcast.c
bcast.h
bearer.c tipc: check attribute length for bearer name 2022-06-14 18:11:56 +02:00
bearer.h
core.c tipc: improve throughput between nodes in netns 2023-01-18 11:42:04 +01:00
core.h tipc: improve throughput between nodes in netns 2023-01-18 11:42:04 +01:00
diag.c
discover.c tipc: fix use-after-free in tipc_disc_rcv() 2023-01-18 11:42:06 +01:00
discover.h
eth_media.c
group.c tipc: Fix memory leak in tipc_group_create_member() 2020-09-26 18:03:13 +02:00
group.h
ib_media.c
Kconfig
link.c tipc: Fix potential OOB in tipc_link_proto_rcv() 2022-12-14 11:30:47 +01:00
link.h
Makefile
monitor.c tipc: fix shift wrapping bug in map_get() 2022-09-15 12:04:55 +02:00
monitor.h
msg.c tipc: skb_linearize the head skb when reassembling msgs 2021-06-03 08:59:07 +02:00
msg.h tipc: Add a missing case of TIPC_DIRECT_MSG type 2023-01-18 11:42:06 +01:00
name_distr.c tipc: improve throughput between nodes in netns 2023-01-18 11:42:04 +01:00
name_distr.h
name_table.c tipc: Fix end of loop tests for list_for_each_entry() 2022-03-02 11:41:06 +01:00
name_table.h
net.c tipc: fix a deadlock when flushing scheduled work 2020-12-11 13:23:32 +01:00
net.h tipc: fix a deadlock when flushing scheduled work 2020-12-11 13:23:32 +01:00
netlink.c tipc: add missing attribute validation for MTU property 2020-03-18 07:17:45 +01:00
netlink.h
netlink_compat.c tipc: fix the msg->req tlv len check in tipc_nl_compat_name_table_dump_header 2022-11-25 17:42:05 +01:00
node.c tipc: call tipc_lxc_xmit without holding node_read_lock 2023-01-18 11:42:06 +01:00
node.h tipc: improve throughput between nodes in netns 2023-01-18 11:42:04 +01:00
socket.c tipc: Add a missing case of TIPC_DIRECT_MSG type 2023-01-18 11:42:06 +01:00
socket.h
subscr.c
subscr.h
sysctl.c
topsrv.c tipc: add an extra conn_get in tipc_conn_alloc 2022-12-08 11:22:58 +01:00
topsrv.h
trace.c
trace.h
udp_media.c tipc: wait and exit until all work queues are done 2021-06-03 08:59:07 +02:00
udp_media.h