Skip to content

Commit 9d4ceaf

Browse files
lxindavem330
authored andcommitted
sctp: implement validate_data for sctp_stream_interleave
validate_data is added as a member of sctp_stream_interleave, used to validate ssn/chunk type for data or mid (message id)/chunk type for idata, called in sctp_eat_data. If this check fails, an abort packet will be sent, as said in section 2.2.3 of RFC8260. It also adds the process for idata in rx path. As Marcelo pointed out, there's no need to add event table for idata, but just share chunk_event_table with data's. It would drop data chunk for idata and drop idata chunk for data by calling validate_data in sctp_eat_data. As last patch did, it also replaces sizeof(struct sctp_data_chunk) with sctp_datachk_len for rx path. After this patch, the idata can be accepted and delivered to ulp layer. Signed-off-by: Xin Long <[email protected]> Acked-by: Marcelo Ricardo Leitner <[email protected]> Acked-by: Neil Horman <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 668c9be commit 9d4ceaf

File tree

6 files changed

+62
-14
lines changed

6 files changed

+62
-14
lines changed

include/net/sctp/sm.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,12 @@ static inline __u16 sctp_data_size(struct sctp_chunk *chunk)
359359
typecheck(__u32, b) && \
360360
((__s32)((a) - (b)) <= 0))
361361

362+
/* Compare two MIDs */
363+
#define MID_lt(a, b) \
364+
(typecheck(__u32, a) && \
365+
typecheck(__u32, b) && \
366+
((__s32)((a) - (b)) < 0))
367+
362368
/* Compare two SSNs */
363369
#define SSN_lt(a,b) \
364370
(typecheck(__u16, a) && \

include/net/sctp/stream_interleave.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ struct sctp_stream_interleave {
3838
const struct sctp_sndrcvinfo *sinfo,
3939
int len, __u8 flags, gfp_t gfp);
4040
void (*assign_number)(struct sctp_chunk *chunk);
41+
bool (*validate_data)(struct sctp_chunk *chunk);
4142
};
4243

4344
void sctp_stream_interleave_init(struct sctp_stream *stream);

include/net/sctp/structs.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1382,7 +1382,11 @@ struct sctp_stream_out {
13821382
};
13831383

13841384
struct sctp_stream_in {
1385-
__u16 ssn;
1385+
union {
1386+
__u32 mid;
1387+
__u16 ssn;
1388+
};
1389+
__u32 fsn;
13861390
};
13871391

13881392
struct sctp_stream {

net/sctp/sm_statefuns.c

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3013,7 +3013,7 @@ enum sctp_disposition sctp_sf_eat_data_6_2(struct net *net,
30133013
return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
30143014
}
30153015

3016-
if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_data_chunk)))
3016+
if (!sctp_chunk_length_valid(chunk, sctp_datachk_len(&asoc->stream)))
30173017
return sctp_sf_violation_chunklen(net, ep, asoc, type, arg,
30183018
commands);
30193019

@@ -3034,7 +3034,7 @@ enum sctp_disposition sctp_sf_eat_data_6_2(struct net *net,
30343034
case SCTP_IERROR_PROTO_VIOLATION:
30353035
return sctp_sf_abort_violation(net, ep, asoc, chunk, commands,
30363036
(u8 *)chunk->subh.data_hdr,
3037-
sizeof(struct sctp_datahdr));
3037+
sctp_datahdr_len(&asoc->stream));
30383038
default:
30393039
BUG();
30403040
}
@@ -3133,7 +3133,7 @@ enum sctp_disposition sctp_sf_eat_data_fast_4_4(
31333133
return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
31343134
}
31353135

3136-
if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_data_chunk)))
3136+
if (!sctp_chunk_length_valid(chunk, sctp_datachk_len(&asoc->stream)))
31373137
return sctp_sf_violation_chunklen(net, ep, asoc, type, arg,
31383138
commands);
31393139

