Received: by 2002:ac0:a594:0:0:0:0:0 with SMTP id m20-v6csp2070501imm; Thu, 24 May 2018 05:22:57 -0700 (PDT) X-Google-Smtp-Source: AB8JxZpwPg9dGHGqniQH+l3uvV9ENLcOQZ3P6oZQ6iLK41ekz7pV4zF2IDvv0CrfqcwvStefcnS7 X-Received: by 2002:a17:902:f83:: with SMTP id 3-v6mr7153677plz.336.1527164577729; Thu, 24 May 2018 05:22:57 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1527164577; cv=none; d=google.com; s=arc-20160816; b=aMZK9T127GsEGQJvPY38WwNQgnfx1drIqtQxrXLeDkhAB8V1sRiKTF1Q6qIJhyjkCI SILGax26Wb7IU+lAf0RXEX7NFIjaGScGDgdzduXDptQ43fbGENRZPrCuPVxV8K/hdBZU EDzoAm5OuZiMV8v7CNPC8Zipex2LHP3dplIrmoSnwbUsL4lwsCGMVEpyEBpSVu5E2Hid tViS6w3D6iXraS4KvHoZU37hXhTqfk7j4cYAuOjvZ4OErZTJeLBEYmt09hVShZtMmicl kDuwEgP+fNHCNe+uD/qtLR+GQA6TSe46HG3GOgutAADr39li2e3pEUGm8NQJLIWCkvTY 3Nyw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:mime-version:user-agent:references :in-reply-to:message-id:date:subject:cc:to:from:dkim-signature :arc-authentication-results; bh=yAcRBSoEVP5G5ZyqlfcmHt/LJQYS0vHugHX6gfjyhsY=; b=KY2vRc6BJYQ/jzFEJx+Zw5f5fyGeMo7nvSM36vjXNapYbGkptHWD2LawpIXfvDlvWU 7m9PEgJuXbVfoHzqxavIFDZfhbJAfX4h9Be4DJHiGDjAcyFMKEbUdn9QdqMveV8xWDgc Y0Gk9Ku3k3A92p19iveZI9iTmyMs8TNCnX+Y/m9G1IT6JcA56tN+URrzUe4vINdvOGrH D4L/NDuzdr0Srp3XfIpTwIlOtCJaRtH05BohvZwFmdOxN0uUyhhi3DSjHV3tMHq0/BBw 37TGDPfgC9h42e08Ej3RZOWWyGKxULQpfLnI/RKAESI0tmrlk4uZOKhIbnwMQbNMJ+7o qnHw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=fB9EYrMd; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id f5-v6si16588603pgc.37.2018.05.24.05.22.43; Thu, 24 May 2018 05:22:57 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=fB9EYrMd; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S970057AbeEXMWC (ORCPT + 99 others); Thu, 24 May 2018 08:22:02 -0400 Received: from mail.kernel.org ([198.145.29.99]:53060 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S966143AbeEXJlG (ORCPT ); Thu, 24 May 2018 05:41:06 -0400 Received: from localhost (LFbn-1-12247-202.w90-92.abo.wanadoo.fr [90.92.61.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 3FF5720891; Thu, 24 May 2018 09:41:05 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1527154865; bh=VmcTLObmwHeislSnqUMp+8qACPdd1R0JofcGs0/IShI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=fB9EYrMdB/5zGaBKjCtf7B3Tn74XHCbziXPmsxy3OcNDkzovIebC+Wqqht8javcXx Ft4A5+jw3G/q5sr/KofSxKObncf1KPnjUUq/D8IVbh5V68AMHYFCPEjQ4qDdNw4u57 47omUvndJDFKIgrtm9Jfgh+ZUX0n4/1n++PgsgfU= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Marcelo Ricardo Leitner , Xin Long , Neil Horman , "David S. Miller" Subject: [PATCH 3.18 16/45] sctp: delay the authentication for the duplicated cookie-echo chunk Date: Thu, 24 May 2018 11:38:24 +0200 Message-Id: <20180524093122.489558564@linuxfoundation.org> X-Mailer: git-send-email 2.17.0 In-Reply-To: <20180524093120.599252450@linuxfoundation.org> References: <20180524093120.599252450@linuxfoundation.org> User-Agent: quilt/0.65 X-stable: review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 3.18-stable review patch. If anyone has any objections, please let me know. ------------------ From: Xin Long [ Upstream commit 59d8d4434f429b4fa8a346fd889058bda427a837 ] Now sctp only delays the authentication for the normal cookie-echo chunk by setting chunk->auth_chunk in sctp_endpoint_bh_rcv(). But for the duplicated one with auth, in sctp_assoc_bh_rcv(), it does authentication first based on the old asoc, which will definitely fail due to the different auth info in the old asoc. The duplicated cookie-echo chunk will create a new asoc with the auth info from this chunk, and the authentication should also be done with the new asoc's auth info for all of the collision 'A', 'B' and 'D'. Otherwise, the duplicated cookie-echo chunk with auth will never pass the authentication and create the new connection. This issue exists since very beginning, and this fix is to make sctp_assoc_bh_rcv() follow the way sctp_endpoint_bh_rcv() does for the normal cookie-echo chunk to delay the authentication. While at it, remove the unused params from sctp_sf_authenticate() and define sctp_auth_chunk_verify() used for all the places that do the delayed authentication. v1->v2: fix the typo in changelog as Marcelo noticed. Acked-by: Marcelo Ricardo Leitner Signed-off-by: Xin Long Acked-by: Neil Horman Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sctp/associola.c | 30 ++++++++++++++++ net/sctp/sm_statefuns.c | 87 ++++++++++++++++++++++++++---------------------- 2 files changed, 77 insertions(+), 40 deletions(-) --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -1001,9 +1001,10 @@ static void sctp_assoc_bh_rcv(struct wor struct sctp_endpoint *ep; struct sctp_chunk *chunk; struct sctp_inq *inqueue; - int state; sctp_subtype_t subtype; + int first_time = 1; /* is this the first time through the loop */ int error = 0; + int state; /* The association should be held so we should be safe. */ ep = asoc->ep; @@ -1014,6 +1015,30 @@ static void sctp_assoc_bh_rcv(struct wor state = asoc->state; subtype = SCTP_ST_CHUNK(chunk->chunk_hdr->type); + /* If the first chunk in the packet is AUTH, do special + * processing specified in Section 6.3 of SCTP-AUTH spec + */ + if (first_time && subtype.chunk == SCTP_CID_AUTH) { + struct sctp_chunkhdr *next_hdr; + + next_hdr = sctp_inq_peek(inqueue); + if (!next_hdr) + goto normal; + + /* If the next chunk is COOKIE-ECHO, skip the AUTH + * chunk while saving a pointer to it so we can do + * Authentication later (during cookie-echo + * processing). + */ + if (next_hdr->type == SCTP_CID_COOKIE_ECHO) { + chunk->auth_chunk = skb_clone(chunk->skb, + GFP_ATOMIC); + chunk->auth = 1; + continue; + } + } + +normal: /* SCTP-AUTH, Section 6.3: * The receiver has a list of chunk types which it expects * to be received only after an AUTH-chunk. This list has @@ -1052,6 +1077,9 @@ static void sctp_assoc_bh_rcv(struct wor /* If there is an error on chunk, discard this packet. */ if (error && chunk) chunk->pdiscard = 1; + + if (first_time) + first_time = 0; } sctp_association_put(asoc); } --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -144,10 +144,8 @@ static sctp_disposition_t sctp_sf_violat void *arg, sctp_cmd_seq_t *commands); -static sctp_ierror_t sctp_sf_authenticate(struct net *net, - const struct sctp_endpoint *ep, +static sctp_ierror_t sctp_sf_authenticate( const struct sctp_association *asoc, - const sctp_subtype_t type, struct sctp_chunk *chunk); static sctp_disposition_t __sctp_sf_do_9_1_abort(struct net *net, @@ -615,6 +613,38 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(s return SCTP_DISPOSITION_CONSUME; } +static bool sctp_auth_chunk_verify(struct net *net, struct sctp_chunk *chunk, + const struct sctp_association *asoc) +{ + struct sctp_chunk auth; + + if (!chunk->auth_chunk) + return true; + + /* SCTP-AUTH: auth_chunk pointer is only set when the cookie-echo + * is supposed to be authenticated and we have to do delayed + * authentication. We've just recreated the association using + * the information in the cookie and now it's much easier to + * do the authentication. + */ + + /* Make sure that we and the peer are AUTH capable */ + if (!net->sctp.auth_enable || !asoc->peer.auth_capable) + return false; + + /* set-up our fake chunk so that we can process it */ + auth.skb = chunk->auth_chunk; + auth.asoc = chunk->asoc; + auth.sctp_hdr = chunk->sctp_hdr; + auth.chunk_hdr = (struct sctp_chunkhdr *) + skb_push(chunk->auth_chunk, + sizeof(struct sctp_chunkhdr)); + skb_pull(chunk->auth_chunk, sizeof(struct sctp_chunkhdr)); + auth.transport = chunk->transport; + + return sctp_sf_authenticate(asoc, &auth) == SCTP_IERROR_NO_ERROR; +} + /* * Respond to a normal COOKIE ECHO chunk. * We are the side that is being asked for an association. @@ -751,36 +781,9 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(st if (error) goto nomem_init; - /* SCTP-AUTH: auth_chunk pointer is only set when the cookie-echo - * is supposed to be authenticated and we have to do delayed - * authentication. We've just recreated the association using - * the information in the cookie and now it's much easier to - * do the authentication. - */ - if (chunk->auth_chunk) { - struct sctp_chunk auth; - sctp_ierror_t ret; - - /* Make sure that we and the peer are AUTH capable */ - if (!net->sctp.auth_enable || !new_asoc->peer.auth_capable) { - sctp_association_free(new_asoc); - return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); - } - - /* set-up our fake chunk so that we can process it */ - auth.skb = chunk->auth_chunk; - auth.asoc = chunk->asoc; - auth.sctp_hdr = chunk->sctp_hdr; - auth.chunk_hdr = (sctp_chunkhdr_t *)skb_push(chunk->auth_chunk, - sizeof(sctp_chunkhdr_t)); - skb_pull(chunk->auth_chunk, sizeof(sctp_chunkhdr_t)); - auth.transport = chunk->transport; - - ret = sctp_sf_authenticate(net, ep, new_asoc, type, &auth); - if (ret != SCTP_IERROR_NO_ERROR) { - sctp_association_free(new_asoc); - return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); - } + if (!sctp_auth_chunk_verify(net, chunk, new_asoc)) { + sctp_association_free(new_asoc); + return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); } repl = sctp_make_cookie_ack(new_asoc, chunk); @@ -1717,13 +1720,15 @@ static sctp_disposition_t sctp_sf_do_dup GFP_ATOMIC)) goto nomem; + if (!sctp_auth_chunk_verify(net, chunk, new_asoc)) + return SCTP_DISPOSITION_DISCARD; + /* Make sure no new addresses are being added during the * restart. Though this is a pretty complicated attack * since you'd have to get inside the cookie. */ - if (!sctp_sf_check_restart_addrs(new_asoc, asoc, chunk, commands)) { + if (!sctp_sf_check_restart_addrs(new_asoc, asoc, chunk, commands)) return SCTP_DISPOSITION_CONSUME; - } /* If the endpoint is in the SHUTDOWN-ACK-SENT state and recognizes * the peer has restarted (Action A), it MUST NOT setup a new @@ -1828,6 +1833,9 @@ static sctp_disposition_t sctp_sf_do_dup GFP_ATOMIC)) goto nomem; + if (!sctp_auth_chunk_verify(net, chunk, new_asoc)) + return SCTP_DISPOSITION_DISCARD; + /* Update the content of current association. */ sctp_add_cmd_sf(commands, SCTP_CMD_UPDATE_ASSOC, SCTP_ASOC(new_asoc)); sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, @@ -1920,6 +1928,9 @@ static sctp_disposition_t sctp_sf_do_dup * a COOKIE ACK. */ + if (!sctp_auth_chunk_verify(net, chunk, asoc)) + return SCTP_DISPOSITION_DISCARD; + /* Don't accidentally move back into established state. */ if (asoc->state < SCTP_STATE_ESTABLISHED) { sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, @@ -3985,10 +3996,8 @@ gen_shutdown: * * The return value is the disposition of the chunk. */ -static sctp_ierror_t sctp_sf_authenticate(struct net *net, - const struct sctp_endpoint *ep, +static sctp_ierror_t sctp_sf_authenticate( const struct sctp_association *asoc, - const sctp_subtype_t type, struct sctp_chunk *chunk) { struct sctp_authhdr *auth_hdr; @@ -4087,7 +4096,7 @@ sctp_disposition_t sctp_sf_eat_auth(stru commands); auth_hdr = (struct sctp_authhdr *)chunk->skb->data; - error = sctp_sf_authenticate(net, ep, asoc, type, chunk); + error = sctp_sf_authenticate(asoc, chunk); switch (error) { case SCTP_IERROR_AUTH_BAD_HMAC: /* Generate the ERROR chunk and discard the rest