Commit 4e0df495 authored by Parthasarathy Bhuvaragan's avatar Parthasarathy Bhuvaragan Committed by David S. Miller

tipc: improve error validations for sockets in CONNECTING state

Until now, the checks for sockets in CONNECTING state was based on
the assumption that the incoming message was always from the
peer's accepted data socket.

However an application using a non-blocking socket sends an implicit
connect, this socket which is in CONNECTING state can receive error
messages from the peer's listening socket. As we discard these
messages, the application socket hangs as there due to inactivity.
In addition to this, there are other places where we process errors
but do not notify the user.

In this commit, we process such incoming error messages and notify
our users about them using sk_state_change().
Signed-off-by: default avatarParthasarathy Bhuvaragan <parthasarathy.bhuvaragan@ericsson.com>
Reviewed-by: default avatarJon Maloy <jon.maloy@ericsson.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 42b531de
...@@ -1259,7 +1259,10 @@ static int tipc_wait_for_rcvmsg(struct socket *sock, long *timeop) ...@@ -1259,7 +1259,10 @@ static int tipc_wait_for_rcvmsg(struct socket *sock, long *timeop)
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
DEFINE_WAIT(wait); DEFINE_WAIT(wait);
long timeo = *timeop; long timeo = *timeop;
int err; int err = sock_error(sk);
if (err)
return err;
for (;;) { for (;;) {
prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
...@@ -1281,6 +1284,10 @@ static int tipc_wait_for_rcvmsg(struct socket *sock, long *timeop) ...@@ -1281,6 +1284,10 @@ static int tipc_wait_for_rcvmsg(struct socket *sock, long *timeop)
err = sock_intr_errno(timeo); err = sock_intr_errno(timeo);
if (signal_pending(current)) if (signal_pending(current))
break; break;
err = sock_error(sk);
if (err)
break;
} }
finish_wait(sk_sleep(sk), &wait); finish_wait(sk_sleep(sk), &wait);
*timeop = timeo; *timeop = timeo;
...@@ -1551,6 +1558,8 @@ static bool filter_connect(struct tipc_sock *tsk, struct sk_buff *skb) ...@@ -1551,6 +1558,8 @@ static bool filter_connect(struct tipc_sock *tsk, struct sk_buff *skb)
struct sock *sk = &tsk->sk; struct sock *sk = &tsk->sk;
struct net *net = sock_net(sk); struct net *net = sock_net(sk);
struct tipc_msg *hdr = buf_msg(skb); struct tipc_msg *hdr = buf_msg(skb);
u32 pport = msg_origport(hdr);
u32 pnode = msg_orignode(hdr);
if (unlikely(msg_mcast(hdr))) if (unlikely(msg_mcast(hdr)))
return false; return false;
...@@ -1558,18 +1567,28 @@ static bool filter_connect(struct tipc_sock *tsk, struct sk_buff *skb) ...@@ -1558,18 +1567,28 @@ static bool filter_connect(struct tipc_sock *tsk, struct sk_buff *skb)
switch (sk->sk_state) { switch (sk->sk_state) {
case TIPC_CONNECTING: case TIPC_CONNECTING:
/* Accept only ACK or NACK message */ /* Accept only ACK or NACK message */
if (unlikely(!msg_connected(hdr))) if (unlikely(!msg_connected(hdr))) {
return false; if (pport != tsk_peer_port(tsk) ||
pnode != tsk_peer_node(tsk))
return false;
tipc_set_sk_state(sk, TIPC_DISCONNECTING);
sk->sk_err = ECONNREFUSED;
sk->sk_state_change(sk);
return true;
}
if (unlikely(msg_errcode(hdr))) { if (unlikely(msg_errcode(hdr))) {
tipc_set_sk_state(sk, TIPC_DISCONNECTING); tipc_set_sk_state(sk, TIPC_DISCONNECTING);
sk->sk_err = ECONNREFUSED; sk->sk_err = ECONNREFUSED;
sk->sk_state_change(sk);
return true; return true;
} }
if (unlikely(!msg_isdata(hdr))) { if (unlikely(!msg_isdata(hdr))) {
tipc_set_sk_state(sk, TIPC_DISCONNECTING); tipc_set_sk_state(sk, TIPC_DISCONNECTING);
sk->sk_err = EINVAL; sk->sk_err = EINVAL;
sk->sk_state_change(sk);
return true; return true;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment