Skip to content

Commit d89ecd1

Browse files
committed
Merge branch 'sctp-race-fix'
Xin Long says: ==================== sctp: fix the race condition in sctp_destroy_sock in a proper way The original fix introduced a dead lock, and has to be removed in Patch 1/2, and we will get a proper way to fix it in Patch 2/2. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 2e9f609 + 34e5b01 commit d89ecd1

File tree

1 file changed

+22
-16
lines changed

1 file changed

+22
-16
lines changed

net/sctp/socket.c

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,18 @@ static struct sctp_af *sctp_sockaddr_af(struct sctp_sock *opt,
357357
return af;
358358
}
359359

360+
static void sctp_auto_asconf_init(struct sctp_sock *sp)
361+
{
362+
struct net *net = sock_net(&sp->inet.sk);
363+
364+
if (net->sctp.default_auto_asconf) {
365+
spin_lock(&net->sctp.addr_wq_lock);
366+
list_add_tail(&sp->auto_asconf_list, &net->sctp.auto_asconf_splist);
367+
spin_unlock(&net->sctp.addr_wq_lock);
368+
sp->do_auto_asconf = 1;
369+
}
370+
}
371+
360372
/* Bind a local address either to an endpoint or to an association. */
361373
static int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len)
362374
{
@@ -418,8 +430,10 @@ static int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len)
418430
return -EADDRINUSE;
419431

420432
/* Refresh ephemeral port. */
421-
if (!bp->port)
433+
if (!bp->port) {
422434
bp->port = inet_sk(sk)->inet_num;
435+
sctp_auto_asconf_init(sp);
436+
}
423437

424438
/* Add the address to the bind address list.
425439
* Use GFP_ATOMIC since BHs will be disabled.
@@ -1520,9 +1534,11 @@ static void sctp_close(struct sock *sk, long timeout)
15201534

15211535
/* Supposedly, no process has access to the socket, but
15221536
* the net layers still may.
1537+
* Also, sctp_destroy_sock() needs to be called with addr_wq_lock
1538+
* held and that should be grabbed before socket lock.
15231539
*/
1524-
local_bh_disable();
1525-
bh_lock_sock(sk);
1540+
spin_lock_bh(&net->sctp.addr_wq_lock);
1541+
bh_lock_sock_nested(sk);
15261542

15271543
/* Hold the sock, since sk_common_release() will put sock_put()
15281544
* and we have just a little more cleanup.
@@ -1531,7 +1547,7 @@ static void sctp_close(struct sock *sk, long timeout)
15311547
sk_common_release(sk);
15321548

15331549
bh_unlock_sock(sk);
1534-
local_bh_enable();
1550+
spin_unlock_bh(&net->sctp.addr_wq_lock);
15351551

15361552
sock_put(sk);
15371553

@@ -4991,16 +5007,6 @@ static int sctp_init_sock(struct sock *sk)
49915007
sk_sockets_allocated_inc(sk);
49925008
sock_prot_inuse_add(net, sk->sk_prot, 1);
49935009

4994-
if (net->sctp.default_auto_asconf) {
4995-
spin_lock(&sock_net(sk)->sctp.addr_wq_lock);
4996-
list_add_tail(&sp->auto_asconf_list,
4997-
&net->sctp.auto_asconf_splist);
4998-
sp->do_auto_asconf = 1;
4999-
spin_unlock(&sock_net(sk)->sctp.addr_wq_lock);
5000-
} else {
5001-
sp->do_auto_asconf = 0;
5002-
}
5003-
50045010
local_bh_enable();
50055011

50065012
return 0;
@@ -5025,9 +5031,7 @@ static void sctp_destroy_sock(struct sock *sk)
50255031

50265032
if (sp->do_auto_asconf) {
50275033
sp->do_auto_asconf = 0;
5028-
spin_lock_bh(&sock_net(sk)->sctp.addr_wq_lock);
50295034
list_del(&sp->auto_asconf_list);
5030-
spin_unlock_bh(&sock_net(sk)->sctp.addr_wq_lock);
50315035
}
50325036
sctp_endpoint_free(sp->ep);
50335037
local_bh_disable();
@@ -9398,6 +9402,8 @@ static int sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
93989402
return err;
93999403
}
94009404

9405+
sctp_auto_asconf_init(newsp);
9406+
94019407
/* Move any messages in the old socket's receive queue that are for the
94029408
* peeled off association to the new socket's receive queue.
94039409
*/

0 commit comments

Comments
 (0)