sctp: fix the processing for INIT chunk
commit eae5783908042a762c24e1bd11876edb91d314b1 upstream.
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: 1da177e4c3
("Linux-2.6.12-rc2")
Signed-off-by: Xin Long <lucien.xin@gmail.com>
Acked-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Ovidiu Panait <ovidiu.panait@windriver.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:

committed by
Greg Kroah-Hartman

parent
bdf0316982
commit
6056abc99b
@@ -149,6 +149,12 @@ static enum sctp_disposition __sctp_sf_do_9_1_abort(
|
|||||||
void *arg,
|
void *arg,
|
||||||
struct sctp_cmd_seq *commands);
|
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
|
/* Small helper function that checks if the chunk length
|
||||||
* is of the appropriate length. The 'required_length' argument
|
* is of the appropriate length. The 'required_length' argument
|
||||||
* is set to be the size of a specific chunk we are testing.
|
* is set to be the size of a specific chunk we are testing.
|
||||||
@@ -330,6 +336,14 @@ enum sctp_disposition sctp_sf_do_5_1B_init(struct net *net,
|
|||||||
if (!chunk->singleton)
|
if (!chunk->singleton)
|
||||||
return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
|
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
|
/* If the packet is an OOTB packet which is temporarily on the
|
||||||
* control endpoint, respond with an ABORT.
|
* control endpoint, respond with an ABORT.
|
||||||
*/
|
*/
|
||||||
@@ -344,14 +358,6 @@ enum sctp_disposition sctp_sf_do_5_1B_init(struct net *net,
|
|||||||
if (chunk->sctp_hdr->vtag != 0)
|
if (chunk->sctp_hdr->vtag != 0)
|
||||||
return sctp_sf_tabort_8_4_8(net, ep, asoc, type, arg, commands);
|
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
|
/* If the INIT is coming toward a closing socket, we'll send back
|
||||||
* and ABORT. Essentially, this catches the race of INIT being
|
* and ABORT. Essentially, this catches the race of INIT being
|
||||||
* backloged to the socket at the same time as the user isses close().
|
* backloged to the socket at the same time as the user isses close().
|
||||||
@@ -1484,19 +1490,16 @@ static enum sctp_disposition sctp_sf_do_unexpected_init(
|
|||||||
if (!chunk->singleton)
|
if (!chunk->singleton)
|
||||||
return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
|
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
|
/* 3.1 A packet containing an INIT chunk MUST have a zero Verification
|
||||||
* Tag.
|
* Tag.
|
||||||
*/
|
*/
|
||||||
if (chunk->sctp_hdr->vtag != 0)
|
if (chunk->sctp_hdr->vtag != 0)
|
||||||
return sctp_sf_tabort_8_4_8(net, ep, asoc, type, arg, commands);
|
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);
|
|
||||||
/* Grab the INIT header. */
|
/* Grab the INIT header. */
|
||||||
chunk->subh.init_hdr = (struct sctp_inithdr *)chunk->skb->data;
|
chunk->subh.init_hdr = (struct sctp_inithdr *)chunk->skb->data;
|
||||||
|
|
||||||
@@ -1814,9 +1817,9 @@ static enum sctp_disposition sctp_sf_do_dupcook_a(
|
|||||||
* its peer.
|
* its peer.
|
||||||
*/
|
*/
|
||||||
if (sctp_state(asoc, SHUTDOWN_ACK_SENT)) {
|
if (sctp_state(asoc, SHUTDOWN_ACK_SENT)) {
|
||||||
disposition = sctp_sf_do_9_2_reshutack(net, ep, asoc,
|
disposition = __sctp_sf_do_9_2_reshutack(net, ep, asoc,
|
||||||
SCTP_ST_CHUNK(chunk->chunk_hdr->type),
|
SCTP_ST_CHUNK(chunk->chunk_hdr->type),
|
||||||
chunk, commands);
|
chunk, commands);
|
||||||
if (SCTP_DISPOSITION_NOMEM == disposition)
|
if (SCTP_DISPOSITION_NOMEM == disposition)
|
||||||
goto nomem;
|
goto nomem;
|
||||||
|
|
||||||
@@ -2915,13 +2918,11 @@ enum sctp_disposition sctp_sf_do_9_2_shut_ctsn(
|
|||||||
* that belong to this association, it should discard the INIT chunk and
|
* that belong to this association, it should discard the INIT chunk and
|
||||||
* retransmit the SHUTDOWN ACK chunk.
|
* retransmit the SHUTDOWN ACK chunk.
|
||||||
*/
|
*/
|
||||||
enum sctp_disposition sctp_sf_do_9_2_reshutack(
|
static enum sctp_disposition
|
||||||
struct net *net,
|
__sctp_sf_do_9_2_reshutack(struct net *net, const struct sctp_endpoint *ep,
|
||||||
const struct sctp_endpoint *ep,
|
const struct sctp_association *asoc,
|
||||||
const struct sctp_association *asoc,
|
const union sctp_subtype type, void *arg,
|
||||||
const union sctp_subtype type,
|
struct sctp_cmd_seq *commands)
|
||||||
void *arg,
|
|
||||||
struct sctp_cmd_seq *commands)
|
|
||||||
{
|
{
|
||||||
struct sctp_chunk *chunk = arg;
|
struct sctp_chunk *chunk = arg;
|
||||||
struct sctp_chunk *reply;
|
struct sctp_chunk *reply;
|
||||||
@@ -2955,6 +2956,26 @@ nomem:
|
|||||||
return SCTP_DISPOSITION_NOMEM;
|
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
|
* sctp_sf_do_ecn_cwr
|
||||||
*
|
*
|
||||||
|
Reference in New Issue
Block a user