@@ -3150,7 +3150,7 @@ enum sctp_disposition sctp_sf_eat_data_fast_4_4(
31503150
case SCTP_IERROR_PROTO_VIOLATION:
31513151
return sctp_sf_abort_violation(net, ep, asoc, chunk, commands,
31523152
(u8 *)chunk->subh.data_hdr,
3153-
sizeof(struct sctp_datahdr));
3153+
sctp_datahdr_len(&asoc->stream));
31543154
default:
31553155
BUG();
31563156
}
@@ -6244,14 +6244,12 @@ static int sctp_eat_data(const struct sctp_association *asoc,
62446244
struct sctp_chunk *err;
62456245
enum sctp_verb deliver;
62466246
size_t datalen;
6247-
u8 ordered = 0;
6248-
u16 ssn, sid;
62496247
__u32 tsn;
62506248
int tmp;
62516249

62526250
data_hdr = (struct sctp_datahdr *)chunk->skb->data;
62536251
chunk->subh.data_hdr = data_hdr;
6254-
skb_pull(chunk->skb, sizeof(*data_hdr));
6252+
skb_pull(chunk->skb, sctp_datahdr_len(&asoc->stream));
62556253

62566254
tsn = ntohl(data_hdr->tsn);
62576255
pr_debug("%s: TSN 0x%x\n", __func__, tsn);
@@ -6299,7 +6297,7 @@ static int sctp_eat_data(const struct sctp_association *asoc,
62996297
* Actually, allow a little bit of overflow (up to a MTU).
63006298
*/
63016299
datalen = ntohs(chunk->chunk_hdr->length);
6302-
datalen -= sizeof(struct sctp_data_chunk);
6300+
datalen -= sctp_datachk_len(&asoc->stream);
63036301

63046302
deliver = SCTP_CMD_CHUNK_ULP;
63056303

@@ -6394,7 +6392,6 @@ static int sctp_eat_data(const struct sctp_association *asoc,
63946392
SCTP_INC_STATS(net, SCTP_MIB_INORDERCHUNKS);
63956393
if (chunk->asoc)
63966394
chunk->asoc->stats.iodchunks++;
6397-
ordered = 1;
63986395
}
63996396

64006397
/* RFC 2960 6.5 Stream Identifier and Stream Sequence Number
@@ -6405,8 +6402,7 @@ static int sctp_eat_data(const struct sctp_association *asoc,
64056402
* with cause set to "Invalid Stream Identifier" (See Section 3.3.10)
64066403
* and discard the DATA chunk.
64076404
*/
6408-
sid = ntohs(data_hdr->stream);
6409-
if (sid >= asoc->stream.incnt) {
6405+
if (ntohs(data_hdr->stream) >= asoc->stream.incnt) {
64106406
/* Mark tsn as received even though we drop it */
64116407
sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_TSN, SCTP_U32(tsn));
64126408

@@ -6427,8 +6423,7 @@ static int sctp_eat_data(const struct sctp_association *asoc,
64276423
* SSN is smaller then the next expected one. If it is, it wrapped
64286424
* and is invalid.
64296425
*/
6430-
ssn = ntohs(data_hdr->ssn);
6431-
if (ordered && SSN_lt(ssn, sctp_ssn_peek(&asoc->stream, in, sid)))
6426+
if (!asoc->stream.si->validate_data(chunk))
64326427
return SCTP_IERROR_PROTO_VIOLATION;
64336428

64346429
/* Send the data up to the user. Note: Schedule the

net/sctp/sm_statetable.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -985,6 +985,9 @@ static const struct sctp_sm_table_entry *sctp_chunk_event_lookup(
985985
if (state > SCTP_STATE_MAX)
986986
return &bug;
987987

988+
if (net->sctp.intl_enable && cid == SCTP_CID_I_DATA)
989+
cid = SCTP_CID_DATA;
990+
988991
if (cid <= SCTP_CID_BASE_MAX)
989992
return &chunk_event_table[cid][state];
990993

net/sctp/stream_interleave.c

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,18 +92,57 @@ static void sctp_chunk_assign_mid(struct sctp_chunk *chunk)
9292
}
9393
}
9494

95+
static bool sctp_validate_data(struct sctp_chunk *chunk)
96+
{
97+
const struct sctp_stream *stream;
98+
__u16 sid, ssn;
99+
100+
if (chunk->chunk_hdr->type != SCTP_CID_DATA)
101+
return false;
102+
103+
if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED)
104+
return true;
105+
106+
stream = &chunk->asoc->stream;
107+
sid = sctp_chunk_stream_no(chunk);
108+
ssn = ntohs(chunk->subh.data_hdr->ssn);
109+
110+
return !SSN_lt(ssn, sctp_ssn_peek(stream, in, sid));
111+
}
112+
113+
static bool sctp_validate_idata(struct sctp_chunk *chunk)
114+
{
115+
struct sctp_stream *stream;
116+
__u32 mid;
117+
__u16 sid;
118+
119+
if (chunk->chunk_hdr->type != SCTP_CID_I_DATA)
120+
return false;
121+
122+
if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED)
123+
return true;
124+
125+
stream = &chunk->asoc->stream;
126+
sid = sctp_chunk_stream_no(chunk);
127+
mid = ntohl(chunk->subh.idata_hdr->mid);
128+
129+
return !MID_lt(mid, sctp_mid_peek(stream, in, sid));
130+
}
131+
95132
static struct sctp_stream_interleave sctp_stream_interleave_0 = {
96133
.data_chunk_len = sizeof(struct sctp_data_chunk),
97134
/* DATA process functions */
98135
.make_datafrag = sctp_make_datafrag_empty,
99136
.assign_number = sctp_chunk_assign_ssn,
137+
.validate_data = sctp_validate_data,
100138
};
101139

102140
static struct sctp_stream_interleave sctp_stream_interleave_1 = {
103141
.data_chunk_len = sizeof(struct sctp_idata_chunk),
104142
/* I-DATA process functions */
105143
.make_datafrag = sctp_make_idatafrag_empty,
106144
.assign_number = sctp_chunk_assign_mid,
145+
.validate_data = sctp_validate_idata,
107146
};
108147

109148
void sctp_stream_interleave_init(struct sctp_stream *stream)

0 commit comments

Comments
 (0)