summaryrefslogtreecommitdiffstats
path: root/net/sctp
diff options
context:
space:
mode:
authorXin Long <lucien.xin@gmail.com>2018-10-29 23:10:29 +0800
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2018-12-01 09:46:33 +0100
commit8b97e045bd6d37f96f161e4d371ae174148e1587 (patch)
tree2517a6a384db801e7a203b72ceefabd15dee2d71 /net/sctp
parent9891fda685f1a9da69012bb39aad81b67870cf5e (diff)
downloadlinux-stable-8b97e045bd6d37f96f161e4d371ae174148e1587.tar.gz
linux-stable-8b97e045bd6d37f96f161e4d371ae174148e1587.tar.bz2
linux-stable-8b97e045bd6d37f96f161e4d371ae174148e1587.zip
sctp: clear the transport of some out_chunk_list chunks in sctp_assoc_rm_peer
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>
Diffstat (limited to 'net/sctp')
-rw-r--r--net/sctp/associola.c10
1 files changed, 7 insertions, 3 deletions
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index a40b8b0ef0d5..f085b01b6603 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -486,8 +486,9 @@ void sctp_assoc_set_primary(struct sctp_association *asoc,
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_association *asoc,
*/
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_association *asoc,
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);