summaryrefslogtreecommitdiffstats
path: root/net/sctp
diff options
context:
space:
mode:
authorXin Long <lucien.xin@gmail.com>2017-11-15 03:55:54 -0500
committerDavid S. Miller <davem@davemloft.net>2017-11-15 20:49:00 -0500
commitca3af4dd28cff4e7216e213ba3b671fbf9f84758 (patch)
treec01bae2ee9419254a2eb0a8d08a558d40758c873 /net/sctp
parent6363b3f3ac5be096d08c8c504128befa0c033529 (diff)
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 <nhorman@tuxdriver.com> Reported-by: Dmitry Vyukov <dvyukov@google.com> Signed-off-by: Xin Long <lucien.xin@gmail.com> Acked-by: Neil Horman <nhorman@tuxdriver.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sctp')
-rw-r--r--net/sctp/socket.c17
1 files changed, 14 insertions, 3 deletions
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index b029757bea03..fec8de73a06f 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -1971,8 +1971,14 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len)
1971 timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT); 1971 timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT);
1972 if (!sctp_wspace(asoc)) { 1972 if (!sctp_wspace(asoc)) {
1973 err = sctp_wait_for_sndbuf(asoc, &timeo, msg_len); 1973 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 }
1975 goto out_free; 1980 goto out_free;
1981 }
1976 } 1982 }
1977 1983
1978 /* If an address is passed with the sendto/sendmsg call, it is used 1984 /* 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,
8006 for (;;) { 8012 for (;;) {
8007 prepare_to_wait_exclusive(&asoc->wait, &wait, 8013 prepare_to_wait_exclusive(&asoc->wait, &wait,
8008 TASK_INTERRUPTIBLE); 8014 TASK_INTERRUPTIBLE);
8015 if (asoc->base.dead)
8016 goto do_dead;
8009 if (!*timeo_p) 8017 if (!*timeo_p)
8010 goto do_nonblock; 8018 goto do_nonblock;
8011 if (sk->sk_err || asoc->state >= SCTP_STATE_SHUTDOWN_PENDING || 8019 if (sk->sk_err || asoc->state >= SCTP_STATE_SHUTDOWN_PENDING)
8012 asoc->base.dead)
8013 goto do_error; 8020 goto do_error;
8014 if (signal_pending(current)) 8021 if (signal_pending(current))
8015 goto do_interrupted; 8022 goto do_interrupted;
@@ -8034,6 +8041,10 @@ out:
8034 8041
8035 return err; 8042 return err;
8036 8043
8044do_dead:
8045 err = -ESRCH;
8046 goto out;
8047
8037do_error: 8048do_error:
8038 err = -EPIPE; 8049 err = -EPIPE;
8039 goto out; 8050 goto out;