aboutsummaryrefslogtreecommitdiffstats
path: root/net/tipc/socket.c
diff options
context:
space:
mode:
authorJon Maloy <jon.maloy@ericsson.com>2018-01-17 10:42:46 -0500
committerDavid S. Miller <davem@davemloft.net>2018-01-19 15:12:21 -0500
commit60c2530696320ee6ffe4491c17079fa403790c98 (patch)
tree619bdaecd86e48c1962a6866e40ada7e09c5addc /net/tipc/socket.c
parent30c3e9d470358a6741e00e1034a1ea85c6a516f0 (diff)
tipc: fix race between poll() and setsockopt()
Letting tipc_poll() dereference a socket's pointer to struct tipc_group entails a race risk, as the group item may be deleted in a concurrent tipc_sk_join() or tipc_sk_leave() thread. We now move the 'open' flag in struct tipc_group to struct tipc_sock, and let the former retain only a pointer to the moved field. This will eliminate the race risk. Reported-by: syzbot+799dafde0286795858ac@syzkaller.appspotmail.com Signed-off-by: Jon Maloy <jon.maloy@ericsson.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/tipc/socket.c')
-rw-r--r--net/tipc/socket.c7
1 files changed, 3 insertions, 4 deletions
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index d799e50ff722..473a096b6fba 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -116,6 +116,7 @@ struct tipc_sock {
116 struct tipc_mc_method mc_method; 116 struct tipc_mc_method mc_method;
117 struct rcu_head rcu; 117 struct rcu_head rcu;
118 struct tipc_group *group; 118 struct tipc_group *group;
119 bool group_is_open;
119}; 120};
120 121
121static int tipc_sk_backlog_rcv(struct sock *sk, struct sk_buff *skb); 122static int tipc_sk_backlog_rcv(struct sock *sk, struct sk_buff *skb);
@@ -715,7 +716,6 @@ static unsigned int tipc_poll(struct file *file, struct socket *sock,
715{ 716{
716 struct sock *sk = sock->sk; 717 struct sock *sk = sock->sk;
717 struct tipc_sock *tsk = tipc_sk(sk); 718 struct tipc_sock *tsk = tipc_sk(sk);
718 struct tipc_group *grp;
719 u32 revents = 0; 719 u32 revents = 0;
720 720
721 sock_poll_wait(file, sk_sleep(sk), wait); 721 sock_poll_wait(file, sk_sleep(sk), wait);
@@ -736,8 +736,7 @@ static unsigned int tipc_poll(struct file *file, struct socket *sock,
736 revents |= POLLIN | POLLRDNORM; 736 revents |= POLLIN | POLLRDNORM;
737 break; 737 break;
738 case TIPC_OPEN: 738 case TIPC_OPEN:
739 grp = tsk->group; 739 if (tsk->group_is_open && !tsk->cong_link_cnt)
740 if ((!grp || tipc_group_is_open(grp)) && !tsk->cong_link_cnt)
741 revents |= POLLOUT; 740 revents |= POLLOUT;
742 if (!tipc_sk_type_connectionless(sk)) 741 if (!tipc_sk_type_connectionless(sk))
743 break; 742 break;
@@ -2758,7 +2757,7 @@ static int tipc_sk_join(struct tipc_sock *tsk, struct tipc_group_req *mreq)
2758 return -EINVAL; 2757 return -EINVAL;
2759 if (grp) 2758 if (grp)
2760 return -EACCES; 2759 return -EACCES;
2761 grp = tipc_group_create(net, tsk->portid, mreq); 2760 grp = tipc_group_create(net, tsk->portid, mreq, &tsk->group_is_open);
2762 if (!grp) 2761 if (!grp)
2763 return -ENOMEM; 2762 return -ENOMEM;
2764 tsk->group = grp; 2763 tsk->group = grp;