提交 e951cc37 编写于 作者: X Xin Long 提交者: Zheng Zengkai

sctp: fix the processing for INIT chunk

mainline inclusion
from mainline
commit eae57839
bugzilla: 182989 https://gitee.com/openeuler/kernel/issues/I4DDEL
CVE: CVE-2021-3772

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=eae5783908042a762c24e1bd11876edb91d314b1

--------------------------------

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: 1da177e4 ("Linux-2.6.12-rc2")
Signed-off-by: NXin Long <lucien.xin@gmail.com>
Acked-by: NMarcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Signed-off-by: NJakub Kicinski <kuba@kernel.org>
Signed-off-by: NChen Jun <chenjun102@huawei.com>

Conflicts:
	net/sctp/sm_statefuns.c
Reviewed-by: NYue Haibing <yuehaibing@huawei.com>
Reviewed-by: Nweiyang wang <wangweiyang2@huawei.com>
Signed-off-by: NChen Jun <chenjun102@huawei.com>
Signed-off-by: NZheng Zengkai <zhengzengkai@huawei.com>
上级 e4dde1ba
...@@ -149,6 +149,12 @@ static enum sctp_disposition __sctp_sf_do_9_1_abort( ...@@ -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, ...@@ -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, ...@@ -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().
...@@ -1480,19 +1486,16 @@ static enum sctp_disposition sctp_sf_do_unexpected_init( ...@@ -1480,19 +1486,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;
...@@ -1810,9 +1813,9 @@ static enum sctp_disposition sctp_sf_do_dupcook_a( ...@@ -1810,9 +1813,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;
...@@ -2909,13 +2912,11 @@ enum sctp_disposition sctp_sf_do_9_2_shut_ctsn( ...@@ -2909,13 +2912,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;
...@@ -2949,6 +2950,26 @@ enum sctp_disposition sctp_sf_do_9_2_reshutack( ...@@ -2949,6 +2950,26 @@ enum sctp_disposition sctp_sf_do_9_2_reshutack(
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
* *
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册