aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorTariq Saeed <tariq.x.saeed@oracle.com>2014-04-03 17:47:11 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-04-03 19:20:56 -0400
commitda8ded405de74de4b189d1128f4c102d06328c29 (patch)
treef89ec00e4c725703aeba00e741f9e5203b9b7594 /fs
parentdb66c71577d525c0cd65e66ff675747565783ba4 (diff)
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>
Diffstat (limited to 'fs')
-rw-r--r--fs/ocfs2/cluster/tcp.c22
1 files changed, 17 insertions, 5 deletions
diff --git a/fs/ocfs2/cluster/tcp.c b/fs/ocfs2/cluster/tcp.c
index b4ab371d46d9..eb649d23a4de 100644
--- a/fs/ocfs2/cluster/tcp.c
+++ b/fs/ocfs2/cluster/tcp.c
@@ -1964,18 +1964,30 @@ static void o2net_listen_data_ready(struct sock *sk, int bytes)
1964 goto out; 1964 goto out;
1965 } 1965 }
1966 1966
1967 /* ->sk_data_ready is also called for a newly established child socket 1967 /* This callback may called twice when a new connection
1968 * before it has been accepted and the acceptor has set up their 1968 * is being established as a child socket inherits everything
1969 * data_ready.. we only want to queue listen work for our listening 1969 * from a parent LISTEN socket, including the data_ready cb of
1970 * socket */ 1970 * the parent. This leads to a hazard. In o2net_accept_one()
1971 * we are still initializing the child socket but have not
1972 * changed the inherited data_ready callback yet when
1973 * data starts arriving.
1974 * We avoid this hazard by checking the state.
1975 * For the listening socket, the state will be TCP_LISTEN; for the new
1976 * socket, will be TCP_ESTABLISHED. Also, in this case,
1977 * sk->sk_user_data is not a valid function pointer.
1978 */
1979
1971 if (sk->sk_state == TCP_LISTEN) { 1980 if (sk->sk_state == TCP_LISTEN) {
1972 mlog(ML_TCP, "bytes: %d\n", bytes); 1981 mlog(ML_TCP, "bytes: %d\n", bytes);
1973 queue_work(o2net_wq, &o2net_listen_work); 1982 queue_work(o2net_wq, &o2net_listen_work);
1983 } else {
1984 ready = NULL;
1974 } 1985 }
1975 1986
1976out: 1987out:
1977 read_unlock(&sk->sk_callback_lock); 1988 read_unlock(&sk->sk_callback_lock);
1978 ready(sk, bytes); 1989 if (ready != NULL)
1990 ready(sk, bytes);
1979} 1991}
1980 1992
1981static int o2net_open_listening_sock(__be32 addr, __be16 port) 1993static int o2net_open_listening_sock(__be32 addr, __be16 port)