Skip to content

Commit

Permalink
sctp: fix the processing for INIT chunk
Browse files Browse the repository at this point in the history
This patch fixes the problems below:

1. In non-shutdown_ack_sent states: in sctp_sf_do_5_1B_init() and
   sctp_sf_do_5_2_2_dupinit():

  chunk length check should be done before any checks that may cause
  to send abort, as making packet for abort will access the init_tag
  from init_hdr in sctp_ootb_pkt_new().

2. In shutdown_ack_sent state: in sctp_sf_do_9_2_reshutack():

  The same checks as does in sctp_sf_do_5_2_2_dupinit() is needed
  for sctp_sf_do_9_2_reshutack().

Fixes: 1da177e ("Linux-2.6.12-rc2")
Signed-off-by: Xin Long <[email protected]>
Acked-by: Marcelo Ricardo Leitner <[email protected]>
Signed-off-by: Jakub Kicinski <[email protected]>
  • Loading branch information
lxin authored and kuba-moo committed Oct 22, 2021
1 parent 4f7019c commit eae5783
Showing 1 changed file with 46 additions and 26 deletions.
72 changes: 46 additions & 26 deletions net/sctp/sm_statefuns.c
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,12 @@ static enum sctp_disposition __sctp_sf_do_9_1_abort(
void *arg,
struct sctp_cmd_seq *commands);

static enum sctp_disposition
__sctp_sf_do_9_2_reshutack(struct net *net, const struct sctp_endpoint *ep,
const struct sctp_association *asoc,
const union sctp_subtype type, void *arg,
struct sctp_cmd_seq *commands);

/* Small helper function that checks if the chunk length
* is of the appropriate length. The 'required_length' argument
* is set to be the size of a specific chunk we are testing.
Expand Down Expand Up @@ -337,6 +343,14 @@ enum sctp_disposition sctp_sf_do_5_1B_init(struct net *net,
if (!chunk->singleton)
return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);

/* Make sure that the INIT chunk has a valid length.
* Normally, this would cause an ABORT with a Protocol Violation
* error, but since we don't have an association, we'll
* just discard the packet.
*/
if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_init_chunk)))
return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);

/* If the packet is an OOTB packet which is temporarily on the
* control endpoint, respond with an ABORT.
*/
Expand All @@ -351,14 +365,6 @@ enum sctp_disposition sctp_sf_do_5_1B_init(struct net *net,
if (chunk->sctp_hdr->vtag != 0)
return sctp_sf_tabort_8_4_8(net, ep, asoc, type, arg, commands);

/* Make sure that the INIT chunk has a valid length.
* Normally, this would cause an ABORT with a Protocol Violation
* error, but since we don't have an association, we'll
* just discard the packet.
*/
if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_init_chunk)))
return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);

/* If the INIT is coming toward a closing socket, we'll send back
* and ABORT. Essentially, this catches the race of INIT being
* backloged to the socket at the same time as the user issues close().
Expand Down Expand Up @@ -1524,20 +1530,16 @@ static enum sctp_disposition sctp_sf_do_unexpected_init(
if (!chunk->singleton)
return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);

/* Make sure that the INIT chunk has a valid length. */
if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_init_chunk)))
return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);

/* 3.1 A packet containing an INIT chunk MUST have a zero Verification
* Tag.
*/
if (chunk->sctp_hdr->vtag != 0)
return sctp_sf_tabort_8_4_8(net, ep, asoc, type, arg, commands);

/* Make sure that the INIT chunk has a valid length.
* In this case, we generate a protocol violation since we have
* an association established.
*/
if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_init_chunk)))
return sctp_sf_violation_chunklen(net, ep, asoc, type, arg,
commands);

if (SCTP_INPUT_CB(chunk->skb)->encap_port != chunk->transport->encap_port)
return sctp_sf_new_encap_port(net, ep, asoc, type, arg, commands);

Expand Down Expand Up @@ -1882,9 +1884,9 @@ static enum sctp_disposition sctp_sf_do_dupcook_a(
* its peer.
*/
if (sctp_state(asoc, SHUTDOWN_ACK_SENT)) {
disposition = sctp_sf_do_9_2_reshutack(net, ep, asoc,
SCTP_ST_CHUNK(chunk->chunk_hdr->type),
chunk, commands);
disposition = __sctp_sf_do_9_2_reshutack(net, ep, asoc,
SCTP_ST_CHUNK(chunk->chunk_hdr->type),
chunk, commands);
if (SCTP_DISPOSITION_NOMEM == disposition)
goto nomem;

Expand Down Expand Up @@ -2970,13 +2972,11 @@ enum sctp_disposition sctp_sf_do_9_2_shut_ctsn(
* that belong to this association, it should discard the INIT chunk and
* retransmit the SHUTDOWN ACK chunk.
*/
enum sctp_disposition sctp_sf_do_9_2_reshutack(
struct net *net,
const struct sctp_endpoint *ep,
const struct sctp_association *asoc,
const union sctp_subtype type,
void *arg,
struct sctp_cmd_seq *commands)
static enum sctp_disposition
__sctp_sf_do_9_2_reshutack(struct net *net, const struct sctp_endpoint *ep,
const struct sctp_association *asoc,
const union sctp_subtype type, void *arg,
struct sctp_cmd_seq *commands)
{
struct sctp_chunk *chunk = arg;
struct sctp_chunk *reply;
Expand Down Expand Up @@ -3010,6 +3010,26 @@ enum sctp_disposition sctp_sf_do_9_2_reshutack(
return SCTP_DISPOSITION_NOMEM;
}

enum sctp_disposition
sctp_sf_do_9_2_reshutack(struct net *net, const struct sctp_endpoint *ep,
const struct sctp_association *asoc,
const union sctp_subtype type, void *arg,
struct sctp_cmd_seq *commands)
{
struct sctp_chunk *chunk = arg;

if (!chunk->singleton)
return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);

if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_init_chunk)))
return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);

if (chunk->sctp_hdr->vtag != 0)
return sctp_sf_tabort_8_4_8(net, ep, asoc, type, arg, commands);

return __sctp_sf_do_9_2_reshutack(net, ep, asoc, type, arg, commands);
}

/*
* sctp_sf_do_ecn_cwr
*
Expand Down

0 comments on commit eae5783

Please sign in to comment.