|
From: Parthasarathy B. <par...@er...> - 2017-04-27 11:54:26
|
In filter_rcv(), when we detect protocol messages with error we
reset the connection and notify the socket using sk_state_change().
tipc_backlog_rcv() also calls filter_rcv() while holding the socket
lock and since the socket is already awake sk_state_change() is
ignored and this error is lost. Now the receive queue will remain
empty and the socket sleeps forever.
In this commit, we enqueue this error message into the socket's
receive queue in addition to the above state change to cover all
conditions.
Signed-off-by: Parthasarathy Bhuvaragan <par...@er...>
---
net/tipc/socket.c | 47 +++++++++++++++++++++++++----------------------
1 file changed, 25 insertions(+), 22 deletions(-)
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index 953655cc05a7..0ab98ec94e7e 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -852,8 +852,10 @@ void tipc_sk_mcast_rcv(struct net *net, struct sk_buff_head *arrvq,
* tipc_sk_proto_rcv - receive a connection mng protocol message
* @tsk: receiving socket
* @skb: pointer to message buffer.
+ *
+ * Returns true if skb should be queued to socket, false otherwise.
*/
-static void tipc_sk_proto_rcv(struct tipc_sock *tsk, struct sk_buff *skb,
+static bool tipc_sk_proto_rcv(struct tipc_sock *tsk, struct sk_buff *skb,
struct sk_buff_head *xmitq)
{
struct sock *sk = &tsk->sk;
@@ -871,7 +873,7 @@ static void tipc_sk_proto_rcv(struct tipc_sock *tsk, struct sk_buff *skb,
tipc_node_remove_conn(sock_net(sk), tsk_peer_node(tsk),
tsk_peer_port(tsk));
sk->sk_state_change(sk);
- goto exit;
+ return true;
}
tsk->probe_unacked = false;
@@ -880,7 +882,7 @@ static void tipc_sk_proto_rcv(struct tipc_sock *tsk, struct sk_buff *skb,
msg_set_type(hdr, CONN_PROBE_REPLY);
if (tipc_msg_reverse(onode, &skb, TIPC_OK))
__skb_queue_tail(xmitq, skb);
- return;
+ return false;
} else if (mtyp == CONN_ACK) {
conn_cong = tsk_conn_cong(tsk);
tsk->snt_unacked -= msg_conn_ack(hdr);
@@ -893,6 +895,7 @@ static void tipc_sk_proto_rcv(struct tipc_sock *tsk, struct sk_buff *skb,
}
exit:
kfree_skb(skb);
+ return false;
}
/**
@@ -1699,35 +1702,35 @@ static bool filter_rcv(struct sock *sk, struct sk_buff *skb,
int usr = msg_user(hdr);
u32 onode;
- if (unlikely(msg_user(hdr) == CONN_MANAGER)) {
- tipc_sk_proto_rcv(tsk, skb, xmitq);
- return false;
- }
-
- if (unlikely(usr == SOCK_WAKEUP)) {
+ switch (usr) {
+ case CONN_MANAGER:
+ if (!tipc_sk_proto_rcv(tsk, skb, xmitq))
+ return false;
+ break;
+ case SOCK_WAKEUP:
onode = msg_orignode(hdr);
kfree_skb(skb);
u32_del(&tsk->cong_links, onode);
tsk->cong_link_cnt--;
sk->sk_write_space(sk);
return false;
- }
-
- /* Drop if illegal message type */
- if (unlikely(msg_type(hdr) > TIPC_DIRECT_MSG)) {
- kfree_skb(skb);
- return false;
- }
+ default:
+ /* Drop if illegal message type */
+ if (unlikely(msg_type(hdr) > TIPC_DIRECT_MSG)) {
+ kfree_skb(skb);
+ return false;
+ }
- /* Reject if wrong message type for current socket state */
- if (tipc_sk_type_connectionless(sk)) {
- if (msg_connected(hdr)) {
+ /* Reject if wrong message type for current socket state */
+ if (tipc_sk_type_connectionless(sk)) {
+ if (msg_connected(hdr)) {
+ err = TIPC_ERR_NO_PORT;
+ goto reject;
+ }
+ } else if (unlikely(!filter_connect(tsk, skb))) {
err = TIPC_ERR_NO_PORT;
goto reject;
}
- } else if (unlikely(!filter_connect(tsk, skb))) {
- err = TIPC_ERR_NO_PORT;
- goto reject;
}
/* Reject message if there isn't room to queue it */
--
2.1.4
|