diff options
author | Cong Wang <xiyou.wangcong@gmail.com> | 2018-12-12 00:43:51 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-12-14 18:48:49 -0500 |
commit | 143ece654f9f5b37bedea252a990be37e48ae3a5 (patch) | |
tree | 3268762e6be9aa0bbb5a1a6de35e77d67e08175b /net/tipc | |
parent | 65cab850f0eeaa9180bd2e10a231964f33743edf (diff) |
tipc: check tsk->group in tipc_wait_for_cond()
tipc_wait_for_cond() drops socket lock before going to sleep,
but tsk->group could be freed right after that release_sock().
So we have to re-check and reload tsk->group after it wakes up.
After this patch, tipc_wait_for_cond() returns -ERESTARTSYS when
tsk->group is NULL, instead of continuing with the assumption of
a non-NULL tsk->group.
(It looks like 'dsts' should be re-checked and reloaded too, but
it is a different bug.)
Similar for tipc_send_group_unicast() and tipc_send_group_anycast().
Reported-by: syzbot+10a9db47c3a0e13eb31c@syzkaller.appspotmail.com
Fixes: b7d42635517f ("tipc: introduce flow control for group broadcast messages")
Fixes: ee106d7f942d ("tipc: introduce group anycast messaging")
Fixes: 27bd9ec027f3 ("tipc: introduce group unicast messaging")
Cc: Ying Xue <ying.xue@windriver.com>
Cc: Jon Maloy <jon.maloy@ericsson.com>
Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
Acked-by: Ying Xue <ying.xue@windriver.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/tipc')
-rw-r--r-- | net/tipc/socket.c | 25 |
1 files changed, 14 insertions, 11 deletions
diff --git a/net/tipc/socket.c b/net/tipc/socket.c index e1396fb87779..656940692a44 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c | |||
@@ -880,7 +880,6 @@ static int tipc_send_group_unicast(struct socket *sock, struct msghdr *m, | |||
880 | DECLARE_SOCKADDR(struct sockaddr_tipc *, dest, m->msg_name); | 880 | DECLARE_SOCKADDR(struct sockaddr_tipc *, dest, m->msg_name); |
881 | int blks = tsk_blocks(GROUP_H_SIZE + dlen); | 881 | int blks = tsk_blocks(GROUP_H_SIZE + dlen); |
882 | struct tipc_sock *tsk = tipc_sk(sk); | 882 | struct tipc_sock *tsk = tipc_sk(sk); |
883 | struct tipc_group *grp = tsk->group; | ||
884 | struct net *net = sock_net(sk); | 883 | struct net *net = sock_net(sk); |
885 | struct tipc_member *mb = NULL; | 884 | struct tipc_member *mb = NULL; |
886 | u32 node, port; | 885 | u32 node, port; |
@@ -894,7 +893,9 @@ static int tipc_send_group_unicast(struct socket *sock, struct msghdr *m, | |||
894 | /* Block or return if destination link or member is congested */ | 893 | /* Block or return if destination link or member is congested */ |
895 | rc = tipc_wait_for_cond(sock, &timeout, | 894 | rc = tipc_wait_for_cond(sock, &timeout, |
896 | !tipc_dest_find(&tsk->cong_links, node, 0) && | 895 | !tipc_dest_find(&tsk->cong_links, node, 0) && |
897 | !tipc_group_cong(grp, node, port, blks, &mb)); | 896 | tsk->group && |
897 | !tipc_group_cong(tsk->group, node, port, blks, | ||
898 | &mb)); | ||
898 | if (unlikely(rc)) | 899 | if (unlikely(rc)) |
899 | return rc; | 900 | return rc; |
900 | 901 | ||
@@ -924,7 +925,6 @@ static int tipc_send_group_anycast(struct socket *sock, struct msghdr *m, | |||
924 | struct tipc_sock *tsk = tipc_sk(sk); | 925 | struct tipc_sock *tsk = tipc_sk(sk); |
925 | struct list_head *cong_links = &tsk->cong_links; | 926 | struct list_head *cong_links = &tsk->cong_links; |
926 | int blks = tsk_blocks(GROUP_H_SIZE + dlen); | 927 | int blks = tsk_blocks(GROUP_H_SIZE + dlen); |
927 | struct tipc_group *grp = tsk->group; | ||
928 | struct tipc_msg *hdr = &tsk->phdr; | 928 | struct tipc_msg *hdr = &tsk->phdr; |
929 | struct tipc_member *first = NULL; | 929 | struct tipc_member *first = NULL; |
930 | struct tipc_member *mbr = NULL; | 930 | struct tipc_member *mbr = NULL; |
@@ -941,9 +941,10 @@ static int tipc_send_group_anycast(struct socket *sock, struct msghdr *m, | |||
941 | type = msg_nametype(hdr); | 941 | type = msg_nametype(hdr); |
942 | inst = dest->addr.name.name.instance; | 942 | inst = dest->addr.name.name.instance; |
943 | scope = msg_lookup_scope(hdr); | 943 | scope = msg_lookup_scope(hdr); |
944 | exclude = tipc_group_exclude(grp); | ||
945 | 944 | ||
946 | while (++lookups < 4) { | 945 | while (++lookups < 4) { |
946 | exclude = tipc_group_exclude(tsk->group); | ||
947 | |||
947 | first = NULL; | 948 | first = NULL; |
948 | 949 | ||
949 | /* Look for a non-congested destination member, if any */ | 950 | /* Look for a non-congested destination member, if any */ |
@@ -952,7 +953,8 @@ static int tipc_send_group_anycast(struct socket *sock, struct msghdr *m, | |||
952 | &dstcnt, exclude, false)) | 953 | &dstcnt, exclude, false)) |
953 | return -EHOSTUNREACH; | 954 | return -EHOSTUNREACH; |
954 | tipc_dest_pop(&dsts, &node, &port); | 955 | tipc_dest_pop(&dsts, &node, &port); |
955 | cong = tipc_group_cong(grp, node, port, blks, &mbr); | 956 | cong = tipc_group_cong(tsk->group, node, port, blks, |
957 | &mbr); | ||
956 | if (!cong) | 958 | if (!cong) |
957 | break; | 959 | break; |
958 | if (mbr == first) | 960 | if (mbr == first) |
@@ -971,7 +973,8 @@ static int tipc_send_group_anycast(struct socket *sock, struct msghdr *m, | |||
971 | /* Block or return if destination link or member is congested */ | 973 | /* Block or return if destination link or member is congested */ |
972 | rc = tipc_wait_for_cond(sock, &timeout, | 974 | rc = tipc_wait_for_cond(sock, &timeout, |
973 | !tipc_dest_find(cong_links, node, 0) && | 975 | !tipc_dest_find(cong_links, node, 0) && |
974 | !tipc_group_cong(grp, node, port, | 976 | tsk->group && |
977 | !tipc_group_cong(tsk->group, node, port, | ||
975 | blks, &mbr)); | 978 | blks, &mbr)); |
976 | if (unlikely(rc)) | 979 | if (unlikely(rc)) |
977 | return rc; | 980 | return rc; |
@@ -1006,8 +1009,7 @@ static int tipc_send_group_bcast(struct socket *sock, struct msghdr *m, | |||
1006 | struct sock *sk = sock->sk; | 1009 | struct sock *sk = sock->sk; |
1007 | struct net *net = sock_net(sk); | 1010 | struct net *net = sock_net(sk); |
1008 | struct tipc_sock *tsk = tipc_sk(sk); | 1011 | struct tipc_sock *tsk = tipc_sk(sk); |
1009 | struct tipc_group *grp = tsk->group; | 1012 | struct tipc_nlist *dsts = tipc_group_dests(tsk->group); |
1010 | struct tipc_nlist *dsts = tipc_group_dests(grp); | ||
1011 | struct tipc_mc_method *method = &tsk->mc_method; | 1013 | struct tipc_mc_method *method = &tsk->mc_method; |
1012 | bool ack = method->mandatory && method->rcast; | 1014 | bool ack = method->mandatory && method->rcast; |
1013 | int blks = tsk_blocks(MCAST_H_SIZE + dlen); | 1015 | int blks = tsk_blocks(MCAST_H_SIZE + dlen); |
@@ -1020,8 +1022,9 @@ static int tipc_send_group_bcast(struct socket *sock, struct msghdr *m, | |||
1020 | return -EHOSTUNREACH; | 1022 | return -EHOSTUNREACH; |
1021 | 1023 | ||
1022 | /* Block or return if any destination link or member is congested */ | 1024 | /* Block or return if any destination link or member is congested */ |
1023 | rc = tipc_wait_for_cond(sock, &timeout, !tsk->cong_link_cnt && | 1025 | rc = tipc_wait_for_cond(sock, &timeout, |
1024 | !tipc_group_bc_cong(grp, blks)); | 1026 | !tsk->cong_link_cnt && tsk->group && |
1027 | !tipc_group_bc_cong(tsk->group, blks)); | ||
1025 | if (unlikely(rc)) | 1028 | if (unlikely(rc)) |
1026 | return rc; | 1029 | return rc; |
1027 | 1030 | ||
@@ -1036,7 +1039,7 @@ static int tipc_send_group_bcast(struct socket *sock, struct msghdr *m, | |||
1036 | msg_set_hdr_sz(hdr, GROUP_H_SIZE); | 1039 | msg_set_hdr_sz(hdr, GROUP_H_SIZE); |
1037 | msg_set_destport(hdr, 0); | 1040 | msg_set_destport(hdr, 0); |
1038 | msg_set_destnode(hdr, 0); | 1041 | msg_set_destnode(hdr, 0); |
1039 | msg_set_grp_bc_seqno(hdr, tipc_group_bc_snd_nxt(grp)); | 1042 | msg_set_grp_bc_seqno(hdr, tipc_group_bc_snd_nxt(tsk->group)); |
1040 | 1043 | ||
1041 | /* Avoid getting stuck with repeated forced replicasts */ | 1044 | /* Avoid getting stuck with repeated forced replicasts */ |
1042 | msg_set_grp_bc_ack_req(hdr, ack); | 1045 | msg_set_grp_bc_ack_req(hdr, ack); |