diff options
author | Tariq Saeed <tariq.x.saeed@oracle.com> | 2014-04-03 17:47:11 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-04-03 19:20:56 -0400 |
commit | da8ded405de74de4b189d1128f4c102d06328c29 (patch) | |
tree | f89ec00e4c725703aeba00e741f9e5203b9b7594 /fs | |
parent | db66c71577d525c0cd65e66ff675747565783ba4 (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.c | 22 |
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 | ||
1976 | out: | 1987 | out: |
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 | ||
1981 | static int o2net_open_listening_sock(__be32 addr, __be16 port) | 1993 | static int o2net_open_listening_sock(__be32 addr, __be16 port) |