mirror of
https://github.com/torvalds/linux.git
synced 2024-11-25 13:41:51 +00:00
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: Parthasarathy Bhuvaragan <parthasarathy.bhuvaragan@ericsson.com> Reviewed-by: Jon Maloy <jon.maloy@ericsson.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
42b531de17
commit
4e0df4951e
@ -1259,7 +1259,10 @@ static int tipc_wait_for_rcvmsg(struct socket *sock, long *timeop)
|
||||
struct sock *sk = sock->sk;
|
||||
DEFINE_WAIT(wait);
|
||||
long timeo = *timeop;
|
||||
int err;
|
||||
int err = sock_error(sk);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
for (;;) {
|
||||
prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
|
||||
@ -1281,6 +1284,10 @@ static int tipc_wait_for_rcvmsg(struct socket *sock, long *timeop)
|
||||
err = sock_intr_errno(timeo);
|
||||
if (signal_pending(current))
|
||||
break;
|
||||
|
||||
err = sock_error(sk);
|
||||
if (err)
|
||||
break;
|
||||
}
|
||||
finish_wait(sk_sleep(sk), &wait);
|
||||
*timeop = timeo;
|
||||
@ -1551,6 +1558,8 @@ static bool filter_connect(struct tipc_sock *tsk, struct sk_buff *skb)
|
||||
struct sock *sk = &tsk->sk;
|
||||
struct net *net = sock_net(sk);
|
||||
struct tipc_msg *hdr = buf_msg(skb);
|
||||
u32 pport = msg_origport(hdr);
|
||||
u32 pnode = msg_orignode(hdr);
|
||||
|
||||
if (unlikely(msg_mcast(hdr)))
|
||||
return false;
|
||||
@ -1558,18 +1567,28 @@ static bool filter_connect(struct tipc_sock *tsk, struct sk_buff *skb)
|
||||
switch (sk->sk_state) {
|
||||
case TIPC_CONNECTING:
|
||||
/* Accept only ACK or NACK message */
|
||||
if (unlikely(!msg_connected(hdr)))
|
||||
return false;
|
||||
if (unlikely(!msg_connected(hdr))) {
|
||||
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))) {
|
||||
tipc_set_sk_state(sk, TIPC_DISCONNECTING);
|
||||
sk->sk_err = ECONNREFUSED;
|
||||
sk->sk_state_change(sk);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (unlikely(!msg_isdata(hdr))) {
|
||||
tipc_set_sk_state(sk, TIPC_DISCONNECTING);
|
||||
sk->sk_err = EINVAL;
|
||||
sk->sk_state_change(sk);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user