Skip to content

Commit 2e3216c

Browse files
Vlad Yasevichdavem330
authored andcommitted
sctp: Follow security requirement of responding with 1 packet
RFC 4960, Section 11.4. Protection of Non-SCTP-Capable Hosts When an SCTP stack receives a packet containing multiple control or DATA chunks and the processing of the packet requires the sending of multiple chunks in response, the sender of the response chunk(s) MUST NOT send more than one packet. If bundling is supported, multiple response chunks that fit into a single packet MAY be bundled together into one single response packet. If bundling is not supported, then the sender MUST NOT send more than one response chunk and MUST discard all other responses. Note that this rule does NOT apply to a SACK chunk, since a SACK chunk is, in itself, a response to DATA and a SACK does not require a response of more DATA. We implement this by not servicing our outqueue until we reach the end of the packet. This enables maximum bundling. We also identify 'response' chunks and make sure that we only send 1 packet when sending such chunks. Signed-off-by: Vlad Yasevich <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 7115e63 commit 2e3216c

File tree

6 files changed

+54
-33
lines changed

6 files changed

+54
-33
lines changed

include/net/sctp/structs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -827,7 +827,7 @@ struct sctp_packet *sctp_packet_init(struct sctp_packet *,
827827
__u16 sport, __u16 dport);
828828
struct sctp_packet *sctp_packet_config(struct sctp_packet *, __u32 vtag, int);
829829
sctp_xmit_t sctp_packet_transmit_chunk(struct sctp_packet *,
830-
struct sctp_chunk *);
830+
struct sctp_chunk *, int);
831831
sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *,
832832
struct sctp_chunk *);
833833
int sctp_packet_transmit(struct sctp_packet *);

net/sctp/associola.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1025,6 +1025,7 @@ static void sctp_assoc_bh_rcv(struct work_struct *work)
10251025
struct sctp_chunk *chunk;
10261026
struct sock *sk;
10271027
struct sctp_inq *inqueue;
1028+
struct sctp_outq *outq;
10281029
int state;
10291030
sctp_subtype_t subtype;
10301031
int error = 0;

net/sctp/output.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,8 @@ void sctp_packet_free(struct sctp_packet *packet)
157157
* packet can be sent only after receiving the COOKIE_ACK.
158158
*/
159159
sctp_xmit_t sctp_packet_transmit_chunk(struct sctp_packet *packet,
160-
struct sctp_chunk *chunk)
160+
struct sctp_chunk *chunk,
161+
int one_packet)
161162
{
162163
sctp_xmit_t retval;
163164
int error = 0;
@@ -175,7 +176,9 @@ sctp_xmit_t sctp_packet_transmit_chunk(struct sctp_packet *packet,
175176
/* If we have an empty packet, then we can NOT ever
176177
* return PMTU_FULL.
177178
*/
178-
retval = sctp_packet_append_chunk(packet, chunk);
179+
if (!one_packet)
180+
retval = sctp_packet_append_chunk(packet,
181+
chunk);
179182
}
180183
break;
181184

net/sctp/outqueue.c

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -702,6 +702,7 @@ int sctp_outq_uncork(struct sctp_outq *q)
702702
return error;
703703
}
704704

705+
705706
/*
706707
* Try to flush an outqueue.
707708
*
@@ -725,6 +726,7 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
725726
sctp_xmit_t status;
726727
int error = 0;
727728
int start_timer = 0;
729+
int one_packet = 0;
728730

729731
/* These transports have chunks to send. */
730732
struct list_head transport_list;
@@ -830,20 +832,33 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
830832
if (sctp_test_T_bit(chunk)) {
831833
packet->vtag = asoc->c.my_vtag;
832834
}
833-
case SCTP_CID_SACK:
834-
case SCTP_CID_HEARTBEAT:
835+
/* The following chunks are "response" chunks, i.e.
836+
* they are generated in response to something we
837+
* received. If we are sending these, then we can
838+
* send only 1 packet containing these chunks.
839+
*/
835840
case SCTP_CID_HEARTBEAT_ACK:
836-
case SCTP_CID_SHUTDOWN:
837841
case SCTP_CID_SHUTDOWN_ACK:
838-
case SCTP_CID_ERROR:
839-
case SCTP_CID_COOKIE_ECHO:
840842
case SCTP_CID_COOKIE_ACK:
841-
case SCTP_CID_ECN_ECNE:
843+
case SCTP_CID_COOKIE_ECHO:
844+
case SCTP_CID_ERROR:
842845
case SCTP_CID_ECN_CWR:
843-
case SCTP_CID_ASCONF:
844846
case SCTP_CID_ASCONF_ACK:
847+
one_packet = 1;
848+
/* Fall throught */
849+
850+
case SCTP_CID_SACK:
851+
case SCTP_CID_HEARTBEAT:
852+
case SCTP_CID_SHUTDOWN:
853+
case SCTP_CID_ECN_ECNE:
854+
case SCTP_CID_ASCONF:
845855
case SCTP_CID_FWD_TSN:
846-
sctp_packet_transmit_chunk(packet, chunk);
856+
status = sctp_packet_transmit_chunk(packet, chunk,
857+
one_packet);
858+
if (status != SCTP_XMIT_OK) {
859+
/* put the chunk back */
860+
list_add(&chunk->list, &q->control_chunk_list);
861+
}
847862
break;
848863

849864
default:
@@ -974,7 +989,7 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
974989
atomic_read(&chunk->skb->users) : -1);
975990

976991
/* Add the chunk to the packet. */
977-
status = sctp_packet_transmit_chunk(packet, chunk);
992+
status = sctp_packet_transmit_chunk(packet, chunk, 0);
978993

