ocfs2/o2net: o2net_listen_data_ready should do nothing if socket state is not TCP_LISTEN
Orabug: 17330860 When accepting an incomming connection o2net_accept_one clones a child data socket from the parent listening socket. It then proceeds to setup the child with callback o2net_data_ready() and sk_user_data to NULL. If data arrives in this window, o2net_listen_data_ready will be called with some non-deterministic value in sk_user_data (not inherited). We panic when we page fault on sk_user_data -- in parent it is sock_def_readable(). The fix is to recognize that this is a data socket being set up by looking at the socket state and do nothing. Signed-off-by: Tariq Saseed <tariq.x.saeed@oracle.com> Signed-off-by: Srinivas Eeda <srinivas.eeda@oracle.com> Reviewed-by: Mark Fasheh <mfasheh@suse.com> Cc: Joel Becker <jlbec@evilplan.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Родитель
db66c71577
Коммит
da8ded405d
|
@ -1964,17 +1964,29 @@ static void o2net_listen_data_ready(struct sock *sk, int bytes)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ->sk_data_ready is also called for a newly established child socket
|
/* This callback may called twice when a new connection
|
||||||
* before it has been accepted and the acceptor has set up their
|
* is being established as a child socket inherits everything
|
||||||
* data_ready.. we only want to queue listen work for our listening
|
* from a parent LISTEN socket, including the data_ready cb of
|
||||||
* socket */
|
* the parent. This leads to a hazard. In o2net_accept_one()
|
||||||
|
* we are still initializing the child socket but have not
|
||||||
|
* changed the inherited data_ready callback yet when
|
||||||
|
* data starts arriving.
|
||||||
|
* We avoid this hazard by checking the state.
|
||||||
|
* For the listening socket, the state will be TCP_LISTEN; for the new
|
||||||
|
* socket, will be TCP_ESTABLISHED. Also, in this case,
|
||||||
|
* sk->sk_user_data is not a valid function pointer.
|
||||||
|
*/
|
||||||
|
|
||||||
if (sk->sk_state == TCP_LISTEN) {
|
if (sk->sk_state == TCP_LISTEN) {
|
||||||
mlog(ML_TCP, "bytes: %d\n", bytes);
|
mlog(ML_TCP, "bytes: %d\n", bytes);
|
||||||
queue_work(o2net_wq, &o2net_listen_work);
|
queue_work(o2net_wq, &o2net_listen_work);
|
||||||
|
} else {
|
||||||
|
ready = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
read_unlock(&sk->sk_callback_lock);
|
read_unlock(&sk->sk_callback_lock);
|
||||||
|
if (ready != NULL)
|
||||||
ready(sk, bytes);
|
ready(sk, bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче