aboutsummaryrefslogtreecommitdiffstats
path: root/net/tipc/socket.c
diff options
context:
space:
mode:
authorParthasarathy Bhuvaragan <parthasarathy.bhuvaragan@ericsson.com>2016-03-01 05:07:09 -0500
committerDavid S. Miller <davem@davemloft.net>2016-03-03 16:30:29 -0500
commitf214fc402967e1bc94ad7f39faa03db5813d6849 (patch)
tree5d2ed4587e08c100519da814d6e4af9e11052cb4 /net/tipc/socket.c
parent1837b2e2bcd23137766555a63867e649c0b637f0 (diff)
tipc: Revert "tipc: use existing sk_write_queue for outgoing packet chain"
reverts commit 94153e36e709e ("tipc: use existing sk_write_queue for outgoing packet chain") In Commit 94153e36e709e, we assume that we fill & empty the socket's sk_write_queue within the same lock_sock() session. This is not true if the link is congested. During congestion, the socket lock is released while we wait for the congestion to cease. This implementation causes a nullptr exception, if the user space program has several threads accessing the same socket descriptor. Consider two threads of the same program performing the following: Thread1 Thread2 -------------------- ---------------------- Enter tipc_sendmsg() Enter tipc_sendmsg() lock_sock() lock_sock() Enter tipc_link_xmit(), ret=ELINKCONG spin on socket lock.. sk_wait_event() : release_sock() grab socket lock : Enter tipc_link_xmit(), ret=0 : release_sock() Wakeup after congestion lock_sock() skb = skb_peek(pktchain); !! TIPC_SKB_CB(skb)->wakeup_pending = tsk->link_cong; In this case, the second thread transmits the buffers belonging to both thread1 and thread2 successfully. When the first thread wakeup after the congestion it assumes that the pktchain is intact and operates on the skb's in it, which leads to the following exception: [2102.439969] BUG: unable to handle kernel NULL pointer dereference at 00000000000000d0 [2102.440074] IP: [<ffffffffa005f330>] __tipc_link_xmit+0x2b0/0x4d0 [tipc] [2102.440074] PGD 3fa3f067 PUD 3fa6b067 PMD 0 [2102.440074] Oops: 0000 [#1] SMP [2102.440074] CPU: 2 PID: 244 Comm: sender Not tainted 3.12.28 #1 [2102.440074] RIP: 0010:[<ffffffffa005f330>] [<ffffffffa005f330>] __tipc_link_xmit+0x2b0/0x4d0 [tipc] [...] [2102.440074] Call Trace: [2102.440074] [<ffffffff8163f0b9>] ? schedule+0x29/0x70 [2102.440074] [<ffffffffa006a756>] ? tipc_node_unlock+0x46/0x170 [tipc] [2102.440074] [<ffffffffa005f761>] tipc_link_xmit+0x51/0xf0 [tipc] [2102.440074] [<ffffffffa006d8ae>] tipc_send_stream+0x11e/0x4f0 [tipc] [2102.440074] [<ffffffff8106b150>] ? __wake_up_sync+0x20/0x20 [2102.440074] [<ffffffffa006dc9c>] tipc_send_packet+0x1c/0x20 [tipc] [2102.440074] [<ffffffff81502478>] sock_sendmsg+0xa8/0xd0 [2102.440074] [<ffffffff81507895>] ? release_sock+0x145/0x170 [2102.440074] [<ffffffff815030d8>] ___sys_sendmsg+0x3d8/0x3e0 [2102.440074] [<ffffffff816426ae>] ? _raw_spin_unlock+0xe/0x10 [2102.440074] [<ffffffff81115c2a>] ? handle_mm_fault+0x6ca/0x9d0 [2102.440074] [<ffffffff8107dd65>] ? set_next_entity+0x85/0xa0 [2102.440074] [<ffffffff816426de>] ? _raw_spin_unlock_irq+0xe/0x20 [2102.440074] [<ffffffff8107463c>] ? finish_task_switch+0x5c/0xc0 [2102.440074] [<ffffffff8163ea8c>] ? __schedule+0x34c/0x950 [2102.440074] [<ffffffff81504e12>] __sys_sendmsg+0x42/0x80 [2102.440074] [<ffffffff81504e62>] SyS_sendmsg+0x12/0x20 [2102.440074] [<ffffffff8164aed2>] system_call_fastpath+0x16/0x1b In this commit, we maintain the skb list always in the stack. Signed-off-by: Parthasarathy Bhuvaragan <parthasarathy.bhuvaragan@ericsson.com> Acked-by: Ying Xue <ying.xue@windriver.com> Acked-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.c33
1 files changed, 19 insertions, 14 deletions
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index 69c29050f14a..4d420bb27396 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -673,7 +673,7 @@ static int tipc_sendmcast(struct socket *sock, struct tipc_name_seq *seq,
673 struct tipc_sock *tsk = tipc_sk(sk); 673 struct tipc_sock *tsk = tipc_sk(sk);
674 struct net *net = sock_net(sk); 674 struct net *net = sock_net(sk);
675 struct tipc_msg *mhdr = &tsk->phdr; 675 struct tipc_msg *mhdr = &tsk->phdr;
676 struct sk_buff_head *pktchain = &sk->sk_write_queue; 676 struct sk_buff_head pktchain;
677 struct iov_iter save = msg->msg_iter; 677 struct iov_iter save = msg->msg_iter;
678 uint mtu; 678 uint mtu;
679 int rc; 679 int rc;
@@ -687,14 +687,16 @@ static int tipc_sendmcast(struct socket *sock, struct tipc_name_seq *seq,
687 msg_set_nameupper(mhdr, seq->upper); 687 msg_set_nameupper(mhdr, seq->upper);
688 msg_set_hdr_sz(mhdr, MCAST_H_SIZE); 688 msg_set_hdr_sz(mhdr, MCAST_H_SIZE);
689 689
690 skb_queue_head_init(&pktchain);
691
690new_mtu: 692new_mtu:
691 mtu = tipc_bcast_get_mtu(net); 693 mtu = tipc_bcast_get_mtu(net);
692 rc = tipc_msg_build(mhdr, msg, 0, dsz, mtu, pktchain); 694 rc = tipc_msg_build(mhdr, msg, 0, dsz, mtu, &pktchain);
693 if (unlikely(rc < 0)) 695 if (unlikely(rc < 0))
694 return rc; 696 return rc;
695 697
696 do { 698 do {
697 rc = tipc_bcast_xmit(net, pktchain); 699 rc = tipc_bcast_xmit(net, &pktchain);
698 if (likely(!rc)) 700 if (likely(!rc))
699 return dsz; 701 return dsz;
700 702
@@ -704,7 +706,7 @@ new_mtu:
704 if (!rc) 706 if (!rc)
705 continue; 707 continue;
706 } 708 }
707 __skb_queue_purge(pktchain); 709 __skb_queue_purge(&pktchain);
708 if (rc == -EMSGSIZE) { 710 if (rc == -EMSGSIZE) {
709 msg->msg_iter = save; 711 msg->msg_iter = save;
710 goto new_mtu; 712 goto new_mtu;
@@ -863,7 +865,7 @@ static int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t dsz)
863 struct net *net = sock_net(sk); 865 struct net *net = sock_net(sk);
864 struct tipc_msg *mhdr = &tsk->phdr; 866 struct tipc_msg *mhdr = &tsk->phdr;
865 u32 dnode, dport; 867 u32 dnode, dport;
866 struct sk_buff_head *pktchain = &sk->sk_write_queue; 868 struct sk_buff_head pktchain;
867 struct sk_buff *skb; 869 struct sk_buff *skb;
868 struct tipc_name_seq *seq; 870 struct tipc_name_seq *seq;
869 struct iov_iter save; 871 struct iov_iter save;
@@ -924,17 +926,18 @@ static int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t dsz)
924 msg_set_hdr_sz(mhdr, BASIC_H_SIZE); 926 msg_set_hdr_sz(mhdr, BASIC_H_SIZE);
925 } 927 }
926 928
929 skb_queue_head_init(&pktchain);
927 save = m->msg_iter; 930 save = m->msg_iter;
928new_mtu: 931new_mtu:
929 mtu = tipc_node_get_mtu(net, dnode, tsk->portid); 932 mtu = tipc_node_get_mtu(net, dnode, tsk->portid);
930 rc = tipc_msg_build(mhdr, m, 0, dsz, mtu, pktchain); 933 rc = tipc_msg_build(mhdr, m, 0, dsz, mtu, &pktchain);
931 if (rc < 0) 934 if (rc < 0)
932 return rc; 935 return rc;
933 936
934 do { 937 do {
935 skb = skb_peek(pktchain); 938 skb = skb_peek(&pktchain);
936 TIPC_SKB_CB(skb)->wakeup_pending = tsk->link_cong; 939 TIPC_SKB_CB(skb)->wakeup_pending = tsk->link_cong;
937 rc = tipc_node_xmit(net, pktchain, dnode, tsk->portid); 940 rc = tipc_node_xmit(net, &pktchain, dnode, tsk->portid);
938 if (likely(!rc)) { 941 if (likely(!rc)) {
939 if (sock->state != SS_READY) 942 if (sock->state != SS_READY)
940 sock->state = SS_CONNECTING; 943 sock->state = SS_CONNECTING;
@@ -946,7 +949,7 @@ new_mtu:
946 if (!rc) 949 if (!rc)
947 continue; 950 continue;
948 } 951 }
949 __skb_queue_purge(pktchain); 952 __skb_queue_purge(&pktchain);
950 if (rc == -EMSGSIZE) { 953 if (rc == -EMSGSIZE) {
951 m->msg_iter = save; 954 m->msg_iter = save;
952 goto new_mtu; 955 goto new_mtu;
@@ -1016,7 +1019,7 @@ static int __tipc_send_stream(struct socket *sock, struct msghdr *m, size_t dsz)
1016 struct net *net = sock_net(sk); 1019 struct net *net = sock_net(sk);
1017 struct tipc_sock *tsk = tipc_sk(sk); 1020 struct tipc_sock *tsk = tipc_sk(sk);
1018 struct tipc_msg *mhdr = &tsk->phdr; 1021 struct tipc_msg *mhdr = &tsk->phdr;
1019 struct sk_buff_head *pktchain = &sk->sk_write_queue; 1022 struct sk_buff_head pktchain;
1020 DECLARE_SOCKADDR(struct sockaddr_tipc *, dest, m->msg_name); 1023 DECLARE_SOCKADDR(struct sockaddr_tipc *, dest, m->msg_name);
1021 u32 portid = tsk->portid; 1024 u32 portid = tsk->portid;
1022 int rc = -EINVAL; 1025 int rc = -EINVAL;
@@ -1044,17 +1047,19 @@ static int __tipc_send_stream(struct socket *sock, struct msghdr *m, size_t dsz)
1044 1047
1045 timeo = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT); 1048 timeo = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT);
1046 dnode = tsk_peer_node(tsk); 1049 dnode = tsk_peer_node(tsk);
1050 skb_queue_head_init(&pktchain);
1047 1051
1048next: 1052next:
1049 save = m->msg_iter; 1053 save = m->msg_iter;
1050 mtu = tsk->max_pkt; 1054 mtu = tsk->max_pkt;
1051 send = min_t(uint, dsz - sent, TIPC_MAX_USER_MSG_SIZE); 1055 send = min_t(uint, dsz - sent, TIPC_MAX_USER_MSG_SIZE);
1052 rc = tipc_msg_build(mhdr, m, sent, send, mtu, pktchain); 1056 rc = tipc_msg_build(mhdr, m, sent, send, mtu, &pktchain);
1053 if (unlikely(rc < 0)) 1057 if (unlikely(rc < 0))
1054 return rc; 1058 return rc;
1059
1055 do { 1060 do {
1056 if (likely(!tsk_conn_cong(tsk))) { 1061 if (likely(!tsk_conn_cong(tsk))) {
1057 rc = tipc_node_xmit(net, pktchain, dnode, portid); 1062 rc = tipc_node_xmit(net, &pktchain, dnode, portid);
1058 if (likely(!rc)) { 1063 if (likely(!rc)) {
1059 tsk->sent_unacked++; 1064 tsk->sent_unacked++;
1060 sent += send; 1065 sent += send;
@@ -1063,7 +1068,7 @@ next:
1063 goto next; 1068 goto next;
1064 } 1069 }
1065 if (rc == -EMSGSIZE) { 1070 if (rc == -EMSGSIZE) {
1066 __skb_queue_purge(pktchain); 1071 __skb_queue_purge(&pktchain);
1067 tsk->max_pkt = tipc_node_get_mtu(net, dnode, 1072 tsk->max_pkt = tipc_node_get_mtu(net, dnode,
1068 portid); 1073 portid);
1069 m->msg_iter = save; 1074 m->msg_iter = save;
@@ -1077,7 +1082,7 @@ next:
1077 rc = tipc_wait_for_sndpkt(sock, &timeo); 1082 rc = tipc_wait_for_sndpkt(sock, &timeo);
1078 } while (!rc); 1083 } while (!rc);
1079 1084
1080 __skb_queue_purge(pktchain); 1085 __skb_queue_purge(&pktchain);
1081 return sent ? sent : rc; 1086 return sent ? sent : rc;
1082} 1087}
1083 1088