979994
switch (status) {
980995
case SCTP_XMIT_PMTU_FULL:
@@ -1239,7 +1254,6 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack)
12391254
* Make sure the empty queue handler will get run later.
12401255
*/
12411256
q->empty = (list_empty(&q->out_chunk_list) &&
1242-
list_empty(&q->control_chunk_list) &&
12431257
list_empty(&q->retransmit));
12441258
if (!q->empty)
12451259
goto finish;

net/sctp/sm_sideeffect.c

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -664,19 +664,14 @@ static int sctp_cmd_process_sack(sctp_cmd_seq_t *cmds,
664664
struct sctp_association *asoc,
665665
struct sctp_sackhdr *sackh)
666666
{
667-
int err;
667+
int err = 0;
668668

669669
if (sctp_outq_sack(&asoc->outqueue, sackh)) {
670670
/* There are no more TSNs awaiting SACK. */
671671
err = sctp_do_sm(SCTP_EVENT_T_OTHER,
672672
SCTP_ST_OTHER(SCTP_EVENT_NO_PENDING_TSN),
673673
asoc->state, asoc->ep, asoc, NULL,
674674
GFP_ATOMIC);
675-
} else {
676-
/* Windows may have opened, so we need
677-
* to check if we have DATA to transmit
678-
*/
679-
err = sctp_outq_flush(&asoc->outqueue, 0);
680675
}
681676

682677
return err;
@@ -1481,8 +1476,15 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
14811476
break;
14821477

14831478
case SCTP_CMD_DISCARD_PACKET:
1484-
/* We need to discard the whole packet. */
1479+
/* We need to discard the whole packet.
1480+
* Uncork the queue since there might be
1481+
* responses pending
1482+
*/
14851483
chunk->pdiscard = 1;
1484+
if (asoc) {
1485+
sctp_outq_uncork(&asoc->outqueue);
1486+
local_cork = 0;
1487+
}
14861488
break;
14871489

14881490
case SCTP_CMD_RTO_PENDING:
@@ -1553,8 +1555,15 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
15531555
}
15541556

15551557
out:
1556-
if (local_cork)
1557-
sctp_outq_uncork(&asoc->outqueue);
1558+
/* If this is in response to a received chunk, wait until
1559+
* we are done with the packet to open the queue so that we don't
1560+
* send multiple packets in response to a single request.
1561+
*/
1562+
if (asoc && SCTP_EVENT_T_CHUNK == event_type && chunk) {
1563+
if (chunk->end_of_packet || chunk->singleton)
1564+
sctp_outq_uncork(&asoc->outqueue);
1565+
} else if (local_cork)
1566+
sctp_outq_uncork(&asoc->outqueue);
15581567
return error;
15591568
nomem:
15601569
error = -ENOMEM;

net/sctp/sm_statefuns.c

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -795,8 +795,6 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep,
795795
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START,
796796
SCTP_TO(SCTP_EVENT_TIMEOUT_AUTOCLOSE));
797797

798-
sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL());
799-
800798
/* This will send the COOKIE ACK */
801799
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl));
802800

@@ -883,7 +881,6 @@ sctp_disposition_t sctp_sf_do_5_1E_ca(const struct sctp_endpoint *ep,
883881
if (asoc->autoclose)
884882
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START,
885883
SCTP_TO(SCTP_EVENT_TIMEOUT_AUTOCLOSE));
886-
sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL());
887884

888885
/* It may also notify its ULP about the successful
889886
* establishment of the association with a Communication Up
@@ -1781,7 +1778,6 @@ static sctp_disposition_t sctp_sf_do_dupcook_b(const struct sctp_endpoint *ep,
17811778
goto nomem;
17821779

17831780
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl));
1784-
sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL());
17851781

17861782
/* RFC 2960 5.1 Normal Establishment of an Association
17871783
*
@@ -1898,22 +1894,20 @@ static sctp_disposition_t sctp_sf_do_dupcook_d(const struct sctp_endpoint *ep,
18981894

18991895
}
19001896
}
1901-
sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL());
19021897

19031898
repl = sctp_make_cookie_ack(new_asoc, chunk);
19041899
if (!repl)
19051900
goto nomem;
19061901

1902+
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl));
1903+
19071904
if (ev)
19081905
sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
19091906
SCTP_ULPEVENT(ev));
19101907
if (ai_ev)
19111908
sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
19121909
SCTP_ULPEVENT(ai_ev));
19131910

1914-
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl));
1915-
sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL());
1916-
19171911
return SCTP_DISPOSITION_CONSUME;
19181912

19191913
nomem:
@@ -3970,9 +3964,6 @@ sctp_disposition_t sctp_sf_unk_chunk(const struct sctp_endpoint *ep,
39703964
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
39713965
break;
39723966
case SCTP_CID_ACTION_DISCARD_ERR:
3973-
/* Discard the packet. */
3974-
sctp_sf_pdiscard(ep, asoc, type, arg, commands);
3975-
39763967
/* Generate an ERROR chunk as response. */
39773968
hdr = unk_chunk->chunk_hdr;
39783969
err_chunk = sctp_make_op_error(asoc, unk_chunk,
@@ -3982,6 +3973,9 @@ sctp_disposition_t sctp_sf_unk_chunk(const struct sctp_endpoint *ep,
39823973
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
39833974
SCTP_CHUNK(err_chunk));
39843975
}
3976+
3977+
/* Discard the packet. */
3978+
sctp_sf_pdiscard(ep, asoc, type, arg, commands);
39853979
return SCTP_DISPOSITION_CONSUME;
39863980
break;
39873981
case SCTP_CID_ACTION_SKIP:

0 commit comments

Comments
 (0)