Skip to content

Commit aced3ce

Browse files
Rao Shoaibdavem330
authored andcommitted
RDS tcp loopback connection can hang
When TCP is used as transport and a program on the system connects to RDS port 16385, connection is accepted but denied per the rules of RDS. However, RDS connections object is left in the list. Next loopback connection will select that connection object as it is at the head of list. The connection attempt will hang as the connection object is set to connect over TCP which is not allowed The issue can be reproduced easily, use rds-ping to ping a local IP address. After that use any program like ncat to connect to the same IP address and port 16385. This will hang so ctrl-c out. Now try rds-ping, it will hang. To fix the issue this patch adds checks to disallow the connection object creation and destroys the connection object. Signed-off-by: Rao Shoaib <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 29bf199 commit aced3ce

File tree

4 files changed

+27
-9
lines changed

4 files changed

+27
-9
lines changed

net/rds/connection.c

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -240,12 +240,23 @@ static struct rds_connection *__rds_conn_create(struct net *net,
240240
if (loop_trans) {
241241
rds_trans_put(loop_trans);
242242
conn->c_loopback = 1;
243-
if (is_outgoing && trans->t_prefer_loopback) {
244-
/* "outgoing" connection - and the transport
245-
* says it wants the connection handled by the
246-
* loopback transport. This is what TCP does.
247-
*/
248-
trans = &rds_loop_transport;
243+
if (trans->t_prefer_loopback) {
244+
if (likely(is_outgoing)) {
245+
/* "outgoing" connection to local address.
246+
* Protocol says it wants the connection
247+
* handled by the loopback transport.
248+
* This is what TCP does.
249+
*/
250+
trans = &rds_loop_transport;
251+
} else {
252+
/* No transport currently in use
253+
* should end up here, but if it
254+
* does, reset/destroy the connection.
255+
*/
256+
kmem_cache_free(rds_conn_slab, conn);
257+
conn = ERR_PTR(-EOPNOTSUPP);
258+
goto out;
259+
}
249260
}
250261
}
251262

net/rds/tcp.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -313,8 +313,8 @@ static void rds6_tcp_tc_info(struct socket *sock, unsigned int len,
313313
}
314314
#endif
315315

316-
static int rds_tcp_laddr_check(struct net *net, const struct in6_addr *addr,
317-
__u32 scope_id)
316+
int rds_tcp_laddr_check(struct net *net, const struct in6_addr *addr,
317+
__u32 scope_id)
318318
{
319319
struct net_device *dev = NULL;
320320
#if IS_ENABLED(CONFIG_IPV6)

net/rds/tcp.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@ u32 rds_tcp_snd_una(struct rds_tcp_connection *tc);
5959
u64 rds_tcp_map_seq(struct rds_tcp_connection *tc, u32 seq);
6060
extern struct rds_transport rds_tcp_transport;
6161
void rds_tcp_accept_work(struct sock *sk);
62-
62+
int rds_tcp_laddr_check(struct net *net, const struct in6_addr *addr,
63+
__u32 scope_id);
6364
/* tcp_connect.c */
6465
int rds_tcp_conn_path_connect(struct rds_conn_path *cp);
6566
void rds_tcp_conn_path_shutdown(struct rds_conn_path *conn);

net/rds/tcp_listen.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,12 @@ int rds_tcp_accept_one(struct socket *sock)
167167
}
168168
#endif
169169

170+
if (!rds_tcp_laddr_check(sock_net(sock->sk), peer_addr, dev_if)) {
171+
/* local address connection is only allowed via loopback */
172+
ret = -EOPNOTSUPP;
173+
goto out;
174+
}
175+
170176
conn = rds_conn_create(sock_net(sock->sk),
171177
my_addr, peer_addr,
172178
&rds_tcp_transport, 0, GFP_KERNEL, dev_if);

0 commit comments

Comments
 (0)