SCTP: Fix Protocol violation when receiving a error length INIT ACK
Subsystems (3)
PATCH 1/1 SCTP: Fix Protocol violation when receiving a error length INIT ACK
Hi Vlad,
When kernel receives a INIT ACK which has an invalid length, it replies a 0 VerificationTag ABORT. This violates sctp protocol apparently, and doesn't comply to RFC requirement. VerificationTag is allowed to set to 0 only in INIT Chunk packet.
We need to record the VerificationTag from INIT ACK before sending out the ABORT Chunk.
Here is a patch for fixing this bug.
--- include/net/sctp/command.h | 1 + net/sctp/sm_sideeffect.c | 5 ++++- net/sctp/sm_statefuns.c | 9 +++++++++ 3 files changed, 14 insertions(+), 1 deletions(-)
include/net/sctp/command.h +1 -0
@@ -104,6 +104,7 @@ typedef enum {SCTP_CMD_ADAPTATION_IND ,/* generate and send adaptation event */ SCTP_CMD_ASSOC_SHKEY ,/* generate the association shared keys */ SCTP_CMD_T1_RETRAN ,/* Mark for retransmission after T1 timeout */ +SCTP_CMD_UPDATE_INITTAG ,/* Update peer inittag */ SCTP_CMD_LAST } sctp_verb_t;
net/sctp/sm_sideeffect.c +4 -1
@@ -1536,7 +1536,10 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, error =sctp_auth_asoc_init_active_key (asoc,GFP_ATOMIC );break ; - +case SCTP_CMD_UPDATE_INITTAG : + asoc->peer.i.init_tag = cmd->obj.u32; +break ; +default :printk (KERN_WARNING "Impossible command: %u, %p\n" , cmd->verb, cmd->obj.ptr);
net/sctp/sm_statefuns.c +9 -0
@@ -4144,6 +4144,15 @@ static sctp_disposition_t sctp_sf_abort_violation( goto nomem;if (asoc) { +/* Treat INIT-ACK as a special case. */ +if (chunk->chunk_hdr->type ==SCTP_CID_INIT_ACK ) { +sctp_initack_chunk_t *initack; + + initack = (sctp_initack_chunk_t *)chunk->chunk_hdr; +sctp_add_cmd_sf (commands,SCTP_CMD_UPDATE_INITTAG , +SCTP_U32 (ntohl (initack->init_hdr.init_tag))); + } +sctp_add_cmd_sf (commands,SCTP_CMD_REPLY ,SCTP_CHUNK (abort));SCTP_INC_STATS (SCTP_MIB_OUTCTRLCHUNKS );
Signature · 1 line
1.5.3
Wei Yongjun
NAKNACK.
If the INIT-ACK chunk is too short to contain the init-tag, get the init-tag of peer may get a unexpected value. Such as this:
CHUNK_INIT_ACK
Type = 2 Flags = 0 Length = 4
So I think the better way is to set T bit of ABORT chunk and used the own's Tag.
Regards.
Wei Yongjun
Quoted 62 lines · Gui Jianfeng
Hi Vlad,
When kernel receives a INIT ACK which has an invalid length, it replies a 0 VerificationTag ABORT.
This violates sctp protocol apparently, and doesn't comply to RFC requirement. VerificationTag is allowed to set to 0 only in INIT Chunk packet. We need to record the VerificationTag from INIT ACK before sending out the ABORT Chunk.Here is a patch for fixing this bug.
Signed-off-by Guijianfeng <[email protected]>--- include/net/sctp/command.h | 1 + net/sctp/sm_sideeffect.c | 5 ++++- net/sctp/sm_statefuns.c | 9 +++++++++ 3 files changed, 14 insertions(+), 1 deletions(-)include/net/sctp/command.h +1
-0@@ -104,6 +104,7 @@ typedef enum {SCTP_CMD_ADAPTATION_IND ,/* generate and send adaptation event */ SCTP_CMD_ASSOC_SHKEY ,/* generate the association shared keys */ SCTP_CMD_T1_RETRAN ,/* Mark for retransmission after T1 timeout */ +SCTP_CMD_UPDATE_INITTAG ,/* Update peer inittag */ SCTP_CMD_LAST } sctp_verb_t;net/sctp/sm_sideeffect.c +4
-1@@ -1536,7 +1536,10 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, error =sctp_auth_asoc_init_active_key (asoc,GFP_ATOMIC );break ; - +case SCTP_CMD_UPDATE_INITTAG : + asoc->peer.i.init_tag = cmd->obj.u32; +break ; +default :printk (KERN_WARNING "Impossible command: %u, %p\n" , cmd->verb, cmd->obj.ptr);net/sctp/sm_statefuns.c +9
-0@@ -4144,6 +4144,15 @@ static sctp_disposition_t sctp_sf_abort_violation( goto nomem;if (asoc) { +/* Treat INIT-ACK as a special case. */ +if (chunk->chunk_hdr->type ==SCTP_CID_INIT_ACK ) { +sctp_initack_chunk_t *initack; + + initack = (sctp_initack_chunk_t *)chunk->chunk_hdr; +sctp_add_cmd_sf (commands,SCTP_CMD_UPDATE_INITTAG , +SCTP_U32 (ntohl (initack->init_hdr.init_tag))); + } +sctp_add_cmd_sf (commands,SCTP_CMD_REPLY ,SCTP_CHUNK (abort));SCTP_INC_STATS (SCTP_MIB_OUTCTRLCHUNKS );
Quoted 6 lines · Wei Yongjun
NACK.
If the INIT-ACK chunk is too short to contain the init-tag, get the init-tag of peer may get a unexpected value.
Such as this:
CHUNK_INIT_ACK
Quoted 6 lines
Type = 2 Flags = 0 Length = 4So I think the better way is to set T bit of ABORT chunk and used the own's Tag.
Seems reasonable. Please ignore the previous one, here is a new patch.
--- net/sctp/outqueue.c | 3 +++ net/sctp/sm_statefuns.c | 5 +++++ 2 files changed, 8 insertions(+), 0 deletions(-)
net/sctp/outqueue.c +3 -0
@@ -793,6 +793,9 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)break ;case SCTP_CID_ABORT : +if (sctp_test_T_bit (chunk)) { + packet->vtag = asoc->c.my_vtag; + }case SCTP_CID_SACK :case SCTP_CID_HEARTBEAT :case SCTP_CID_HEARTBEAT_ACK :
net/sctp/sm_statefuns.c +5 -0
@@ -4144,6 +4144,11 @@ static sctp_disposition_t sctp_sf_abort_violation( goto nomem;if (asoc) { +/* Treat INIT-ACK as a special case. */ +if (chunk->chunk_hdr->type ==SCTP_CID_INIT_ACK ) { + abort->chunk_hdr->flags |=SCTP_CHUNK_FLAG_T ; + } +sctp_add_cmd_sf (commands,SCTP_CMD_REPLY ,SCTP_CHUNK (abort));SCTP_INC_STATS (SCTP_MIB_OUTCTRLCHUNKS );
Signature · 6 lines
1.5.3 -- Regards Gui Jianfeng
Hi Gui:
I looked the source code and found that only in the state *COOKIE_WAIT* received INIT-ACK need to do this, not all of the states. The other states we should have known the init-tag of peer.
Quoted 47 lines · Gui Jianfeng
Quoted 6 lines · Wei Yongjun
NACK.
If the INIT-ACK chunk is too short to contain the init-tag, get the init-tag of peer may get a unexpected value.
Such as this:
CHUNK_INIT_ACKQuoted 7 lines
Type = 2 Flags = 0 Length = 4So I think the better way is to set T bit of ABORT chunk and used the own's Tag.
Seems reasonable. Please ignore the previous one, here is a new patch.
Signed-off-by Gui Jianfeng <[email protected]>--- net/sctp/outqueue.c | 3 +++ net/sctp/sm_statefuns.c | 5 +++++ 2 files changed, 8 insertions(+), 0 deletions(-)net/sctp/outqueue.c +3
-0@@ -793,6 +793,9 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)break ;case SCTP_CID_ABORT : +if (sctp_test_T_bit (chunk)) { + packet->vtag = asoc->c.my_vtag; + }case SCTP_CID_SACK :case SCTP_CID_HEARTBEAT :case SCTP_CID_HEARTBEAT_ACK :net/sctp/sm_statefuns.c +0
-0@@ -4144,6 +4144,11 @@ static sctp_disposition_t sctp_sf_abort_violation( goto nomem;
net/sctp/sm_statefuns.c static sctp_disposition_t sctp_sf_abort_violation( · line 4154
Quoted 10 lines
net/sctp/sm_statefuns.c +5
-0if (asoc) { +/* Treat INIT-ACK as a special case. */ +if (chunk->chunk_hdr->type ==SCTP_CID_INIT_ACK ) { + abort->chunk_hdr->flags |=SCTP_CHUNK_FLAG_T ; + } +sctp_add_cmd_sf (commands,SCTP_CMD_REPLY ,SCTP_CHUNK (abort));SCTP_INC_STATS (SCTP_MIB_OUTCTRLCHUNKS );
Those code should be move to sctp_make_abort <../cgi-bin/global.cgi?pattern=sctp_make_abort&type=reference>() for common using. And may be need check whether we need the T flags.
Quoted 5 lines · Wei Yongjun
Hi Gui:
I looked the source code and found that only in the state *COOKIE_WAIT* received INIT-ACK need to do this, not all of the states. The other states we should have known the init-tag of peer.
yes, it's the only possibility.
Quoted 50 lines
Quoted 48 lines · Gui Jianfeng
Quoted 6 lines · Wei Yongjun
NACK.
If the INIT-ACK chunk is too short to contain the init-tag, get the init-tag of peer may get a unexpected value.
Such as this:
CHUNK_INIT_ACKQuoted 7 lines
Type = 2 Flags = 0 Length = 4So I think the better way is to set T bit of ABORT chunk and used the own's Tag.
Seems reasonable. Please ignore the previous one, here is a new patch.
Signed-off-by Gui Jianfeng <[email protected]>--- net/sctp/outqueue.c | 3 +++ net/sctp/sm_statefuns.c | 5 +++++ 2 files changed, 8 insertions(+), 0 deletions(-)net/sctp/outqueue.c +3
-0@@ -793,6 +793,9 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)break ;case SCTP_CID_ABORT : +if (sctp_test_T_bit (chunk)) { + packet->vtag = asoc->c.my_vtag; + }case SCTP_CID_SACK :case SCTP_CID_HEARTBEAT :case
SCTP_CID_HEARTBEAT_ACK:net/sctp/sm_statefuns.c +0
-0@@ -4144,6 +4144,11 @@ static sctp_disposition_t sctp_sf_abort_violation( goto nomem;
Quoted 12 lines
net/sctp/sm_statefuns.c static sctp_disposition_t sctp_sf_abort_violation( · line 4154
Quoted 10 lines
net/sctp/sm_statefuns.c +5
-0if (asoc) { +/* Treat INIT-ACK as a special case. */ +if (chunk->chunk_hdr->type ==SCTP_CID_INIT_ACK ) { + abort->chunk_hdr->flags |=SCTP_CHUNK_FLAG_T ; + } +sctp_add_cmd_sf (commands,SCTP_CMD_REPLY ,SCTP_CHUNK (abort));SCTP_INC_STATS (SCTP_MIB_OUTCTRLCHUNKS );Those code should be move to
sctp_make_abort()for common using. And may be need check whether we need the T flags.
This rarely happens, so i think it's sufficient to place this block of code here. Moving it into sctp_make_abort() will waste much cpu time when generating each abort chunk .
Quoted 4 lines
Signature · 2 lines
Regards Gui Jianfeng
Quoted 67 lines · Gui Jianfeng
Quoted 5 lines · Wei Yongjun
Hi Gui:
I looked the source code and found that only in the state *COOKIE_WAIT* received INIT-ACK need to do this, not all of the states. The other states we should have known the init-tag of peer.
yes, it's the only possibility.
Quoted 47 lines
Quoted 46 lines · Gui Jianfeng
Quoted 6 lines · Wei Yongjun
NACK.
If the INIT-ACK chunk is too short to contain the init-tag, get the init-tag of peer may get a unexpected value.
Such as this:
CHUNK_INIT_ACKQuoted 7 lines
Type = 2 Flags = 0 Length = 4So I think the better way is to set T bit of ABORT chunk and used the own's Tag.
Seems reasonable. Please ignore the previous one, here is a new patch.
Signed-off-by Gui Jianfeng <[email protected]>--- net/sctp/outqueue.c | 3 +++ net/sctp/sm_statefuns.c | 5 +++++ 2 files changed, 8 insertions(+), 0 deletions(-)net/sctp/outqueue.c +3
-0@@ -793,6 +793,9 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)break ;case SCTP_CID_ABORT : +if (sctp_test_T_bit (chunk)) { + packet->vtag = asoc->c.my_vtag; + }case SCTP_CID_SACK :case SCTP_CID_HEARTBEAT :case
SCTP_CID_HEARTBEAT_ACK:net/sctp/sm_statefuns.c +0
-0@@ -4144,6 +4144,11 @@ static sctp_disposition_t sctp_sf_abort_violation( goto nomem;Quoted 12 lines
net/sctp/sm_statefuns.c static sctp_disposition_t sctp_sf_abort_violation( · line 4154
Quoted 10 lines
net/sctp/sm_statefuns.c +5
-0if (asoc) { +/* Treat INIT-ACK as a special case. */ +if (chunk->chunk_hdr->type ==SCTP_CID_INIT_ACK ) { + abort->chunk_hdr->flags |=SCTP_CHUNK_FLAG_T ; + } +sctp_add_cmd_sf (commands,SCTP_CMD_REPLY ,SCTP_CHUNK (abort));SCTP_INC_STATS (SCTP_MIB_OUTCTRLCHUNKS );Those code should be move to
sctp_make_abort()for common using. And may be need check whether we need the T flags.
Quoted 3 lines
This rarely happens, so i think it's sufficient to place this block of code here. Moving it into
sctp_make_abort()will waste much cpu time when generating each abort chunk .
There is a side-effect to this patch that now we will completely ignore the verification tag in the INIT-ACK regardless of the violation.
In particular, if the INIT-ACK contains all the fixed parameters but violates structure in some variable parameters, we'll currently use the Initiate Tag from the INIT-ACK in
the ABORT. We should not be changing this behavior.
The simple hack is to add some conditional code into the the different violation functions, but I'd like to see if there is a cleaner way to solve this.
-vlad
Quoted 10 lines · Vlad Yasevich
There is a side-effect to this patch that now we will completely ignore the verification
tag in the INIT-ACK regardless of the violation.In particular, if the INIT-ACK contains all the fixed parameters but violates structure
in some variable parameters, we'll currently use the Initiate Tag from the INIT-ACK in
the ABORT. We should not be changing this behavior.
Quoted 3 lines
The simple hack is to add some conditional code into the the different violation functions, but
I'd like to see if there is a cleaner way to solve this.
Vlad,
The problem you said has been addressed, this is a new patch. Just treat an INIT-ACK received during COOKIE-WAIT as a special case. this patch will not break the normal behavior.
--- include/net/sctp/command.h | 1 + net/sctp/outqueue.c | 3 +++ net/sctp/sm_sideeffect.c | 5 ++++- net/sctp/sm_statefuns.c | 18 ++++++++++++++++++ 4 files changed, 26 insertions(+), 1 deletions(-)
include/net/sctp/command.h +1 -0
@@ -104,6 +104,7 @@ typedef enum {SCTP_CMD_ADAPTATION_IND ,/* generate and send adaptation event */ SCTP_CMD_ASSOC_SHKEY ,/* generate the association shared keys */ SCTP_CMD_T1_RETRAN ,/* Mark for retransmission after T1 timeout */ +SCTP_CMD_UPDATE_INITTAG ,/* Update peer inittag */ SCTP_CMD_LAST } sctp_verb_t;
net/sctp/outqueue.c +3 -0
@@ -793,6 +793,9 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)break ;case SCTP_CID_ABORT : +if (sctp_test_T_bit (chunk)) { + packet->vtag = asoc->c.my_vtag; + }case SCTP_CID_SACK :case SCTP_CID_HEARTBEAT :case SCTP_CID_HEARTBEAT_ACK :
net/sctp/sm_sideeffect.c +4 -1
@@ -1536,7 +1536,10 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, error =sctp_auth_asoc_init_active_key (asoc,GFP_ATOMIC );break ; - +case SCTP_CMD_UPDATE_INITTAG : + asoc->peer.i.init_tag = cmd->obj.u32; +break ; +default :printk (KERN_WARNING "Impossible command: %u, %p\n" , cmd->verb, cmd->obj.ptr);
net/sctp/sm_statefuns.c +18 -0
@@ -4144,6 +4144,24 @@ static sctp_disposition_t sctp_sf_abort_violation( goto nomem;if (asoc) { +/* Treat INIT-ACK as a special case during COOKIE-WAIT. */ +if (chunk->chunk_hdr->type ==SCTP_CID_INIT_ACK + && !asoc->peer.i.init_tag) { +sctp_initack_chunk_t *initack; + + initack = (sctp_initack_chunk_t *)chunk->chunk_hdr; +if (!sctp_chunk_length_valid (chunk, +sizeof (sctp_initack_chunk_t))) + abort->chunk_hdr->flags |=SCTP_CHUNK_FLAG_T ; +else { +unsigned int inittag; + + inittag =ntohl (initack->init_hdr.init_tag); +sctp_add_cmd_sf (commands,SCTP_CMD_UPDATE_INITTAG , +SCTP_U32 (inittag)); + } + } +sctp_add_cmd_sf (commands,SCTP_CMD_REPLY ,SCTP_CHUNK (abort));SCTP_INC_STATS (SCTP_MIB_OUTCTRLCHUNKS );
Signature · 7 lines
1.5.3 -- Regards Gui Jianfeng
Quoted 11 lines · Gui Jianfeng
Quoted 10 lines · Vlad Yasevich
There is a side-effect to this patch that now we will completely ignore the verification
tag in the INIT-ACK regardless of the violation.In particular, if the INIT-ACK contains all the fixed parameters but violates structure
in some variable parameters, we'll currently use the Initiate Tag from the INIT-ACK in
the ABORT. We should not be changing this behavior.
Quoted 8 lines
Quoted 3 lines
The simple hack is to add some conditional code into the the different violation functions, but
I'd like to see if there is a cleaner way to solve this.Vlad,
The problem you said has been addressed, this is a new patch. Just treat an INIT-ACK received during COOKIE-WAIT as a special case. this patch will not break the normal behavior.
Ok. One minor style thing.
Quoted 56 lines
Signed-off-by Gui Jianfeng <[email protected]>--- include/net/sctp/command.h | 1 + net/sctp/outqueue.c | 3 +++ net/sctp/sm_sideeffect.c | 5 ++++- net/sctp/sm_statefuns.c | 18 ++++++++++++++++++ 4 files changed, 26 insertions(+), 1 deletions(-)include/net/sctp/command.h +1
-0@@ -104,6 +104,7 @@ typedef enum {SCTP_CMD_ADAPTATION_IND ,/* generate and send adaptation event */ SCTP_CMD_ASSOC_SHKEY ,/* generate the association shared keys */ SCTP_CMD_T1_RETRAN ,/* Mark for retransmission after T1 timeout */ +SCTP_CMD_UPDATE_INITTAG ,/* Update peer inittag */ SCTP_CMD_LAST } sctp_verb_t;net/sctp/outqueue.c +3
-0@@ -793,6 +793,9 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)break ;case SCTP_CID_ABORT : +if (sctp_test_T_bit (chunk)) { + packet->vtag = asoc->c.my_vtag; + }case SCTP_CID_SACK :case SCTP_CID_HEARTBEAT :case SCTP_CID_HEARTBEAT_ACK :net/sctp/sm_sideeffect.c +4
-1@@ -1536,7 +1536,10 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, error =sctp_auth_asoc_init_active_key (asoc,GFP_ATOMIC );break ; - +case SCTP_CMD_UPDATE_INITTAG : + asoc->peer.i.init_tag = cmd->obj.u32; +break ; +default :printk (KERN_WARNING "Impossible command: %u, %p\n" , cmd->verb, cmd->obj.ptr);net/sctp/sm_statefuns.c +0
-0
net/sctp/sm_statefuns.c static sctp_disposition_t sctp_sf_abort_violation( · line 4149
Quoted 6 lines
net/sctp/sm_statefuns.c +3
-0@@ -4144,6 +4144,24 @@ static sctp_disposition_t sctp_sf_abort_violation( goto nomem;if (asoc) { +/* Treat INIT-ACK as a special case during COOKIE-WAIT. */ +if (chunk->chunk_hdr->type ==SCTP_CID_INIT_ACK + && !asoc->peer.i.init_tag) {
^^^^^^^^^
The '&&' usually goes at the end of the line.
Quoted 8 lines
net/sctp/sm_statefuns.c +8
-0+sctp_initack_chunk_t *initack; + + initack = (sctp_initack_chunk_t *)chunk->chunk_hdr; +if (!sctp_chunk_length_valid (chunk, +sizeof (sctp_initack_chunk_t))) + abort->chunk_hdr->flags |=SCTP_CHUNK_FLAG_T ; +else { +unsigned int inittag;
net/sctp/sm_statefuns.c static sctp_disposition_t sctp_sf_abort_violation( · line 4167
Quoted 10 lines
net/sctp/sm_statefuns.c +7
-0+ + inittag =ntohl (initack->init_hdr.init_tag); +sctp_add_cmd_sf (commands,SCTP_CMD_UPDATE_INITTAG , +SCTP_U32 (inittag)); + } + } +sctp_add_cmd_sf (commands,SCTP_CMD_REPLY ,SCTP_CHUNK (abort));SCTP_INC_STATS (SCTP_MIB_OUTCTRLCHUNKS );
Can you also resend with a clean patch description.
Thanks
-vlad