diff options
| -rw-r--r-- | include/net/sctp/constants.h | 4 | ||||
| -rw-r--r-- | include/net/sctp/sm.h | 1 | ||||
| -rw-r--r-- | include/net/sctp/structs.h | 8 | ||||
| -rw-r--r-- | net/sctp/associola.c | 10 | ||||
| -rw-r--r-- | net/sctp/endpointola.c | 29 | ||||
| -rw-r--r-- | net/sctp/input.c | 65 | ||||
| -rw-r--r-- | net/sctp/inqueue.c | 19 | ||||
| -rw-r--r-- | net/sctp/sm_statefuns.c | 218 | ||||
| -rw-r--r-- | net/sctp/sm_statetable.c | 33 |
9 files changed, 374 insertions, 13 deletions
diff --git a/include/net/sctp/constants.h b/include/net/sctp/constants.h index 777118f06dba..da8354e8e33c 100644 --- a/include/net/sctp/constants.h +++ b/include/net/sctp/constants.h | |||
| @@ -183,7 +183,9 @@ typedef enum { | |||
| 183 | SCTP_IERROR_NO_DATA, | 183 | SCTP_IERROR_NO_DATA, |
| 184 | SCTP_IERROR_BAD_STREAM, | 184 | SCTP_IERROR_BAD_STREAM, |
| 185 | SCTP_IERROR_BAD_PORTS, | 185 | SCTP_IERROR_BAD_PORTS, |
| 186 | 186 | SCTP_IERROR_AUTH_BAD_HMAC, | |
| 187 | SCTP_IERROR_AUTH_BAD_KEYID, | ||
| 188 | SCTP_IERROR_PROTO_VIOLATION, | ||
| 187 | } sctp_ierror_t; | 189 | } sctp_ierror_t; |
| 188 | 190 | ||
| 189 | 191 | ||
diff --git a/include/net/sctp/sm.h b/include/net/sctp/sm.h index 148cdb4b9606..bf2f5ed69c15 100644 --- a/include/net/sctp/sm.h +++ b/include/net/sctp/sm.h | |||
| @@ -143,6 +143,7 @@ sctp_state_fn_t sctp_sf_do_asconf_ack; | |||
| 143 | sctp_state_fn_t sctp_sf_do_9_2_reshutack; | 143 | sctp_state_fn_t sctp_sf_do_9_2_reshutack; |
| 144 | sctp_state_fn_t sctp_sf_eat_fwd_tsn; | 144 | sctp_state_fn_t sctp_sf_eat_fwd_tsn; |
| 145 | sctp_state_fn_t sctp_sf_eat_fwd_tsn_fast; | 145 | sctp_state_fn_t sctp_sf_eat_fwd_tsn_fast; |
| 146 | sctp_state_fn_t sctp_sf_eat_auth; | ||
| 146 | 147 | ||
| 147 | /* Prototypes for primitive event state functions. */ | 148 | /* Prototypes for primitive event state functions. */ |
| 148 | sctp_state_fn_t sctp_sf_do_prm_asoc; | 149 | sctp_state_fn_t sctp_sf_do_prm_asoc; |
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 31841c3a7fe8..47e54f8e2b65 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h | |||
| @@ -724,6 +724,13 @@ struct sctp_chunk { | |||
| 724 | */ | 724 | */ |
| 725 | struct sctp_transport *transport; | 725 | struct sctp_transport *transport; |
| 726 | 726 | ||
| 727 | /* SCTP-AUTH: For the special case inbound processing of COOKIE-ECHO | ||
| 728 | * we need save a pointer to the AUTH chunk, since the SCTP-AUTH | ||
| 729 | * spec violates the principle premis that all chunks are processed | ||
| 730 | * in order. | ||
| 731 | */ | ||
| 732 | struct sk_buff *auth_chunk; | ||
| 733 | |||
| 727 | __u8 rtt_in_progress; /* Is this chunk used for RTT calculation? */ | 734 | __u8 rtt_in_progress; /* Is this chunk used for RTT calculation? */ |
| 728 | __u8 resent; /* Has this chunk ever been retransmitted. */ | 735 | __u8 resent; /* Has this chunk ever been retransmitted. */ |
| 729 | __u8 has_tsn; /* Does this chunk have a TSN yet? */ | 736 | __u8 has_tsn; /* Does this chunk have a TSN yet? */ |
| @@ -1067,6 +1074,7 @@ void sctp_inq_init(struct sctp_inq *); | |||
| 1067 | void sctp_inq_free(struct sctp_inq *); | 1074 | void sctp_inq_free(struct sctp_inq *); |
| 1068 | void sctp_inq_push(struct sctp_inq *, struct sctp_chunk *packet); | 1075 | void sctp_inq_push(struct sctp_inq *, struct sctp_chunk *packet); |
| 1069 | struct sctp_chunk *sctp_inq_pop(struct sctp_inq *); | 1076 | struct sctp_chunk *sctp_inq_pop(struct sctp_inq *); |
| 1077 | struct sctp_chunkhdr *sctp_inq_peek(struct sctp_inq *); | ||
| 1070 | void sctp_inq_set_th_handler(struct sctp_inq *, work_func_t); | 1078 | void sctp_inq_set_th_handler(struct sctp_inq *, work_func_t); |
| 1071 | 1079 | ||
| 1072 | /* This is the structure we use to hold outbound chunks. You push | 1080 | /* This is the structure we use to hold outbound chunks. You push |
diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 3bdd8dcb76a7..03158e3665da 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c | |||
| @@ -1011,6 +1011,16 @@ static void sctp_assoc_bh_rcv(struct work_struct *work) | |||
| 1011 | state = asoc->state; | 1011 | state = asoc->state; |
| 1012 | subtype = SCTP_ST_CHUNK(chunk->chunk_hdr->type); | 1012 | subtype = SCTP_ST_CHUNK(chunk->chunk_hdr->type); |
| 1013 | 1013 | ||
| 1014 | /* SCTP-AUTH, Section 6.3: | ||
| 1015 | * The receiver has a list of chunk types which it expects | ||
| 1016 | * to be received only after an AUTH-chunk. This list has | ||
| 1017 | * been sent to the peer during the association setup. It | ||
| 1018 | * MUST silently discard these chunks if they are not placed | ||
| 1019 | * after an AUTH chunk in the packet. | ||
| 1020 | */ | ||
| 1021 | if (sctp_auth_recv_cid(subtype.chunk, asoc) && !chunk->auth) | ||
| 1022 | continue; | ||
| 1023 | |||
| 1014 | /* Remember where the last DATA chunk came from so we | 1024 | /* Remember where the last DATA chunk came from so we |
| 1015 | * know where to send the SACK. | 1025 | * know where to send the SACK. |
| 1016 | */ | 1026 | */ |
diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c index c8d5023606a5..2d2d81ef4a69 100644 --- a/net/sctp/endpointola.c +++ b/net/sctp/endpointola.c | |||
| @@ -400,6 +400,7 @@ static void sctp_endpoint_bh_rcv(struct work_struct *work) | |||
| 400 | sctp_subtype_t subtype; | 400 | sctp_subtype_t subtype; |
| 401 | sctp_state_t state; | 401 | sctp_state_t state; |
| 402 | int error = 0; | 402 | int error = 0; |
| 403 | int first_time = 1; /* is this the first time through the looop */ | ||
| 403 | 404 | ||
| 404 | if (ep->base.dead) | 405 | if (ep->base.dead) |
| 405 | return; | 406 | return; |
| @@ -411,6 +412,29 @@ static void sctp_endpoint_bh_rcv(struct work_struct *work) | |||
| 411 | while (NULL != (chunk = sctp_inq_pop(inqueue))) { | 412 | while (NULL != (chunk = sctp_inq_pop(inqueue))) { |
| 412 | subtype = SCTP_ST_CHUNK(chunk->chunk_hdr->type); | 413 | subtype = SCTP_ST_CHUNK(chunk->chunk_hdr->type); |
| 413 | 414 | ||
| 415 | /* If the first chunk in the packet is AUTH, do special | ||
| 416 | * processing specified in Section 6.3 of SCTP-AUTH spec | ||
| 417 | */ | ||
| 418 | if (first_time && (subtype.chunk == SCTP_CID_AUTH)) { | ||
| 419 | struct sctp_chunkhdr *next_hdr; | ||
| 420 | |||
| 421 | next_hdr = sctp_inq_peek(inqueue); | ||
| 422 | if (!next_hdr) | ||
| 423 | goto normal; | ||
| 424 | |||
| 425 | /* If the next chunk is COOKIE-ECHO, skip the AUTH | ||
| 426 | * chunk while saving a pointer to it so we can do | ||
| 427 | * Authentication later (during cookie-echo | ||
| 428 | * processing). | ||
| 429 | */ | ||
| 430 | if (next_hdr->type == SCTP_CID_COOKIE_ECHO) { | ||
| 431 | chunk->auth_chunk = skb_clone(chunk->skb, | ||
| 432 | GFP_ATOMIC); | ||
| 433 | chunk->auth = 1; | ||
| 434 | continue; | ||
| 435 | } | ||
| 436 | } | ||
| 437 | normal: | ||
| 414 | /* We might have grown an association since last we | 438 | /* We might have grown an association since last we |
| 415 | * looked, so try again. | 439 | * looked, so try again. |
| 416 | * | 440 | * |
| @@ -426,6 +450,8 @@ static void sctp_endpoint_bh_rcv(struct work_struct *work) | |||
| 426 | } | 450 | } |
| 427 | 451 | ||
| 428 | state = asoc ? asoc->state : SCTP_STATE_CLOSED; | 452 | state = asoc ? asoc->state : SCTP_STATE_CLOSED; |
| 453 | if (sctp_auth_recv_cid(subtype.chunk, asoc) && !chunk->auth) | ||
| 454 | continue; | ||
| 429 | 455 | ||
| 430 | /* Remember where the last DATA chunk came from so we | 456 | /* Remember where the last DATA chunk came from so we |
| 431 | * know where to send the SACK. | 457 | * know where to send the SACK. |
| @@ -449,5 +475,8 @@ static void sctp_endpoint_bh_rcv(struct work_struct *work) | |||
| 449 | */ | 475 | */ |
| 450 | if (!sctp_sk(sk)->ep) | 476 | if (!sctp_sk(sk)->ep) |
| 451 | break; | 477 | break; |
| 478 | |||
| 479 | if (first_time) | ||
| 480 | first_time = 0; | ||
| 452 | } | 481 | } |
| 453 | } | 482 | } |
diff --git a/net/sctp/input.c b/net/sctp/input.c index f9a0c9276e3b..86503e7fa21e 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c | |||
| @@ -911,15 +911,6 @@ static struct sctp_association *__sctp_rcv_init_lookup(struct sk_buff *skb, | |||
| 911 | 911 | ||
| 912 | ch = (sctp_chunkhdr_t *) skb->data; | 912 | ch = (sctp_chunkhdr_t *) skb->data; |
| 913 | 913 | ||
| 914 | /* If this is INIT/INIT-ACK look inside the chunk too. */ | ||
| 915 | switch (ch->type) { | ||
| 916 | case SCTP_CID_INIT: | ||
| 917 | case SCTP_CID_INIT_ACK: | ||
| 918 | break; | ||
| 919 | default: | ||
| 920 | return NULL; | ||
| 921 | } | ||
| 922 | |||
| 923 | /* The code below will attempt to walk the chunk and extract | 914 | /* The code below will attempt to walk the chunk and extract |
| 924 | * parameter information. Before we do that, we need to verify | 915 | * parameter information. Before we do that, we need to verify |
| 925 | * that the chunk length doesn't cause overflow. Otherwise, we'll | 916 | * that the chunk length doesn't cause overflow. Otherwise, we'll |
| @@ -964,6 +955,60 @@ static struct sctp_association *__sctp_rcv_init_lookup(struct sk_buff *skb, | |||
| 964 | return NULL; | 955 | return NULL; |
| 965 | } | 956 | } |
| 966 | 957 | ||
| 958 | /* SCTP-AUTH, Section 6.3: | ||
| 959 | * If the receiver does not find a STCB for a packet containing an AUTH | ||
| 960 | * chunk as the first chunk and not a COOKIE-ECHO chunk as the second | ||
| 961 | * chunk, it MUST use the chunks after the AUTH chunk to look up an existing | ||
| 962 | * association. | ||
| 963 | * | ||
| 964 | * This means that any chunks that can help us identify the association need | ||
| 965 | * to be looked at to find this assocation. | ||
| 966 | * | ||
| 967 | * TODO: The only chunk currently defined that can do that is ASCONF, but we | ||
| 968 | * don't support that functionality yet. | ||
| 969 | */ | ||
| 970 | static struct sctp_association *__sctp_rcv_auth_lookup(struct sk_buff *skb, | ||
| 971 | const union sctp_addr *paddr, | ||
| 972 | const union sctp_addr *laddr, | ||
| 973 | struct sctp_transport **transportp) | ||
| 974 | { | ||
| 975 | /* XXX - walk through the chunks looking for something that can | ||
| 976 | * help us find the association. INIT, and INIT-ACK are not permitted. | ||
| 977 | * That leaves ASCONF, but we don't support that yet. | ||
| 978 | */ | ||
| 979 | return NULL; | ||
| 980 | } | ||
| 981 | |||
| 982 | /* | ||
| 983 | * There are circumstances when we need to look inside the SCTP packet | ||
| 984 | * for information to help us find the association. Examples | ||
| 985 | * include looking inside of INIT/INIT-ACK chunks or after the AUTH | ||
| 986 | * chunks. | ||
| 987 | */ | ||
| 988 | static struct sctp_association *__sctp_rcv_lookup_harder(struct sk_buff *skb, | ||
| 989 | const union sctp_addr *paddr, | ||
| 990 | const union sctp_addr *laddr, | ||
| 991 | struct sctp_transport **transportp) | ||
| 992 | { | ||
| 993 | sctp_chunkhdr_t *ch; | ||
| 994 | |||
| 995 | ch = (sctp_chunkhdr_t *) skb->data; | ||
| 996 | |||
| 997 | /* If this is INIT/INIT-ACK look inside the chunk too. */ | ||
| 998 | switch (ch->type) { | ||
| 999 | case SCTP_CID_INIT: | ||
| 1000 | case SCTP_CID_INIT_ACK: | ||
| 1001 | return __sctp_rcv_init_lookup(skb, laddr, transportp); | ||
| 1002 | break; | ||
| 1003 | |||
| 1004 | case SCTP_CID_AUTH: | ||
| 1005 | return __sctp_rcv_auth_lookup(skb, paddr, laddr, transportp); | ||
| 1006 | break; | ||
| 1007 | } | ||
| 1008 | |||
| 1009 | return NULL; | ||
| 1010 | } | ||
| 1011 | |||
| 967 | /* Lookup an association for an inbound skb. */ | 1012 | /* Lookup an association for an inbound skb. */ |
| 968 | static struct sctp_association *__sctp_rcv_lookup(struct sk_buff *skb, | 1013 | static struct sctp_association *__sctp_rcv_lookup(struct sk_buff *skb, |
| 969 | const union sctp_addr *paddr, | 1014 | const union sctp_addr *paddr, |
| @@ -979,7 +1024,7 @@ static struct sctp_association *__sctp_rcv_lookup(struct sk_buff *skb, | |||
| 979 | * parameters within the INIT or INIT-ACK. | 1024 | * parameters within the INIT or INIT-ACK. |
| 980 | */ | 1025 | */ |
| 981 | if (!asoc) | 1026 | if (!asoc) |
| 982 | asoc = __sctp_rcv_init_lookup(skb, laddr, transportp); | 1027 | asoc = __sctp_rcv_lookup_harder(skb, paddr, laddr, transportp); |
| 983 | 1028 | ||
| 984 | return asoc; | 1029 | return asoc; |
| 985 | } | 1030 | } |
diff --git a/net/sctp/inqueue.c b/net/sctp/inqueue.c index e4ea7fdf36ed..f10fe7fbf24c 100644 --- a/net/sctp/inqueue.c +++ b/net/sctp/inqueue.c | |||
| @@ -100,6 +100,25 @@ void sctp_inq_push(struct sctp_inq *q, struct sctp_chunk *chunk) | |||
| 100 | q->immediate.func(&q->immediate); | 100 | q->immediate.func(&q->immediate); |
| 101 | } | 101 | } |
| 102 | 102 | ||
| 103 | /* Peek at the next chunk on the inqeue. */ | ||
| 104 | struct sctp_chunkhdr *sctp_inq_peek(struct sctp_inq *queue) | ||
| 105 | { | ||
| 106 | struct sctp_chunk *chunk; | ||
| 107 | sctp_chunkhdr_t *ch = NULL; | ||
| 108 | |||
| 109 | chunk = queue->in_progress; | ||
| 110 | /* If there is no more chunks in this packet, say so */ | ||
| 111 | if (chunk->singleton || | ||
| 112 | chunk->end_of_packet || | ||
| 113 | chunk->pdiscard) | ||
| 114 | return NULL; | ||
| 115 | |||
| 116 | ch = (sctp_chunkhdr_t *)chunk->chunk_end; | ||
| 117 | |||
| 118 | return ch; | ||
| 119 | } | ||
| 120 | |||
| 121 | |||
| 103 | /* Extract a chunk from an SCTP inqueue. | 122 | /* Extract a chunk from an SCTP inqueue. |
| 104 | * | 123 | * |
| 105 | * WARNING: If you need to put the chunk on another queue, you need to | 124 | * WARNING: If you need to put the chunk on another queue, you need to |
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 385486360fe9..5aef4aafdfdc 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c | |||
| @@ -138,6 +138,11 @@ static sctp_disposition_t sctp_sf_violation_chunk( | |||
| 138 | void *arg, | 138 | void *arg, |
| 139 | sctp_cmd_seq_t *commands); | 139 | sctp_cmd_seq_t *commands); |
| 140 | 140 | ||
| 141 | static sctp_ierror_t sctp_sf_authenticate(const struct sctp_endpoint *ep, | ||
| 142 | const struct sctp_association *asoc, | ||
| 143 | const sctp_subtype_t type, | ||
| 144 | struct sctp_chunk *chunk); | ||
| 145 | |||
| 141 | /* Small helper function that checks if the chunk length | 146 | /* Small helper function that checks if the chunk length |
| 142 | * is of the appropriate length. The 'required_length' argument | 147 | * is of the appropriate length. The 'required_length' argument |
| 143 | * is set to be the size of a specific chunk we are testing. | 148 | * is set to be the size of a specific chunk we are testing. |
| @@ -495,8 +500,6 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const struct sctp_endpoint *ep, | |||
| 495 | (sctp_init_chunk_t *)chunk->chunk_hdr, chunk, | 500 | (sctp_init_chunk_t *)chunk->chunk_hdr, chunk, |
| 496 | &err_chunk)) { | 501 | &err_chunk)) { |
| 497 | 502 | ||
| 498 | SCTP_INC_STATS(SCTP_MIB_ABORTEDS); | ||
| 499 | |||
| 500 | /* This chunk contains fatal error. It is to be discarded. | 503 | /* This chunk contains fatal error. It is to be discarded. |
| 501 | * Send an ABORT, with causes if there is any. | 504 | * Send an ABORT, with causes if there is any. |
| 502 | */ | 505 | */ |
| @@ -521,6 +524,22 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const struct sctp_endpoint *ep, | |||
| 521 | sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands); | 524 | sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands); |
| 522 | error = SCTP_ERROR_INV_PARAM; | 525 | error = SCTP_ERROR_INV_PARAM; |
| 523 | } | 526 | } |
| 527 | |||
| 528 | /* SCTP-AUTH, Section 6.3: | ||
| 529 | * It should be noted that if the receiver wants to tear | ||
| 530 | * down an association in an authenticated way only, the | ||
| 531 | * handling of malformed packets should not result in | ||
| 532 | * tearing down the association. | ||
| 533 | * | ||
| 534 | * This means that if we only want to abort associations | ||
| 535 | * in an authenticated way (i.e AUTH+ABORT), then we | ||
| 536 | * can't destory this association just becuase the packet | ||
| 537 | * was malformed. | ||
| 538 | */ | ||
| 539 | if (sctp_auth_recv_cid(SCTP_CID_ABORT, asoc)) | ||
| 540 | return sctp_sf_pdiscard(ep, asoc, type, arg, commands); | ||
| 541 | |||
| 542 | SCTP_INC_STATS(SCTP_MIB_ABORTEDS); | ||
| 524 | return sctp_stop_t1_and_abort(commands, error, ECONNREFUSED, | 543 | return sctp_stop_t1_and_abort(commands, error, ECONNREFUSED, |
| 525 | asoc, chunk->transport); | 544 | asoc, chunk->transport); |
| 526 | } | 545 | } |
| @@ -699,6 +718,36 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep, | |||
| 699 | if (error) | 718 | if (error) |
| 700 | goto nomem_init; | 719 | goto nomem_init; |
| 701 | 720 | ||
| 721 | /* SCTP-AUTH: auth_chunk pointer is only set when the cookie-echo | ||
| 722 | * is supposed to be authenticated and we have to do delayed | ||
| 723 | * authentication. We've just recreated the association using | ||
| 724 | * the information in the cookie and now it's much easier to | ||
| 725 | * do the authentication. | ||
| 726 | */ | ||
| 727 | if (chunk->auth_chunk) { | ||
| 728 | struct sctp_chunk auth; | ||
| 729 | sctp_ierror_t ret; | ||
| 730 | |||
| 731 | /* set-up our fake chunk so that we can process it */ | ||
| 732 | auth.skb = chunk->auth_chunk; | ||
| 733 | auth.asoc = chunk->asoc; | ||
| 734 | auth.sctp_hdr = chunk->sctp_hdr; | ||
| 735 | auth.chunk_hdr = (sctp_chunkhdr_t *)skb_push(chunk->auth_chunk, | ||
| 736 | sizeof(sctp_chunkhdr_t)); | ||
| 737 | skb_pull(chunk->auth_chunk, sizeof(sctp_chunkhdr_t)); | ||
| 738 | auth.transport = chunk->transport; | ||
| 739 | |||
| 740 | ret = sctp_sf_authenticate(ep, new_asoc, type, &auth); | ||
| 741 | |||
| 742 | /* We can now safely free the auth_chunk clone */ | ||
| 743 | kfree_skb(chunk->auth_chunk); | ||
| 744 | |||
| 745 | if (ret != SCTP_IERROR_NO_ERROR) { | ||
| 746 | sctp_association_free(new_asoc); | ||
| 747 | return sctp_sf_pdiscard(ep, asoc, type, arg, commands); | ||
| 748 | } | ||
| 749 | } | ||
| 750 | |||
| 702 | repl = sctp_make_cookie_ack(new_asoc, chunk); | 751 | repl = sctp_make_cookie_ack(new_asoc, chunk); |
| 703 | if (!repl) | 752 | if (!repl) |
| 704 | goto nomem_init; | 753 | goto nomem_init; |
| @@ -3653,6 +3702,156 @@ gen_shutdown: | |||
| 3653 | } | 3702 | } |
| 3654 | 3703 | ||
| 3655 | /* | 3704 | /* |
| 3705 | * SCTP-AUTH Section 6.3 Receving authenticated chukns | ||
| 3706 | * | ||
| 3707 | * The receiver MUST use the HMAC algorithm indicated in the HMAC | ||
| 3708 | * Identifier field. If this algorithm was not specified by the | ||
| 3709 | * receiver in the HMAC-ALGO parameter in the INIT or INIT-ACK chunk | ||
| 3710 | * during association setup, the AUTH chunk and all chunks after it MUST | ||
| 3711 | * be discarded and an ERROR chunk SHOULD be sent with the error cause | ||
| 3712 | * defined in Section 4.1. | ||
| 3713 | * | ||
| 3714 | * If an endpoint with no shared key receives a Shared Key Identifier | ||
| 3715 | * other than 0, it MUST silently discard all authenticated chunks. If | ||
| 3716 | * the endpoint has at least one endpoint pair shared key for the peer, | ||
| 3717 | * it MUST use the key specified by the Shared Key Identifier if a | ||
| 3718 | * key has been configured for that Shared Key Identifier. If no | ||
| 3719 | * endpoint pair shared key has been configured for that Shared Key | ||
| 3720 | * Identifier, all authenticated chunks MUST be silently discarded. | ||
| 3721 | * | ||
| 3722 | * Verification Tag: 8.5 Verification Tag [Normal verification] | ||
| 3723 | * | ||
| 3724 | * The return value is the disposition of the chunk. | ||
| 3725 | */ | ||
| 3726 | static sctp_ierror_t sctp_sf_authenticate(const struct sctp_endpoint *ep, | ||
| 3727 | const struct sctp_association *asoc, | ||
| 3728 | const sctp_subtype_t type, | ||
| 3729 | struct sctp_chunk *chunk) | ||
| 3730 | { | ||
| 3731 | struct sctp_authhdr *auth_hdr; | ||
| 3732 | struct sctp_hmac *hmac; | ||
| 3733 | unsigned int sig_len; | ||
| 3734 | __u16 key_id; | ||
| 3735 | __u8 *save_digest; | ||
| 3736 | __u8 *digest; | ||
| 3737 | |||
| 3738 | /* Pull in the auth header, so we can do some more verification */ | ||
| 3739 | auth_hdr = (struct sctp_authhdr *)chunk->skb->data; | ||
| 3740 | chunk->subh.auth_hdr = auth_hdr; | ||
| 3741 | skb_pull(chunk->skb, sizeof(struct sctp_authhdr)); | ||
| 3742 | |||
| 3743 | /* Make sure that we suport the HMAC algorithm from the auth | ||
| 3744 | * chunk. | ||
| 3745 | */ | ||
| 3746 | if (!sctp_auth_asoc_verify_hmac_id(asoc, auth_hdr->hmac_id)) | ||
| 3747 | return SCTP_IERROR_AUTH_BAD_HMAC; | ||
| 3748 | |||
| 3749 | /* Make sure that the provided shared key identifier has been | ||
| 3750 | * configured | ||
| 3751 | */ | ||
| 3752 | key_id = ntohs(auth_hdr->shkey_id); | ||
| 3753 | if (key_id != asoc->active_key_id && !sctp_auth_get_shkey(asoc, key_id)) | ||
| 3754 | return SCTP_IERROR_AUTH_BAD_KEYID; | ||
| 3755 | |||
| 3756 | |||
| 3757 | /* Make sure that the length of the signature matches what | ||
| 3758 | * we expect. | ||
| 3759 | */ | ||
| 3760 | sig_len = ntohs(chunk->chunk_hdr->length) - sizeof(sctp_auth_chunk_t); | ||
| 3761 | hmac = sctp_auth_get_hmac(ntohs(auth_hdr->hmac_id)); | ||
| 3762 | if (sig_len != hmac->hmac_len) | ||
| 3763 | return SCTP_IERROR_PROTO_VIOLATION; | ||
| 3764 | |||
| 3765 | /* Now that we've done validation checks, we can compute and | ||
| 3766 | * verify the hmac. The steps involved are: | ||
| 3767 | * 1. Save the digest from the chunk. | ||
| 3768 | * 2. Zero out the digest in the chunk. | ||
| 3769 | * 3. Compute the new digest | ||
| 3770 | * 4. Compare saved and new digests. | ||
| 3771 | */ | ||
| 3772 | digest = auth_hdr->hmac; | ||
| 3773 | skb_pull(chunk->skb, sig_len); | ||
| 3774 | |||
| 3775 | save_digest = kmemdup(digest, sig_len, GFP_ATOMIC); | ||
| 3776 | if (!save_digest) | ||
| 3777 | goto nomem; | ||
| 3778 | |||
| 3779 | memset(digest, 0, sig_len); | ||
| 3780 | |||
| 3781 | sctp_auth_calculate_hmac(asoc, chunk->skb, | ||
| 3782 | (struct sctp_auth_chunk *)chunk->chunk_hdr, | ||
| 3783 | GFP_ATOMIC); | ||
| 3784 | |||
| 3785 | /* Discard the packet if the digests do not match */ | ||
| 3786 | if (memcmp(save_digest, digest, sig_len)) { | ||
| 3787 | kfree(save_digest); | ||
| 3788 | return SCTP_IERROR_BAD_SIG; | ||
| 3789 | } | ||
| 3790 | |||
| 3791 | kfree(save_digest); | ||
| 3792 | chunk->auth = 1; | ||
| 3793 | |||
| 3794 | return SCTP_IERROR_NO_ERROR; | ||
| 3795 | nomem: | ||
| 3796 | return SCTP_IERROR_NOMEM; | ||
| 3797 | } | ||
| 3798 | |||
| 3799 | sctp_disposition_t sctp_sf_eat_auth(const struct sctp_endpoint *ep, | ||
| 3800 | const struct sctp_association *asoc, | ||
| 3801 | const sctp_subtype_t type, | ||
| 3802 | void *arg, | ||
| 3803 | sctp_cmd_seq_t *commands) | ||
| 3804 | { | ||
| 3805 | struct sctp_authhdr *auth_hdr; | ||
| 3806 | struct sctp_chunk *chunk = arg; | ||
| 3807 | struct sctp_chunk *err_chunk; | ||
| 3808 | sctp_ierror_t error; | ||
| 3809 | |||
| 3810 | if (!sctp_vtag_verify(chunk, asoc)) { | ||
| 3811 | sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_BAD_TAG, | ||
| 3812 | SCTP_NULL()); | ||
| 3813 | return sctp_sf_pdiscard(ep, asoc, type, arg, commands); | ||
| 3814 | } | ||
| 3815 | |||
| 3816 | /* Make sure that the AUTH chunk has valid length. */ | ||
| 3817 | if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_auth_chunk))) | ||
| 3818 | return sctp_sf_violation_chunklen(ep, asoc, type, arg, | ||
| 3819 | commands); | ||
| 3820 | |||
| 3821 | auth_hdr = (struct sctp_authhdr *)chunk->skb->data; | ||
| 3822 | error = sctp_sf_authenticate(ep, asoc, type, chunk); | ||
| 3823 | switch (error) { | ||
| 3824 | case SCTP_IERROR_AUTH_BAD_HMAC: | ||
| 3825 | /* Generate the ERROR chunk and discard the rest | ||
| 3826 | * of the packet | ||
| 3827 | */ | ||
| 3828 | err_chunk = sctp_make_op_error(asoc, chunk, | ||
| 3829 | SCTP_ERROR_UNSUP_HMAC, | ||
| 3830 | &auth_hdr->hmac_id, | ||
| 3831 | sizeof(__u16)); | ||
| 3832 | if (err_chunk) { | ||
| 3833 | sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, | ||
| 3834 | SCTP_CHUNK(err_chunk)); | ||
| 3835 | } | ||
| 3836 | /* Fall Through */ | ||
| 3837 | case SCTP_IERROR_AUTH_BAD_KEYID: | ||
| 3838 | case SCTP_IERROR_BAD_SIG: | ||
| 3839 | return sctp_sf_pdiscard(ep, asoc, type, arg, commands); | ||
| 3840 | break; | ||
| 3841 | case SCTP_IERROR_PROTO_VIOLATION: | ||
| 3842 | return sctp_sf_violation_chunklen(ep, asoc, type, arg, | ||
| 3843 | commands); | ||
| 3844 | break; | ||
| 3845 | case SCTP_IERROR_NOMEM: | ||
| 3846 | return SCTP_DISPOSITION_NOMEM; | ||
| 3847 | default: | ||
| 3848 | break; | ||
| 3849 | } | ||
| 3850 | |||
| 3851 | return SCTP_DISPOSITION_CONSUME; | ||
| 3852 | } | ||
| 3853 | |||
| 3854 | /* | ||
| 3656 | * Process an unknown chunk. | 3855 | * Process an unknown chunk. |
| 3657 | * | 3856 | * |
| 3658 | * Section: 3.2. Also, 2.1 in the implementor's guide. | 3857 | * Section: 3.2. Also, 2.1 in the implementor's guide. |
| @@ -3857,6 +4056,20 @@ static sctp_disposition_t sctp_sf_abort_violation( | |||
| 3857 | if (!abort) | 4056 | if (!abort) |
| 3858 | goto nomem; | 4057 | goto nomem; |
| 3859 | 4058 | ||
| 4059 | /* SCTP-AUTH, Section 6.3: | ||
| 4060 | * It should be noted that if the receiver wants to tear | ||
| 4061 | * down an association in an authenticated way only, the | ||
| 4062 | * handling of malformed packets should not result in | ||
| 4063 | * tearing down the association. | ||
| 4064 | * | ||
| 4065 | * This means that if we only want to abort associations | ||
| 4066 | * in an authenticated way (i.e AUTH+ABORT), then we | ||
| 4067 | * can't destory this association just becuase the packet | ||
| 4068 | * was malformed. | ||
| 4069 | */ | ||
| 4070 | if (sctp_auth_recv_cid(SCTP_CID_ABORT, asoc)) | ||
| 4071 | goto discard; | ||
| 4072 | |||
| 3860 | if (asoc) { | 4073 | if (asoc) { |
| 3861 | sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort)); | 4074 | sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort)); |
| 3862 | SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS); | 4075 | SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS); |
| @@ -3894,6 +4107,7 @@ static sctp_disposition_t sctp_sf_abort_violation( | |||
| 3894 | SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS); | 4107 | SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS); |
| 3895 | } | 4108 | } |
| 3896 | 4109 | ||
| 4110 | discard: | ||
| 3897 | sctp_sf_pdiscard(ep, asoc, SCTP_ST_CHUNK(0), arg, commands); | 4111 | sctp_sf_pdiscard(ep, asoc, SCTP_ST_CHUNK(0), arg, commands); |
| 3898 | 4112 | ||
| 3899 | SCTP_INC_STATS(SCTP_MIB_ABORTEDS); | 4113 | SCTP_INC_STATS(SCTP_MIB_ABORTEDS); |
diff --git a/net/sctp/sm_statetable.c b/net/sctp/sm_statetable.c index ddb0ba3974b0..a93a4bc8f68f 100644 --- a/net/sctp/sm_statetable.c +++ b/net/sctp/sm_statetable.c | |||
| @@ -523,6 +523,34 @@ static const sctp_sm_table_entry_t prsctp_chunk_event_table[SCTP_NUM_PRSCTP_CHUN | |||
| 523 | TYPE_SCTP_FWD_TSN, | 523 | TYPE_SCTP_FWD_TSN, |
| 524 | }; /*state_fn_t prsctp_chunk_event_table[][] */ | 524 | }; /*state_fn_t prsctp_chunk_event_table[][] */ |
| 525 | 525 | ||
| 526 | #define TYPE_SCTP_AUTH { \ | ||
| 527 | /* SCTP_STATE_EMPTY */ \ | ||
| 528 | TYPE_SCTP_FUNC(sctp_sf_ootb), \ | ||
| 529 | /* SCTP_STATE_CLOSED */ \ | ||
| 530 | TYPE_SCTP_FUNC(sctp_sf_ootb), \ | ||
| 531 | /* SCTP_STATE_COOKIE_WAIT */ \ | ||
| 532 | TYPE_SCTP_FUNC(sctp_sf_discard_chunk), \ | ||
| 533 | /* SCTP_STATE_COOKIE_ECHOED */ \ | ||
| 534 | TYPE_SCTP_FUNC(sctp_sf_eat_auth), \ | ||
| 535 | /* SCTP_STATE_ESTABLISHED */ \ | ||
| 536 | TYPE_SCTP_FUNC(sctp_sf_eat_auth), \ | ||
| 537 | /* SCTP_STATE_SHUTDOWN_PENDING */ \ | ||
| 538 | TYPE_SCTP_FUNC(sctp_sf_eat_auth), \ | ||
| 539 | /* SCTP_STATE_SHUTDOWN_SENT */ \ | ||
| 540 | TYPE_SCTP_FUNC(sctp_sf_eat_auth), \ | ||
| 541 | /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ | ||
| 542 | TYPE_SCTP_FUNC(sctp_sf_eat_auth), \ | ||
| 543 | /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ | ||
| 544 | TYPE_SCTP_FUNC(sctp_sf_eat_auth), \ | ||
| 545 | } /* TYPE_SCTP_AUTH */ | ||
| 546 | |||
| 547 | /* The primary index for this table is the chunk type. | ||
| 548 | * The secondary index for this table is the state. | ||
| 549 | */ | ||
| 550 | static const sctp_sm_table_entry_t auth_chunk_event_table[SCTP_NUM_AUTH_CHUNK_TYPES][SCTP_STATE_NUM_STATES] = { | ||
| 551 | TYPE_SCTP_AUTH, | ||
| 552 | }; /*state_fn_t auth_chunk_event_table[][] */ | ||
| 553 | |||
| 526 | static const sctp_sm_table_entry_t | 554 | static const sctp_sm_table_entry_t |
| 527 | chunk_event_table_unknown[SCTP_STATE_NUM_STATES] = { | 555 | chunk_event_table_unknown[SCTP_STATE_NUM_STATES] = { |
| 528 | /* SCTP_STATE_EMPTY */ | 556 | /* SCTP_STATE_EMPTY */ |
| @@ -976,5 +1004,10 @@ static const sctp_sm_table_entry_t *sctp_chunk_event_lookup(sctp_cid_t cid, | |||
| 976 | return &addip_chunk_event_table[1][state]; | 1004 | return &addip_chunk_event_table[1][state]; |
| 977 | } | 1005 | } |
| 978 | 1006 | ||
| 1007 | if (sctp_auth_enable) { | ||
| 1008 | if (cid == SCTP_CID_AUTH) | ||
| 1009 | return &auth_chunk_event_table[0][state]; | ||
| 1010 | } | ||
| 1011 | |||
| 979 | return &chunk_event_table_unknown[state]; | 1012 | return &chunk_event_table_unknown[state]; |
| 980 | } | 1013 | } |
