Commit df132eff authored by Xin Long's avatar Xin Long Committed by David S. Miller

sctp: clear the transport of some out_chunk_list chunks in sctp_assoc_rm_peer

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: default avatarXin Long <lucien.xin@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 2b0ab727
...@@ -499,8 +499,9 @@ void sctp_assoc_set_primary(struct sctp_association *asoc, ...@@ -499,8 +499,9 @@ void sctp_assoc_set_primary(struct sctp_association *asoc,
void sctp_assoc_rm_peer(struct sctp_association *asoc, void sctp_assoc_rm_peer(struct sctp_association *asoc,
struct sctp_transport *peer) 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", pr_debug("%s: association:%p addr:%pISpc\n",
__func__, asoc, &peer->ipaddr.sa); __func__, asoc, &peer->ipaddr.sa);
...@@ -564,7 +565,6 @@ void sctp_assoc_rm_peer(struct sctp_association *asoc, ...@@ -564,7 +565,6 @@ void sctp_assoc_rm_peer(struct sctp_association *asoc,
*/ */
if (!list_empty(&peer->transmitted)) { if (!list_empty(&peer->transmitted)) {
struct sctp_transport *active = asoc->peer.active_path; struct sctp_transport *active = asoc->peer.active_path;
struct sctp_chunk *ch;
/* Reset the transport of each chunk on this list */ /* Reset the transport of each chunk on this list */
list_for_each_entry(ch, &peer->transmitted, list_for_each_entry(ch, &peer->transmitted,
...@@ -586,6 +586,10 @@ void sctp_assoc_rm_peer(struct sctp_association *asoc, ...@@ -586,6 +586,10 @@ void sctp_assoc_rm_peer(struct sctp_association *asoc,
sctp_transport_hold(active); 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--; asoc->peer.transport_count--;
sctp_transport_free(peer); sctp_transport_free(peer);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment