Skip to content

Commit ca3af4d

Browse files
lxindavem330
authored andcommitted
sctp: do not free asoc when it is already dead in sctp_sendmsg
Now in sctp_sendmsg sctp_wait_for_sndbuf could schedule out without holding sock sk. It means the current asoc can be freed elsewhere, like when receiving an abort packet. If the asoc is just created in sctp_sendmsg and sctp_wait_for_sndbuf returns err, the asoc will be freed again due to new_asoc is not nil. An use-after-free issue would be triggered by this. This patch is to fix it by setting new_asoc with nil if the asoc is already dead when cpu schedules back, so that it will not be freed again in sctp_sendmsg. v1->v2: set new_asoc as nil in sctp_sendmsg instead of sctp_wait_for_sndbuf. Suggested-by: Neil Horman <[email protected]> Reported-by: Dmitry Vyukov <[email protected]> Signed-off-by: Xin Long <[email protected]> Acked-by: Neil Horman <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 6363b3f commit ca3af4d

File tree

1 file changed

+14
-3
lines changed

1 file changed

+14
-3
lines changed

net/sctp/socket.c

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1971,8 +1971,14 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len)
19711971
timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT);
19721972
if (!sctp_wspace(asoc)) {
19731973
err = sctp_wait_for_sndbuf(asoc, &timeo, msg_len);
1974-
if (err)
1974+
if (err) {
1975+
if (err == -ESRCH) {
1976+
/* asoc is already dead. */
1977+
new_asoc = NULL;
1978+
err = -EPIPE;
1979+
}
19751980
goto out_free;
1981+
}
19761982
}
19771983

19781984
/* If an address is passed with the sendto/sendmsg call, it is used
@@ -8006,10 +8012,11 @@ static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p,
80068012
for (;;) {
80078013
prepare_to_wait_exclusive(&asoc->wait, &wait,
80088014
TASK_INTERRUPTIBLE);
8015+
if (asoc->base.dead)
8016+
goto do_dead;
80098017
if (!*timeo_p)
80108018
goto do_nonblock;
8011-
if (sk->sk_err || asoc->state >= SCTP_STATE_SHUTDOWN_PENDING ||
8012-
asoc->base.dead)
8019+
if (sk->sk_err || asoc->state >= SCTP_STATE_SHUTDOWN_PENDING)
80138020
goto do_error;
80148021
if (signal_pending(current))
80158022
goto do_interrupted;
@@ -8034,6 +8041,10 @@ static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p,
80348041

80358042
return err;
80368043

8044+
do_dead:
8045+
err = -ESRCH;
8046+
goto out;
8047+
80378048
do_error:
80388049
err = -EPIPE;
80398050
goto out;

0 commit comments

Comments
 (0)