Commit c5c1a030 authored by Ka-Cheong Poon's avatar Ka-Cheong Poon Committed by David S. Miller

net/rds: An rds_sock is added too early to the hash table

In rds_bind(), an rds_sock is added to the RDS bind hash table before
rs_transport is set.  This means that the socket can be found by the
receive code path when rs_transport is NULL.  And the receive code
path de-references rs_transport for congestion update check.  This can
cause a panic.  An rds_sock should not be added to the bind hash table
before all the needed fields are set.

Reported-by: syzbot+4b4f8163c2e246df3c4c@syzkaller.appspotmail.com
Signed-off-by: default avatarKa-Cheong Poon <ka-cheong.poon@oracle.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 3e493173
/* /*
* Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2006, 2019 Oracle and/or its affiliates. All rights reserved.
* *
* This software is available to you under a choice of one of two * This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU * licenses. You may choose to be licensed under the terms of the GNU
...@@ -239,34 +239,30 @@ int rds_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) ...@@ -239,34 +239,30 @@ int rds_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
goto out; goto out;
} }
sock_set_flag(sk, SOCK_RCU_FREE); /* The transport can be set using SO_RDS_TRANSPORT option before the
ret = rds_add_bound(rs, binding_addr, &port, scope_id); * socket is bound.
if (ret) */
goto out; if (rs->rs_transport) {
if (rs->rs_transport) { /* previously bound */
trans = rs->rs_transport; trans = rs->rs_transport;
if (trans->laddr_check(sock_net(sock->sk), if (trans->laddr_check(sock_net(sock->sk),
binding_addr, scope_id) != 0) { binding_addr, scope_id) != 0) {
ret = -ENOPROTOOPT; ret = -ENOPROTOOPT;
rds_remove_bound(rs); goto out;
} else {
ret = 0;
} }
goto out; } else {
} trans = rds_trans_get_preferred(sock_net(sock->sk),
trans = rds_trans_get_preferred(sock_net(sock->sk), binding_addr, binding_addr, scope_id);
scope_id); if (!trans) {
if (!trans) { ret = -EADDRNOTAVAIL;
ret = -EADDRNOTAVAIL; pr_info_ratelimited("RDS: %s could not find a transport for %pI6c, load rds_tcp or rds_rdma?\n",
rds_remove_bound(rs); __func__, binding_addr);
pr_info_ratelimited("RDS: %s could not find a transport for %pI6c, load rds_tcp or rds_rdma?\n", goto out;
__func__, binding_addr); }
goto out; rs->rs_transport = trans;
} }
rs->rs_transport = trans; sock_set_flag(sk, SOCK_RCU_FREE);
ret = 0; ret = rds_add_bound(rs, binding_addr, &port, scope_id);
out: out:
release_sock(sk); release_sock(sk);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment