summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCong Wang <xiyou.wangcong@gmail.com>2018-09-11 04:27:26 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2018-09-26 09:36:30 +0300
commit53a3bad7e9e713b2734637bf21c0473c60372355 (patch)
treef8ea97055b51f2defb54c2f8eb89a8a2d98845b6
parentbfb8799ab575c6076ca2ee1738453643d5ef6bfa (diff)
downloadlinux-53a3bad7e9e713b2734637bf21c0473c60372355.tar.xz
rds: fix two RCU related problems
[ Upstream commit cc4dfb7f70a344f24c1c71e298deea0771dadcb2 ] When a rds sock is bound, it is inserted into the bind_hash_table which is protected by RCU. But when releasing rds sock, after it is removed from this hash table, it is freed immediately without respecting RCU grace period. This could cause some use-after-free as reported by syzbot. Mark the rds sock with SOCK_RCU_FREE before inserting it into the bind_hash_table, so that it would be always freed after a RCU grace period. The other problem is in rds_find_bound(), the rds sock could be freed in between rhashtable_lookup_fast() and rds_sock_addref(), so we need to extend RCU read lock protection in rds_find_bound() to close this race condition. Reported-and-tested-by: syzbot+8967084bcac563795dc6@syzkaller.appspotmail.com Reported-by: syzbot+93a5839deb355537440f@syzkaller.appspotmail.com Cc: Sowmini Varadhan <sowmini.varadhan@oracle.com> Cc: Santosh Shilimkar <santosh.shilimkar@oracle.com> Cc: rds-devel@oss.oracle.com Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com> Acked-by: Santosh Shilimkar <santosh.shilimkar@oarcle.com> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--net/rds/bind.c5
1 files changed, 4 insertions, 1 deletions
diff --git a/net/rds/bind.c b/net/rds/bind.c
index adb53ae97a02..cc7e3a138598 100644
--- a/net/rds/bind.c
+++ b/net/rds/bind.c
@@ -60,11 +60,13 @@ struct rds_sock *rds_find_bound(__be32 addr, __be16 port)
u64 key = ((u64)addr << 32) | port;
struct rds_sock *rs;
- rs = rhashtable_lookup_fast(&bind_hash_table, &key, ht_parms);
+ rcu_read_lock();
+ rs = rhashtable_lookup(&bind_hash_table, &key, ht_parms);
if (rs && !sock_flag(rds_rs_to_sk(rs), SOCK_DEAD))
rds_sock_addref(rs);
else
rs = NULL;
+ rcu_read_unlock();
rdsdebug("returning rs %p for %pI4:%u\n", rs, &addr,
ntohs(port));
@@ -157,6 +159,7 @@ int rds_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
goto out;
}
+ sock_set_flag(sk, SOCK_RCU_FREE);
ret = rds_add_bound(rs, sin->sin_addr.s_addr, &sin->sin_port);
if (ret)
goto out;