Skip to content

Commit 021fd0f

Browse files
ffmanceraPaolo Abeni
authored andcommitted
net/rds: fix recursive lock in rds_tcp_conn_slots_available
syzbot reported a recursive lock warning in rds_tcp_get_peer_sport() as it calls inet6_getname() which acquires the socket lock that was already held by __release_sock(). kworker/u8:6/2985 is trying to acquire lock: ffff88807a07aa20 (k-sk_lock-AF_INET6){+.+.}-{0:0}, at: lock_sock include/net/sock.h:1709 [inline] ffff88807a07aa20 (k-sk_lock-AF_INET6){+.+.}-{0:0}, at: inet6_getname+0x15d/0x650 net/ipv6/af_inet6.c:533 but task is already holding lock: ffff88807a07aa20 (k-sk_lock-AF_INET6){+.+.}-{0:0}, at: lock_sock include/net/sock.h:1709 [inline] ffff88807a07aa20 (k-sk_lock-AF_INET6){+.+.}-{0:0}, at: tcp_sock_set_cork+0x2c/0x2e0 net/ipv4/tcp.c:3694 lock_sock_nested+0x48/0x100 net/core/sock.c:3780 lock_sock include/net/sock.h:1709 [inline] inet6_getname+0x15d/0x650 net/ipv6/af_inet6.c:533 rds_tcp_get_peer_sport net/rds/tcp_listen.c:70 [inline] rds_tcp_conn_slots_available+0x288/0x470 net/rds/tcp_listen.c:149 rds_recv_hs_exthdrs+0x60f/0x7c0 net/rds/recv.c:265 rds_recv_incoming+0x9f6/0x12d0 net/rds/recv.c:389 rds_tcp_data_recv+0x7f1/0xa40 net/rds/tcp_recv.c:243 __tcp_read_sock+0x196/0x970 net/ipv4/tcp.c:1702 rds_tcp_read_sock net/rds/tcp_recv.c:277 [inline] rds_tcp_data_ready+0x369/0x950 net/rds/tcp_recv.c:331 tcp_rcv_established+0x19e9/0x2670 net/ipv4/tcp_input.c:6675 tcp_v6_do_rcv+0x8eb/0x1ba0 net/ipv6/tcp_ipv6.c:1609 sk_backlog_rcv include/net/sock.h:1185 [inline] __release_sock+0x1b8/0x3a0 net/core/sock.c:3213 Reading from the socket struct directly is safe from possible paths. For rds_tcp_accept_one(), the socket has just been accepted and is not yet exposed to concurrent access. For rds_tcp_conn_slots_available(), direct access avoids the recursive deadlock seen during backlog processing where the socket lock is already held from the __release_sock(). However, rds_tcp_conn_slots_available() is also called from the normal softirq path via tcp_data_ready() where the lock is not held. This is also safe because inet_dport is a stable 16 bits field. A READ_ONCE() annotation as the value might be accessed lockless in a concurrent access context. Note that it is also safe to call rds_tcp_conn_slots_available() from rds_conn_shutdown() because the fan-out is disabled. Fixes: 9d27a0f ("net/rds: Trigger rds_send_ping() more than once") Reported-by: syzbot+5efae91f60932839f0a5@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=5efae91f60932839f0a5 Signed-off-by: Fernando Fernandez Mancera <fmancera@suse.de> Reviewed-by: Allison Henderson <achender@kernel.org> Link: https://patch.msgid.link/20260219075738.4403-1-fmancera@suse.de Signed-off-by: Paolo Abeni <pabeni@redhat.com>
1 parent 3aa6776 commit 021fd0f

2 files changed

Lines changed: 8 additions & 23 deletions

File tree

net/rds/connection.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,9 @@ void rds_conn_shutdown(struct rds_conn_path *cp)
455455
rcu_read_unlock();
456456
}
457457

458+
/* we do not hold the socket lock here but it is safe because
459+
* fan-out is disabled when calling conn_slots_available()
460+
*/
458461
if (conn->c_trans->conn_slots_available)
459462
conn->c_trans->conn_slots_available(conn, false);
460463
}

net/rds/tcp_listen.c

Lines changed: 5 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -59,30 +59,12 @@ void rds_tcp_keepalive(struct socket *sock)
5959
static int
6060
rds_tcp_get_peer_sport(struct socket *sock)
6161
{
62-
union {
63-
struct sockaddr_storage storage;
64-
struct sockaddr addr;
65-
struct sockaddr_in sin;
66-
struct sockaddr_in6 sin6;
67-
} saddr;
68-
int sport;
69-
70-
if (kernel_getpeername(sock, &saddr.addr) >= 0) {
71-
switch (saddr.addr.sa_family) {
72-
case AF_INET:
73-
sport = ntohs(saddr.sin.sin_port);
74-
break;
75-
case AF_INET6:
76-
sport = ntohs(saddr.sin6.sin6_port);
77-
break;
78-
default:
79-
sport = -1;
80-
}
81-
} else {
82-
sport = -1;
83-
}
62+
struct sock *sk = sock->sk;
63+
64+
if (!sk)
65+
return -1;
8466

85-
return sport;
67+
return ntohs(READ_ONCE(inet_sk(sk)->inet_dport));
8668
}
8769

8870
/* rds_tcp_accept_one_path(): if accepting on cp_index > 0, make sure the

0 commit comments

Comments
 (0)