Skip to content

Commit 59d8d44

Browse files
lxindavem330
authored andcommitted
sctp: delay the authentication for the duplicated cookie-echo chunk
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 <[email protected]> Signed-off-by: Xin Long <[email protected]> Acked-by: Neil Horman <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent a86b74d commit 59d8d44

File tree

2 files changed

+75
-41
lines changed

2 files changed

+75
-41
lines changed

net/sctp/associola.c

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1024,8 +1024,9 @@ static void sctp_assoc_bh_rcv(struct work_struct *work)
10241024
struct sctp_endpoint *ep;
10251025
struct sctp_chunk *chunk;
10261026
struct sctp_inq *inqueue;
1027-
int state;
1027+
int first_time = 1; /* is this the first time through the loop */
10281028
int error = 0;
1029+
int state;
10291030

10301031
/* The association should be held so we should be safe. */
10311032
ep = asoc->ep;
@@ -1036,6 +1037,30 @@ static void sctp_assoc_bh_rcv(struct work_struct *work)
10361037
state = asoc->state;
10371038
subtype = SCTP_ST_CHUNK(chunk->chunk_hdr->type);
10381039

1040+
/* If the first chunk in the packet is AUTH, do special
1041+
* processing specified in Section 6.3 of SCTP-AUTH spec
1042+
*/
1043+
if (first_time && subtype.chunk == SCTP_CID_AUTH) {
1044+
struct sctp_chunkhdr *next_hdr;
1045+
1046+
next_hdr = sctp_inq_peek(inqueue);
1047+
if (!next_hdr)
1048+
goto normal;
1049+
1050+
/* If the next chunk is COOKIE-ECHO, skip the AUTH
1051+
* chunk while saving a pointer to it so we can do
1052+
* Authentication later (during cookie-echo
1053+
* processing).
1054+
*/
1055+
if (next_hdr->type == SCTP_CID_COOKIE_ECHO) {
1056+
chunk->auth_chunk = skb_clone(chunk->skb,
1057+
GFP_ATOMIC);
1058+
chunk->auth = 1;
1059+
continue;
1060+
}
1061+
}
1062+
1063+
normal:
10391064
/* SCTP-AUTH, Section 6.3:
10401065
* The receiver has a list of chunk types which it expects
10411066
* to be received only after an AUTH-chunk. This list has
@@ -1074,6 +1099,9 @@ static void sctp_assoc_bh_rcv(struct work_struct *work)
10741099
/* If there is an error on chunk, discard this packet. */
10751100
if (error && chunk)
10761101
chunk->pdiscard = 1;
1102+
1103+
if (first_time)
1104+
first_time = 0;
10771105
}
10781106
sctp_association_put(asoc);
10791107
}

net/sctp/sm_statefuns.c

Lines changed: 46 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -153,10 +153,7 @@ static enum sctp_disposition sctp_sf_violation_chunk(
153153
struct sctp_cmd_seq *commands);
154154

155155
static enum sctp_ierror sctp_sf_authenticate(
156-
struct net *net,
157-
const struct sctp_endpoint *ep,
158156
const struct sctp_association *asoc,
159-
const union sctp_subtype type,
160157
struct sctp_chunk *chunk);
161158

