aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorVlad Yasevich <vladislav.yasevich@hp.com>2009-01-22 17:53:23 -0500
committerDavid S. Miller <davem@davemloft.net>2009-01-22 17:53:23 -0500
commitae53b5bd77719fed58086c5be60ce4f22bffe1c6 (patch)
treeb48da8033f59117512a5486a779b0853a255dc7b /net
parent759af00ebef858015eb68876ac1f383bcb6a1774 (diff)
sctp: Fix another socket race during accept/peeloff
There is a race between sctp_rcv() and sctp_accept() where we have moved the association from the listening socket to the accepted socket, but sctp_rcv() processing cached the old socket and continues to use it. The easy solution is to check for the socket mismatch once we've grabed the socket lock. If we hit a mis-match, that means that were are currently holding the lock on the listening socket, but the association is refrencing a newly accepted socket. We need to drop the lock on the old socket and grab the lock on the new one. A more proper solution might be to create accepted sockets when the new association is established, similar to TCP. That would eliminate the race for 1-to-1 style sockets, but it would still existing for 1-to-many sockets where a user wished to peeloff an association. For now, we'll live with this easy solution as it addresses the problem. Reported-by: Michal Hocko <mhocko@suse.cz> Reported-by: Karsten Keil <kkeil@suse.de> Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/sctp/input.c13
1 files changed, 13 insertions, 0 deletions
diff --git a/net/sctp/input.c b/net/sctp/input.c
index bf612d954d41..2e4a8646dbc3 100644
--- a/net/sctp/input.c
+++ b/net/sctp/input.c
@@ -249,6 +249,19 @@ int sctp_rcv(struct sk_buff *skb)
249 */ 249 */
250 sctp_bh_lock_sock(sk); 250 sctp_bh_lock_sock(sk);
251 251
252 if (sk != rcvr->sk) {
253 /* Our cached sk is different from the rcvr->sk. This is
254 * because migrate()/accept() may have moved the association
255 * to a new socket and released all the sockets. So now we
256 * are holding a lock on the old socket while the user may
257 * be doing something with the new socket. Switch our veiw
258 * of the current sk.
259 */
260 sctp_bh_unlock_sock(sk);
261 sk = rcvr->sk;
262 sctp_bh_lock_sock(sk);
263 }
264
252 if (sock_owned_by_user(sk)) { 265 if (sock_owned_by_user(sk)) {
253 SCTP_INC_STATS_BH(SCTP_MIB_IN_PKT_BACKLOG); 266 SCTP_INC_STATS_BH(SCTP_MIB_IN_PKT_BACKLOG);
254 sctp_add_backlog(sk, skb); 267 sctp_add_backlog(sk, skb);