diff options
author | Vlad Yasevich <vladislav.yasevich@hp.com> | 2009-09-04 18:21:03 -0400 |
---|---|---|
committer | Vlad Yasevich <vladislav.yasevich@hp.com> | 2009-09-04 18:21:03 -0400 |
commit | f1751c57f7bb816c9b6b4cb5d79c703aaa7199da (patch) | |
tree | 68e75889f4fd4b576f50bd52088c79f7c837323d /net/sctp/sm_statefuns.c | |
parent | be2971438dec2e2d041af4701472a93a7dd03642 (diff) |
sctp: Catch bogus stream sequence numbers
Since our TSN map is capable of holding at most a 4K chunk gap,
there is no way that during this gap, a stream sequence number
(unsigned short) can wrap such that the new number is smaller
then the next expected one. If such a case is encountered,
this is a protocol violation.
Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
Diffstat (limited to 'net/sctp/sm_statefuns.c')
-rw-r--r-- | net/sctp/sm_statefuns.c | 28 |
1 files changed, 26 insertions, 2 deletions
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index a7f18a352364..c8fae1983dd1 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c | |||
@@ -2891,6 +2891,9 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const struct sctp_endpoint *ep, | |||
2891 | goto discard_force; | 2891 | goto discard_force; |
2892 | case SCTP_IERROR_NO_DATA: | 2892 | case SCTP_IERROR_NO_DATA: |
2893 | goto consume; | 2893 | goto consume; |
2894 | case SCTP_IERROR_PROTO_VIOLATION: | ||
2895 | return sctp_sf_abort_violation(ep, asoc, chunk, commands, | ||
2896 | (u8 *)chunk->subh.data_hdr, sizeof(sctp_datahdr_t)); | ||
2894 | default: | 2897 | default: |
2895 | BUG(); | 2898 | BUG(); |
2896 | } | 2899 | } |
@@ -3001,6 +3004,9 @@ sctp_disposition_t sctp_sf_eat_data_fast_4_4(const struct sctp_endpoint *ep, | |||
3001 | break; | 3004 | break; |
3002 | case SCTP_IERROR_NO_DATA: | 3005 | case SCTP_IERROR_NO_DATA: |
3003 | goto consume; | 3006 | goto consume; |
3007 | case SCTP_IERROR_PROTO_VIOLATION: | ||
3008 | return sctp_sf_abort_violation(ep, asoc, chunk, commands, | ||
3009 | (u8 *)chunk->subh.data_hdr, sizeof(sctp_datahdr_t)); | ||
3004 | default: | 3010 | default: |
3005 | BUG(); | 3011 | BUG(); |
3006 | } | 3012 | } |
@@ -5877,6 +5883,9 @@ static int sctp_eat_data(const struct sctp_association *asoc, | |||
5877 | __u32 tsn; | 5883 | __u32 tsn; |
5878 | struct sctp_tsnmap *map = (struct sctp_tsnmap *)&asoc->peer.tsn_map; | 5884 | struct sctp_tsnmap *map = (struct sctp_tsnmap *)&asoc->peer.tsn_map; |
5879 | struct sock *sk = asoc->base.sk; | 5885 | struct sock *sk = asoc->base.sk; |
5886 | u16 ssn; | ||
5887 | u16 sid; | ||
5888 | u8 ordered = 0; | ||
5880 | 5889 | ||
5881 | data_hdr = chunk->subh.data_hdr = (sctp_datahdr_t *)chunk->skb->data; | 5890 | data_hdr = chunk->subh.data_hdr = (sctp_datahdr_t *)chunk->skb->data; |
5882 | skb_pull(chunk->skb, sizeof(sctp_datahdr_t)); | 5891 | skb_pull(chunk->skb, sizeof(sctp_datahdr_t)); |
@@ -6016,8 +6025,10 @@ static int sctp_eat_data(const struct sctp_association *asoc, | |||
6016 | */ | 6025 | */ |
6017 | if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) | 6026 | if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) |
6018 | SCTP_INC_STATS(SCTP_MIB_INUNORDERCHUNKS); | 6027 | SCTP_INC_STATS(SCTP_MIB_INUNORDERCHUNKS); |
6019 | else | 6028 | else { |
6020 | SCTP_INC_STATS(SCTP_MIB_INORDERCHUNKS); | 6029 | SCTP_INC_STATS(SCTP_MIB_INORDERCHUNKS); |
6030 | ordered = 1; | ||
6031 | } | ||
6021 | 6032 | ||
6022 | /* RFC 2960 6.5 Stream Identifier and Stream Sequence Number | 6033 | /* RFC 2960 6.5 Stream Identifier and Stream Sequence Number |
6023 | * | 6034 | * |
@@ -6027,7 +6038,8 @@ static int sctp_eat_data(const struct sctp_association *asoc, | |||
6027 | * with cause set to "Invalid Stream Identifier" (See Section 3.3.10) | 6038 | * with cause set to "Invalid Stream Identifier" (See Section 3.3.10) |
6028 | * and discard the DATA chunk. | 6039 | * and discard the DATA chunk. |
6029 | */ | 6040 | */ |
6030 | if (ntohs(data_hdr->stream) >= asoc->c.sinit_max_instreams) { | 6041 | sid = ntohs(data_hdr->stream); |
6042 | if (sid >= asoc->c.sinit_max_instreams) { | ||
6031 | /* Mark tsn as received even though we drop it */ | 6043 | /* Mark tsn as received even though we drop it */ |
6032 | sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_TSN, SCTP_U32(tsn)); | 6044 | sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_TSN, SCTP_U32(tsn)); |
6033 | 6045 | ||
@@ -6040,6 +6052,18 @@ static int sctp_eat_data(const struct sctp_association *asoc, | |||
6040 | return SCTP_IERROR_BAD_STREAM; | 6052 | return SCTP_IERROR_BAD_STREAM; |
6041 | } | 6053 | } |
6042 | 6054 | ||
6055 | /* Check to see if the SSN is possible for this TSN. | ||
6056 | * The biggest gap we can record is 4K wide. Since SSNs wrap | ||
6057 | * at an unsigned short, there is no way that an SSN can | ||
6058 | * wrap and for a valid TSN. We can simply check if the current | ||
6059 | * SSN is smaller then the next expected one. If it is, it wrapped | ||
6060 | * and is invalid. | ||
6061 | */ | ||
6062 | ssn = ntohs(data_hdr->ssn); | ||
6063 | if (ordered && SSN_lt(ssn, sctp_ssn_peek(&asoc->ssnmap->in, sid))) { | ||
6064 | return SCTP_IERROR_PROTO_VIOLATION; | ||
6065 | } | ||
6066 | |||
6043 | /* Send the data up to the user. Note: Schedule the | 6067 | /* Send the data up to the user. Note: Schedule the |
6044 | * SCTP_CMD_CHUNK_ULP cmd before the SCTP_CMD_GEN_SACK, as the SACK | 6068 | * SCTP_CMD_CHUNK_ULP cmd before the SCTP_CMD_GEN_SACK, as the SACK |
6045 | * chunk needs the updated rwnd. | 6069 | * chunk needs the updated rwnd. |