162159
static enum sctp_disposition __sctp_sf_do_9_1_abort(
@@ -626,6 +623,38 @@ enum sctp_disposition sctp_sf_do_5_1C_ack(struct net *net,
626623
return SCTP_DISPOSITION_CONSUME;
627624
}
628625

626+
static bool sctp_auth_chunk_verify(struct net *net, struct sctp_chunk *chunk,
627+
const struct sctp_association *asoc)
628+
{
629+
struct sctp_chunk auth;
630+
631+
if (!chunk->auth_chunk)
632+
return true;
633+
634+
/* SCTP-AUTH: auth_chunk pointer is only set when the cookie-echo
635+
* is supposed to be authenticated and we have to do delayed
636+
* authentication. We've just recreated the association using
637+
* the information in the cookie and now it's much easier to
638+
* do the authentication.
639+
*/
640+
641+
/* Make sure that we and the peer are AUTH capable */
642+
if (!net->sctp.auth_enable || !asoc->peer.auth_capable)
643+
return false;
644+
645+
/* set-up our fake chunk so that we can process it */
646+
auth.skb = chunk->auth_chunk;
647+
auth.asoc = chunk->asoc;
648+
auth.sctp_hdr = chunk->sctp_hdr;
649+
auth.chunk_hdr = (struct sctp_chunkhdr *)
650+
skb_push(chunk->auth_chunk,
651+
sizeof(struct sctp_chunkhdr));
652+
skb_pull(chunk->auth_chunk, sizeof(struct sctp_chunkhdr));
653+
auth.transport = chunk->transport;
654+
655+
return sctp_sf_authenticate(asoc, &auth) == SCTP_IERROR_NO_ERROR;
656+
}
657+
629658
/*
630659
* Respond to a normal COOKIE ECHO chunk.
631660
* We are the side that is being asked for an association.
@@ -763,37 +792,9 @@ enum sctp_disposition sctp_sf_do_5_1D_ce(struct net *net,
763792
if (error)
764793
goto nomem_init;
765794

766-
/* SCTP-AUTH: auth_chunk pointer is only set when the cookie-echo
767-
* is supposed to be authenticated and we have to do delayed
768-
* authentication. We've just recreated the association using
769-
* the information in the cookie and now it's much easier to
770-
* do the authentication.
771-
*/
772-
if (chunk->auth_chunk) {
773-
struct sctp_chunk auth;
774-
enum sctp_ierror ret;
775-
776-
/* Make sure that we and the peer are AUTH capable */
777-
if (!net->sctp.auth_enable || !new_asoc->peer.auth_capable) {
778-
sctp_association_free(new_asoc);
779-
return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
780-
}
781-
782-
/* set-up our fake chunk so that we can process it */
783-
auth.skb = chunk->auth_chunk;
784-
auth.asoc = chunk->asoc;
785-
auth.sctp_hdr = chunk->sctp_hdr;
786-
auth.chunk_hdr = (struct sctp_chunkhdr *)
787-
skb_push(chunk->auth_chunk,
788-
sizeof(struct sctp_chunkhdr));
789-
skb_pull(chunk->auth_chunk, sizeof(struct sctp_chunkhdr));
790-
auth.transport = chunk->transport;
791-
792-
ret = sctp_sf_authenticate(net, ep, new_asoc, type, &auth);
793-
if (ret != SCTP_IERROR_NO_ERROR) {
794-
sctp_association_free(new_asoc);
795-
return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
796-
}
795+
if (!sctp_auth_chunk_verify(net, chunk, new_asoc)) {
796+
sctp_association_free(new_asoc);
797+
return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
797798
}
798799

799800
repl = sctp_make_cookie_ack(new_asoc, chunk);
@@ -1797,13 +1798,15 @@ static enum sctp_disposition sctp_sf_do_dupcook_a(
17971798
if (sctp_auth_asoc_init_active_key(new_asoc, GFP_ATOMIC))
17981799
goto nomem;
17991800

1801+
if (!sctp_auth_chunk_verify(net, chunk, new_asoc))
1802+
return SCTP_DISPOSITION_DISCARD;
1803+
18001804
/* Make sure no new addresses are being added during the
18011805
* restart. Though this is a pretty complicated attack
18021806
* since you'd have to get inside the cookie.
18031807
*/
1804-
if (!sctp_sf_check_restart_addrs(new_asoc, asoc, chunk, commands)) {
1808+
if (!sctp_sf_check_restart_addrs(new_asoc, asoc, chunk, commands))
18051809
return SCTP_DISPOSITION_CONSUME;
1806-
}
18071810

18081811
/* If the endpoint is in the SHUTDOWN-ACK-SENT state and recognizes
18091812
* the peer has restarted (Action A), it MUST NOT setup a new
@@ -1912,6 +1915,9 @@ static enum sctp_disposition sctp_sf_do_dupcook_b(
19121915
if (sctp_auth_asoc_init_active_key(new_asoc, GFP_ATOMIC))
19131916
goto nomem;
19141917

1918+
if (!sctp_auth_chunk_verify(net, chunk, new_asoc))
1919+
return SCTP_DISPOSITION_DISCARD;
1920+
19151921
/* Update the content of current association. */
19161922
sctp_add_cmd_sf(commands, SCTP_CMD_UPDATE_ASSOC, SCTP_ASOC(new_asoc));
19171923
sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
@@ -2009,6 +2015,9 @@ static enum sctp_disposition sctp_sf_do_dupcook_d(
20092015
* a COOKIE ACK.
20102016
*/
20112017

2018+
if (!sctp_auth_chunk_verify(net, chunk, asoc))
2019+
return SCTP_DISPOSITION_DISCARD;
2020+
20122021
/* Don't accidentally move back into established state. */
20132022
if (asoc->state < SCTP_STATE_ESTABLISHED) {
20142023
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
@@ -4171,10 +4180,7 @@ enum sctp_disposition sctp_sf_eat_fwd_tsn_fast(
41714180
* The return value is the disposition of the chunk.
41724181
*/
41734182
static enum sctp_ierror sctp_sf_authenticate(
4174-
struct net *net,
4175-
const struct sctp_endpoint *ep,
41764183
const struct sctp_association *asoc,
4177-
const union sctp_subtype type,
41784184
struct sctp_chunk *chunk)
41794185
{
41804186
struct sctp_shared_key *sh_key = NULL;
@@ -4275,7 +4281,7 @@ enum sctp_disposition sctp_sf_eat_auth(struct net *net,
42754281
commands);
42764282

42774283
auth_hdr = (struct sctp_authhdr *)chunk->skb->data;
4278-
error = sctp_sf_authenticate(net, ep, asoc, type, chunk);
4284+
error = sctp_sf_authenticate(asoc, chunk);
42794285
switch (error) {
42804286
case SCTP_IERROR_AUTH_BAD_HMAC:
42814287
/* Generate the ERROR chunk and discard the rest

0 commit comments

Comments
 (0)