From: Eugene Teo <eteo@redhat.com> Date: Thu, 9 Oct 2008 14:08:27 +0800 Subject: [net] sctp: INIT-ACK indicates no AUTH peer support oops Message-id: 48ED9FDB.7010903@redhat.com O-Subject: [RHEL5.3 patch] BZ#466082 kernel: sctp: Fix oops when INIT-ACK indicates that peer doesn't support AUTH Bugzilla: 466082 RH-Acked-by: Jiri Pirko <jpirko@redhat.com> RH-Acked-by: Neil Horman <nhorman@redhat.com> RH-Acked-by: Arnaldo Carvalho de Melo <acme@redhat.com> RH-Acked-by: David Miller <davem@redhat.com> CVE: CVE-2008-4576 This is for bz#466082. I'm still waiting for a CVE name to be assigned. 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. Backport of upstream commit: add52379dde2e5300e2d574b172e62c6cf43b3d3 Signed-off-by: Eugene Teo <eteo@redhat.com> diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 27329ce..a15f868 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -546,11 +546,12 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc, /* Check to see if this is a duplicate. */ peer = sctp_assoc_lookup_paddr(asoc, addr); 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_ACTIVE) - peer->state = SCTP_ACTIVE; - if (peer_state == SCTP_UNCONFIRMED) - peer->state = SCTP_UNCONFIRMED; + peer->state = SCTP_ACTIVE; } return peer; } diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 17b5092..289a4fc 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -1956,12 +1956,10 @@ clean_up: /* Release the transport structures. */ list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) { transport = list_entry(pos, struct sctp_transport, transports); - list_del_init(pos); - sctp_transport_free(transport); + if (transport->state != SCTP_ACTIVE) + sctp_assoc_rm_peer(asoc, transport); } - asoc->peer.transport_count = 0; - nomem: return 0; }