diff options
Diffstat (limited to 'net/sctp/sm_statefuns.c')
-rw-r--r-- | net/sctp/sm_statefuns.c | 163 |
1 files changed, 130 insertions, 33 deletions
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 5e7fb0f54b88..caed19d90d06 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c | |||
@@ -90,6 +90,11 @@ static sctp_disposition_t sctp_sf_shut_8_4_5(const struct sctp_endpoint *ep, | |||
90 | const sctp_subtype_t type, | 90 | const sctp_subtype_t type, |
91 | void *arg, | 91 | void *arg, |
92 | sctp_cmd_seq_t *commands); | 92 | sctp_cmd_seq_t *commands); |
93 | static sctp_disposition_t sctp_sf_tabort_8_4_8(const struct sctp_endpoint *ep, | ||
94 | const struct sctp_association *asoc, | ||
95 | const sctp_subtype_t type, | ||
96 | void *arg, | ||
97 | sctp_cmd_seq_t *commands); | ||
93 | static struct sctp_sackhdr *sctp_sm_pull_sack(struct sctp_chunk *chunk); | 98 | static struct sctp_sackhdr *sctp_sm_pull_sack(struct sctp_chunk *chunk); |
94 | 99 | ||
95 | static sctp_disposition_t sctp_stop_t1_and_abort(sctp_cmd_seq_t *commands, | 100 | static sctp_disposition_t sctp_stop_t1_and_abort(sctp_cmd_seq_t *commands, |
@@ -98,6 +103,7 @@ static sctp_disposition_t sctp_stop_t1_and_abort(sctp_cmd_seq_t *commands, | |||
98 | struct sctp_transport *transport); | 103 | struct sctp_transport *transport); |
99 | 104 | ||
100 | static sctp_disposition_t sctp_sf_abort_violation( | 105 | static sctp_disposition_t sctp_sf_abort_violation( |
106 | const struct sctp_endpoint *ep, | ||
101 | const struct sctp_association *asoc, | 107 | const struct sctp_association *asoc, |
102 | void *arg, | 108 | void *arg, |
103 | sctp_cmd_seq_t *commands, | 109 | sctp_cmd_seq_t *commands, |
@@ -118,6 +124,13 @@ static sctp_disposition_t sctp_sf_violation_ctsn( | |||
118 | void *arg, | 124 | void *arg, |
119 | sctp_cmd_seq_t *commands); | 125 | sctp_cmd_seq_t *commands); |
120 | 126 | ||
127 | static sctp_disposition_t sctp_sf_violation_chunk( | ||
128 | const struct sctp_endpoint *ep, | ||
129 | const struct sctp_association *asoc, | ||
130 | const sctp_subtype_t type, | ||
131 | void *arg, | ||
132 | sctp_cmd_seq_t *commands); | ||
133 | |||
121 | /* Small helper function that checks if the chunk length | 134 | /* Small helper function that checks if the chunk length |
122 | * is of the appropriate length. The 'required_length' argument | 135 | * is of the appropriate length. The 'required_length' argument |
123 | * is set to be the size of a specific chunk we are testing. | 136 | * is set to be the size of a specific chunk we are testing. |
@@ -181,16 +194,21 @@ sctp_disposition_t sctp_sf_do_4_C(const struct sctp_endpoint *ep, | |||
181 | struct sctp_chunk *chunk = arg; | 194 | struct sctp_chunk *chunk = arg; |
182 | struct sctp_ulpevent *ev; | 195 | struct sctp_ulpevent *ev; |
183 | 196 | ||
197 | if (!sctp_vtag_verify_either(chunk, asoc)) | ||
198 | return sctp_sf_pdiscard(ep, asoc, type, arg, commands); | ||
199 | |||
184 | /* RFC 2960 6.10 Bundling | 200 | /* RFC 2960 6.10 Bundling |
185 | * | 201 | * |
186 | * An endpoint MUST NOT bundle INIT, INIT ACK or | 202 | * An endpoint MUST NOT bundle INIT, INIT ACK or |
187 | * SHUTDOWN COMPLETE with any other chunks. | 203 | * SHUTDOWN COMPLETE with any other chunks. |
188 | */ | 204 | */ |
189 | if (!chunk->singleton) | 205 | if (!chunk->singleton) |
190 | return SCTP_DISPOSITION_VIOLATION; | 206 | return sctp_sf_violation_chunk(ep, asoc, type, arg, commands); |
191 | 207 | ||
192 | if (!sctp_vtag_verify_either(chunk, asoc)) | 208 | /* Make sure that the SHUTDOWN_COMPLETE chunk has a valid length. */ |
193 | return sctp_sf_pdiscard(ep, asoc, type, arg, commands); | 209 | if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t))) |
210 | return sctp_sf_violation_chunklen(ep, asoc, type, arg, | ||
211 | commands); | ||
194 | 212 | ||
195 | /* RFC 2960 10.2 SCTP-to-ULP | 213 | /* RFC 2960 10.2 SCTP-to-ULP |
196 | * | 214 | * |
@@ -450,17 +468,17 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const struct sctp_endpoint *ep, | |||
450 | if (!sctp_vtag_verify(chunk, asoc)) | 468 | if (!sctp_vtag_verify(chunk, asoc)) |
451 | return sctp_sf_pdiscard(ep, asoc, type, arg, commands); | 469 | return sctp_sf_pdiscard(ep, asoc, type, arg, commands); |
452 | 470 | ||
453 | /* Make sure that the INIT-ACK chunk has a valid length */ | ||
454 | if (!sctp_chunk_length_valid(chunk, sizeof(sctp_initack_chunk_t))) | ||
455 | return sctp_sf_violation_chunklen(ep, asoc, type, arg, | ||
456 | commands); | ||
457 | /* 6.10 Bundling | 471 | /* 6.10 Bundling |
458 | * An endpoint MUST NOT bundle INIT, INIT ACK or | 472 | * An endpoint MUST NOT bundle INIT, INIT ACK or |
459 | * SHUTDOWN COMPLETE with any other chunks. | 473 | * SHUTDOWN COMPLETE with any other chunks. |
460 | */ | 474 | */ |
461 | if (!chunk->singleton) | 475 | if (!chunk->singleton) |
462 | return SCTP_DISPOSITION_VIOLATION; | 476 | return sctp_sf_violation_chunk(ep, asoc, type, arg, commands); |
463 | 477 | ||
478 | /* Make sure that the INIT-ACK chunk has a valid length */ | ||
479 | if (!sctp_chunk_length_valid(chunk, sizeof(sctp_initack_chunk_t))) | ||
480 | return sctp_sf_violation_chunklen(ep, asoc, type, arg, | ||
481 | commands); | ||
464 | /* Grab the INIT header. */ | 482 | /* Grab the INIT header. */ |
465 | chunk->subh.init_hdr = (sctp_inithdr_t *) chunk->skb->data; | 483 | chunk->subh.init_hdr = (sctp_inithdr_t *) chunk->skb->data; |
466 | 484 | ||
@@ -585,7 +603,7 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep, | |||
585 | * control endpoint, respond with an ABORT. | 603 | * control endpoint, respond with an ABORT. |
586 | */ | 604 | */ |
587 | if (ep == sctp_sk((sctp_get_ctl_sock()))->ep) | 605 | if (ep == sctp_sk((sctp_get_ctl_sock()))->ep) |
588 | return sctp_sf_ootb(ep, asoc, type, arg, commands); | 606 | return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands); |
589 | 607 | ||
590 | /* Make sure that the COOKIE_ECHO chunk has a valid length. | 608 | /* Make sure that the COOKIE_ECHO chunk has a valid length. |
591 | * In this case, we check that we have enough for at least a | 609 | * In this case, we check that we have enough for at least a |
@@ -2496,6 +2514,11 @@ sctp_disposition_t sctp_sf_do_9_2_reshutack(const struct sctp_endpoint *ep, | |||
2496 | struct sctp_chunk *chunk = (struct sctp_chunk *) arg; | 2514 | struct sctp_chunk *chunk = (struct sctp_chunk *) arg; |
2497 | struct sctp_chunk *reply; | 2515 | struct sctp_chunk *reply; |
2498 | 2516 | ||
2517 | /* Make sure that the chunk has a valid length */ | ||
2518 | if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t))) | ||
2519 | return sctp_sf_violation_chunklen(ep, asoc, type, arg, | ||
2520 | commands); | ||
2521 | |||
2499 | /* Since we are not going to really process this INIT, there | 2522 | /* Since we are not going to really process this INIT, there |
2500 | * is no point in verifying chunk boundries. Just generate | 2523 | * is no point in verifying chunk boundries. Just generate |
2501 | * the SHUTDOWN ACK. | 2524 | * the SHUTDOWN ACK. |
@@ -2929,7 +2952,7 @@ sctp_disposition_t sctp_sf_eat_sack_6_2(const struct sctp_endpoint *ep, | |||
2929 | * | 2952 | * |
2930 | * The return value is the disposition of the chunk. | 2953 | * The return value is the disposition of the chunk. |
2931 | */ | 2954 | */ |
2932 | sctp_disposition_t sctp_sf_tabort_8_4_8(const struct sctp_endpoint *ep, | 2955 | static sctp_disposition_t sctp_sf_tabort_8_4_8(const struct sctp_endpoint *ep, |
2933 | const struct sctp_association *asoc, | 2956 | const struct sctp_association *asoc, |
2934 | const sctp_subtype_t type, | 2957 | const sctp_subtype_t type, |
2935 | void *arg, | 2958 | void *arg, |
@@ -3126,14 +3149,14 @@ sctp_disposition_t sctp_sf_ootb(const struct sctp_endpoint *ep, | |||
3126 | 3149 | ||
3127 | ch = (sctp_chunkhdr_t *) chunk->chunk_hdr; | 3150 | ch = (sctp_chunkhdr_t *) chunk->chunk_hdr; |
3128 | do { | 3151 | do { |
3129 | /* Break out if chunk length is less then minimal. */ | 3152 | /* Report violation if the chunk is less then minimal */ |
3130 | if (ntohs(ch->length) < sizeof(sctp_chunkhdr_t)) | 3153 | if (ntohs(ch->length) < sizeof(sctp_chunkhdr_t)) |
3131 | break; | 3154 | return sctp_sf_violation_chunklen(ep, asoc, type, arg, |
3132 | 3155 | commands); | |
3133 | ch_end = ((__u8 *)ch) + WORD_ROUND(ntohs(ch->length)); | ||
3134 | if (ch_end > skb_tail_pointer(skb)) | ||
3135 | break; | ||
3136 | 3156 | ||
3157 | /* Now that we know we at least have a chunk header, | ||
3158 | * do things that are type appropriate. | ||
3159 | */ | ||
3137 | if (SCTP_CID_SHUTDOWN_ACK == ch->type) | 3160 | if (SCTP_CID_SHUTDOWN_ACK == ch->type) |
3138 | ootb_shut_ack = 1; | 3161 | ootb_shut_ack = 1; |
3139 | 3162 | ||
@@ -3145,6 +3168,12 @@ sctp_disposition_t sctp_sf_ootb(const struct sctp_endpoint *ep, | |||
3145 | if (SCTP_CID_ABORT == ch->type) | 3168 | if (SCTP_CID_ABORT == ch->type) |
3146 | return sctp_sf_pdiscard(ep, asoc, type, arg, commands); | 3169 | return sctp_sf_pdiscard(ep, asoc, type, arg, commands); |
3147 | 3170 | ||
3171 | /* Report violation if chunk len overflows */ | ||
3172 | ch_end = ((__u8 *)ch) + WORD_ROUND(ntohs(ch->length)); | ||
3173 | if (ch_end > skb_tail_pointer(skb)) | ||
3174 | return sctp_sf_violation_chunklen(ep, asoc, type, arg, | ||
3175 | commands); | ||
3176 | |||
3148 | ch = (sctp_chunkhdr_t *) ch_end; | 3177 | ch = (sctp_chunkhdr_t *) ch_end; |
3149 | } while (ch_end < skb_tail_pointer(skb)); | 3178 | } while (ch_end < skb_tail_pointer(skb)); |
3150 | 3179 | ||
@@ -3244,6 +3273,13 @@ sctp_disposition_t sctp_sf_do_8_5_1_E_sa(const struct sctp_endpoint *ep, | |||
3244 | void *arg, | 3273 | void *arg, |
3245 | sctp_cmd_seq_t *commands) | 3274 | sctp_cmd_seq_t *commands) |
3246 | { | 3275 | { |
3276 | struct sctp_chunk *chunk = arg; | ||
3277 | |||
3278 | /* Make sure that the SHUTDOWN_ACK chunk has a valid length. */ | ||
3279 | if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t))) | ||
3280 | return sctp_sf_violation_chunklen(ep, asoc, type, arg, | ||
3281 | commands); | ||
3282 | |||
3247 | /* Although we do have an association in this case, it corresponds | 3283 | /* Although we do have an association in this case, it corresponds |
3248 | * to a restarted association. So the packet is treated as an OOTB | 3284 | * to a restarted association. So the packet is treated as an OOTB |
3249 | * packet and the state function that handles OOTB SHUTDOWN_ACK is | 3285 | * packet and the state function that handles OOTB SHUTDOWN_ACK is |
@@ -3658,6 +3694,16 @@ sctp_disposition_t sctp_sf_discard_chunk(const struct sctp_endpoint *ep, | |||
3658 | void *arg, | 3694 | void *arg, |
3659 | sctp_cmd_seq_t *commands) | 3695 | sctp_cmd_seq_t *commands) |
3660 | { | 3696 | { |
3697 | struct sctp_chunk *chunk = arg; | ||
3698 | |||
3699 | /* Make sure that the chunk has a valid length. | ||
3700 | * Since we don't know the chunk type, we use a general | ||
3701 | * chunkhdr structure to make a comparison. | ||
3702 | */ | ||
3703 | if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t))) | ||
3704 | return sctp_sf_violation_chunklen(ep, asoc, type, arg, | ||
3705 | commands); | ||
3706 | |||
3661 | SCTP_DEBUG_PRINTK("Chunk %d is discarded\n", type.chunk); | 3707 | SCTP_DEBUG_PRINTK("Chunk %d is discarded\n", type.chunk); |
3662 | return SCTP_DISPOSITION_DISCARD; | 3708 | return SCTP_DISPOSITION_DISCARD; |
3663 | } | 3709 | } |
@@ -3713,6 +3759,13 @@ sctp_disposition_t sctp_sf_violation(const struct sctp_endpoint *ep, | |||
3713 | void *arg, | 3759 | void *arg, |
3714 | sctp_cmd_seq_t *commands) | 3760 | sctp_cmd_seq_t *commands) |
3715 | { | 3761 | { |
3762 | struct sctp_chunk *chunk = arg; | ||
3763 | |||
3764 | /* Make sure that the chunk has a valid length. */ | ||
3765 | if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t))) | ||
3766 | return sctp_sf_violation_chunklen(ep, asoc, type, arg, | ||
3767 | commands); | ||
3768 | |||
3716 | return SCTP_DISPOSITION_VIOLATION; | 3769 | return SCTP_DISPOSITION_VIOLATION; |
3717 | } | 3770 | } |
3718 | 3771 | ||
@@ -3720,12 +3773,14 @@ sctp_disposition_t sctp_sf_violation(const struct sctp_endpoint *ep, | |||
3720 | * Common function to handle a protocol violation. | 3773 | * Common function to handle a protocol violation. |
3721 | */ | 3774 | */ |
3722 | static sctp_disposition_t sctp_sf_abort_violation( | 3775 | static sctp_disposition_t sctp_sf_abort_violation( |
3776 | const struct sctp_endpoint *ep, | ||
3723 | const struct sctp_association *asoc, | 3777 | const struct sctp_association *asoc, |
3724 | void *arg, | 3778 | void *arg, |
3725 | sctp_cmd_seq_t *commands, | 3779 | sctp_cmd_seq_t *commands, |
3726 | const __u8 *payload, | 3780 | const __u8 *payload, |
3727 | const size_t paylen) | 3781 | const size_t paylen) |
3728 | { | 3782 | { |
3783 | struct sctp_packet *packet = NULL; | ||
3729 | struct sctp_chunk *chunk = arg; | 3784 | struct sctp_chunk *chunk = arg; |
3730 | struct sctp_chunk *abort = NULL; | 3785 | struct sctp_chunk *abort = NULL; |
3731 | 3786 | ||
@@ -3734,30 +3789,51 @@ static sctp_disposition_t sctp_sf_abort_violation( | |||
3734 | if (!abort) | 3789 | if (!abort) |
3735 | goto nomem; | 3790 | goto nomem; |
3736 | 3791 | ||
3737 | sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort)); | 3792 | if (asoc) { |
3738 | SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS); | 3793 | sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort)); |
3794 | SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS); | ||
3739 | 3795 | ||
3740 | if (asoc->state <= SCTP_STATE_COOKIE_ECHOED) { | 3796 | if (asoc->state <= SCTP_STATE_COOKIE_ECHOED) { |
3741 | sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, | 3797 | sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, |
3742 | SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT)); | 3798 | SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT)); |
3743 | sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR, | 3799 | sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR, |
3744 | SCTP_ERROR(ECONNREFUSED)); | 3800 | SCTP_ERROR(ECONNREFUSED)); |
3745 | sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, | 3801 | sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, |
3746 | SCTP_PERR(SCTP_ERROR_PROTO_VIOLATION)); | 3802 | SCTP_PERR(SCTP_ERROR_PROTO_VIOLATION)); |
3803 | } else { | ||
3804 | sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR, | ||
3805 | SCTP_ERROR(ECONNABORTED)); | ||
3806 | sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, | ||
3807 | SCTP_PERR(SCTP_ERROR_PROTO_VIOLATION)); | ||
3808 | SCTP_DEC_STATS(SCTP_MIB_CURRESTAB); | ||
3809 | } | ||
3747 | } else { | 3810 | } else { |
3748 | sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR, | 3811 | packet = sctp_ootb_pkt_new(asoc, chunk); |
3749 | SCTP_ERROR(ECONNABORTED)); | 3812 | |
3750 | sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, | 3813 | if (!packet) |
3751 | SCTP_PERR(SCTP_ERROR_PROTO_VIOLATION)); | 3814 | goto nomem_pkt; |
3752 | SCTP_DEC_STATS(SCTP_MIB_CURRESTAB); | 3815 | |
3816 | if (sctp_test_T_bit(abort)) | ||
3817 | packet->vtag = ntohl(chunk->sctp_hdr->vtag); | ||
3818 | |||
3819 | abort->skb->sk = ep->base.sk; | ||
3820 | |||
3821 | sctp_packet_append_chunk(packet, abort); | ||
3822 | |||
3823 | sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT, | ||
3824 | SCTP_PACKET(packet)); | ||
3825 | |||
3826 | SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS); | ||
3753 | } | 3827 | } |
3754 | 3828 | ||
3755 | sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET, SCTP_NULL()); | 3829 | sctp_sf_pdiscard(ep, asoc, SCTP_ST_CHUNK(0), arg, commands); |
3756 | 3830 | ||
3757 | SCTP_INC_STATS(SCTP_MIB_ABORTEDS); | 3831 | SCTP_INC_STATS(SCTP_MIB_ABORTEDS); |
3758 | 3832 | ||
3759 | return SCTP_DISPOSITION_ABORT; | 3833 | return SCTP_DISPOSITION_ABORT; |
3760 | 3834 | ||
3835 | nomem_pkt: | ||
3836 | sctp_chunk_free(abort); | ||
3761 | nomem: | 3837 | nomem: |
3762 | return SCTP_DISPOSITION_NOMEM; | 3838 | return SCTP_DISPOSITION_NOMEM; |
3763 | } | 3839 | } |
@@ -3790,7 +3866,7 @@ static sctp_disposition_t sctp_sf_violation_chunklen( | |||
3790 | { | 3866 | { |
3791 | char err_str[]="The following chunk had invalid length:"; | 3867 | char err_str[]="The following chunk had invalid length:"; |
3792 | 3868 | ||
3793 | return sctp_sf_abort_violation(asoc, arg, commands, err_str, | 3869 | return sctp_sf_abort_violation(ep, asoc, arg, commands, err_str, |
3794 | sizeof(err_str)); | 3870 | sizeof(err_str)); |
3795 | } | 3871 | } |
3796 | 3872 | ||
@@ -3809,10 +3885,31 @@ static sctp_disposition_t sctp_sf_violation_ctsn( | |||
3809 | { | 3885 | { |
3810 | char err_str[]="The cumulative tsn ack beyond the max tsn currently sent:"; | 3886 | char err_str[]="The cumulative tsn ack beyond the max tsn currently sent:"; |
3811 | 3887 | ||
3812 | return sctp_sf_abort_violation(asoc, arg, commands, err_str, | 3888 | return sctp_sf_abort_violation(ep, asoc, arg, commands, err_str, |
3813 | sizeof(err_str)); | 3889 | sizeof(err_str)); |
3814 | } | 3890 | } |
3815 | 3891 | ||
3892 | /* Handle protocol violation of an invalid chunk bundling. For example, | ||
3893 | * when we have an association and we recieve bundled INIT-ACK, or | ||
3894 | * SHUDOWN-COMPLETE, our peer is clearly violationg the "MUST NOT bundle" | ||
3895 | * statement from the specs. Additinally, there might be an attacker | ||
3896 | * on the path and we may not want to continue this communication. | ||
3897 | */ | ||
3898 | static sctp_disposition_t sctp_sf_violation_chunk( | ||
3899 | const struct sctp_endpoint *ep, | ||
3900 | const struct sctp_association *asoc, | ||
3901 | const sctp_subtype_t type, | ||
3902 | void *arg, | ||
3903 | sctp_cmd_seq_t *commands) | ||
3904 | { | ||
3905 | char err_str[]="The following chunk violates protocol:"; | ||
3906 | |||
3907 | if (!asoc) | ||
3908 | return sctp_sf_violation(ep, asoc, type, arg, commands); | ||
3909 | |||
3910 | return sctp_sf_abort_violation(ep, asoc, arg, commands, err_str, | ||
3911 | sizeof(err_str)); | ||
3912 | } | ||
3816 | /*************************************************************************** | 3913 | /*************************************************************************** |
3817 | * These are the state functions for handling primitive (Section 10) events. | 3914 | * These are the state functions for handling primitive (Section 10) events. |
3818 | ***************************************************************************/ | 3915 | ***************************************************************************/ |