Commit add52379 authored by Vlad Yasevich's avatar Vlad Yasevich Committed by David S. Miller

sctp: Fix oops when INIT-ACK indicates that peer doesn't support AUTH

If INIT-ACK is received with SupportedExtensions parameter which
indicates that the peer does not support AUTH, the packet will be
silently ignore, and sctp_process_init() do cleanup all of the
transports in the association.
When T1-Init timer is expires, OOPS happen while we try to choose
a different init transport.

The solution is to only clean up the non-active transports, i.e
the ones that the peer added.  However, that introduces a problem
with sctp_connectx(), because we don't mark the proper state for
the transports provided by the user.  So, we'll simply mark
user-provided transports as ACTIVE.  That will allow INIT
retransmissions to work properly in the sctp_connectx() context
and prevent the crash.
Signed-off-by: default avatarVlad Yasevich <vladislav.yasevich@hp.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 0ef46e28
...@@ -599,11 +599,12 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc, ...@@ -599,11 +599,12 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
/* Check to see if this is a duplicate. */ /* Check to see if this is a duplicate. */
peer = sctp_assoc_lookup_paddr(asoc, addr); peer = sctp_assoc_lookup_paddr(asoc, addr);
if (peer) { if (peer) {
/* An UNKNOWN state is only set on transports added by
* user in sctp_connectx() call. Such transports should be
* considered CONFIRMED per RFC 4960, Section 5.4.
*/
if (peer->state == SCTP_UNKNOWN) { if (peer->state == SCTP_UNKNOWN) {
if (peer_state == SCTP_ACTIVE) peer->state = SCTP_ACTIVE;
peer->state = SCTP_ACTIVE;
if (peer_state == SCTP_UNCONFIRMED)
peer->state = SCTP_UNCONFIRMED;
} }
return peer; return peer;
} }
......
...@@ -2321,12 +2321,10 @@ int sctp_process_init(struct sctp_association *asoc, sctp_cid_t cid, ...@@ -2321,12 +2321,10 @@ int sctp_process_init(struct sctp_association *asoc, sctp_cid_t cid,
/* Release the transport structures. */ /* Release the transport structures. */
list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) { list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) {
transport = list_entry(pos, struct sctp_transport, transports); transport = list_entry(pos, struct sctp_transport, transports);
list_del_init(pos); if (transport->state != SCTP_ACTIVE)
sctp_transport_free(transport); sctp_assoc_rm_peer(asoc, transport);
} }
asoc->peer.transport_count = 0;
nomem: nomem:
return 0; return 0;
} }
......
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