| From df132eff463873e14e019a07f387b4d577d6d1f9 Mon Sep 17 00:00:00 2001 |
| From: Xin Long <lucien.xin@gmail.com> |
| Date: Mon, 29 Oct 2018 23:10:29 +0800 |
| Subject: sctp: clear the transport of some out_chunk_list chunks in sctp_assoc_rm_peer |
| |
| From: Xin Long <lucien.xin@gmail.com> |
| |
| commit df132eff463873e14e019a07f387b4d577d6d1f9 upstream. |
| |
| If a transport is removed by asconf but there still are some chunks with |
| this transport queuing on out_chunk_list, later an use-after-free issue |
| will be caused when accessing this transport from these chunks in |
| sctp_outq_flush(). |
| |
| This is an old bug, we fix it by clearing the transport of these chunks |
| in out_chunk_list when removing a transport in sctp_assoc_rm_peer(). |
| |
| Reported-by: syzbot+56a40ceee5fb35932f4d@syzkaller.appspotmail.com |
| Signed-off-by: Xin Long <lucien.xin@gmail.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| net/sctp/associola.c | 10 +++++++--- |
| 1 file changed, 7 insertions(+), 3 deletions(-) |
| |
| --- a/net/sctp/associola.c |
| +++ b/net/sctp/associola.c |
| @@ -486,8 +486,9 @@ void sctp_assoc_set_primary(struct sctp_ |
| void sctp_assoc_rm_peer(struct sctp_association *asoc, |
| struct sctp_transport *peer) |
| { |
| - struct list_head *pos; |
| - struct sctp_transport *transport; |
| + struct sctp_transport *transport; |
| + struct list_head *pos; |
| + struct sctp_chunk *ch; |
| |
| pr_debug("%s: association:%p addr:%pISpc\n", |
| __func__, asoc, &peer->ipaddr.sa); |
| @@ -543,7 +544,6 @@ void sctp_assoc_rm_peer(struct sctp_asso |
| */ |
| if (!list_empty(&peer->transmitted)) { |
| struct sctp_transport *active = asoc->peer.active_path; |
| - struct sctp_chunk *ch; |
| |
| /* Reset the transport of each chunk on this list */ |
| list_for_each_entry(ch, &peer->transmitted, |
| @@ -565,6 +565,10 @@ void sctp_assoc_rm_peer(struct sctp_asso |
| sctp_transport_hold(active); |
| } |
| |
| + list_for_each_entry(ch, &asoc->outqueue.out_chunk_list, list) |
| + if (ch->transport == peer) |
| + ch->transport = NULL; |
| + |
| asoc->peer.transport_count--; |
| |
| sctp_transport_free(peer); |