* [PATCH net-next 0/3] sctp: add proper process for duplicated stream reconf requests @ 2017-04-15 14:00 Xin Long 2017-04-15 14:00 ` [PATCH net-next 1/3] sctp: process duplicated strreset out and addstrm out requests correctly Xin Long 2017-04-18 17:40 ` [PATCH net-next 0/3] sctp: add proper process for duplicated stream reconf requests David Miller 0 siblings, 2 replies; 5+ messages in thread From: Xin Long @ 2017-04-15 14:00 UTC (permalink / raw) To: network dev, linux-sctp; +Cc: Marcelo Ricardo Leitner, Neil Horman, davem Now sctp stream reconf will process a request again even if it's seqno is less than asoc->strreset_inseq. It may cause a replay attack. This patchset is to avoid it by add proper process for all duplicated stream reconf requests. Xin Long (3): sctp: process duplicated strreset out and addstrm out requests correctly sctp: process duplicated strreset in and addstrm in requests correctly sctp: process duplicated strreset asoc request correctly include/net/sctp/structs.h | 1 + net/sctp/stream.c | 96 +++++++++++++++++++++++++++++++++++----------- 2 files changed, 74 insertions(+), 23 deletions(-) -- 2.1.0 ^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH net-next 1/3] sctp: process duplicated strreset out and addstrm out requests correctly 2017-04-15 14:00 [PATCH net-next 0/3] sctp: add proper process for duplicated stream reconf requests Xin Long @ 2017-04-15 14:00 ` Xin Long 2017-04-15 14:00 ` [PATCH net-next 2/3] sctp: process duplicated strreset in and addstrm in " Xin Long 2017-04-18 17:40 ` [PATCH net-next 0/3] sctp: add proper process for duplicated stream reconf requests David Miller 1 sibling, 1 reply; 5+ messages in thread From: Xin Long @ 2017-04-15 14:00 UTC (permalink / raw) To: network dev, linux-sctp; +Cc: Marcelo Ricardo Leitner, Neil Horman, davem Now sctp stream reconf will process a request again even if it's seqno is less than asoc->strreset_inseq. If one request has been done successfully and some data chunks have been accepted and then a duplicated strreset out request comes, the streamin's ssn will be cleared. It will cause that stream will never receive chunks any more because of unsynchronized ssn. It allows a replay attack. A similar issue also exists when processing addstrm out requests. It will cause more extra streams being added. This patch is to fix it by saving the last 2 results into asoc. When a duplicated strreset out or addstrm out request is received, reply it with bad seqno if it's seqno < asoc->strreset_inseq - 2, and reply it with the result saved in asoc if it's seqno >= asoc->strreset_inseq - 2. Note that it saves last 2 results instead of only last 1 result, because two requests can be sent together in one chunk. And note that when receiving a duplicated request, the receiver side will still reply it even if the peer has received the response. It's safe, As the response will be dropped by the peer. Signed-off-by: Xin Long <lucien.xin@gmail.com> --- include/net/sctp/structs.h | 1 + net/sctp/stream.c | 39 +++++++++++++++++++++++++++++---------- 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index b751399..a8b38e1 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -1889,6 +1889,7 @@ struct sctp_association { __u32 strreset_outseq; /* Update after receiving response */ __u32 strreset_inseq; /* Update after receiving request */ + __u32 strreset_result[2]; /* save the results of last 2 responses */ struct sctp_chunk *strreset_chunk; /* save request chunk */ diff --git a/net/sctp/stream.c b/net/sctp/stream.c index 4ec3679..6cab7c3 100644 --- a/net/sctp/stream.c +++ b/net/sctp/stream.c @@ -344,6 +344,13 @@ static sctp_paramhdr_t *sctp_chunk_lookup_strreset_param( return NULL; } +static void sctp_update_strreset_result(struct sctp_association *asoc, + __u32 result) +{ + asoc->strreset_result[1] = asoc->strreset_result[0]; + asoc->strreset_result[0] = result; +} + struct sctp_chunk *sctp_process_strreset_outreq( struct sctp_association *asoc, union sctp_params param, @@ -360,15 +367,19 @@ struct sctp_chunk *sctp_process_strreset_outreq( if (ntohl(outreq->send_reset_at_tsn) > sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map)) { result = SCTP_STRRESET_IN_PROGRESS; - goto out; + goto err; } - if (request_seq > asoc->strreset_inseq) { + if (TSN_lt(asoc->strreset_inseq, request_seq) || + TSN_lt(request_seq, asoc->strreset_inseq - 2)) { result = SCTP_STRRESET_ERR_BAD_SEQNO; - goto out; - } else if (request_seq == asoc->strreset_inseq) { - asoc->strreset_inseq++; + goto err; + } else if (TSN_lt(request_seq, asoc->strreset_inseq)) { + i = asoc->strreset_inseq - request_seq - 1; + result = asoc->strreset_result[i]; + goto err; } + asoc->strreset_inseq++; /* Check strreset_enable after inseq inc, as sender cannot tell * the peer doesn't enable strreset after receiving response with @@ -427,6 +438,8 @@ struct sctp_chunk *sctp_process_strreset_outreq( GFP_ATOMIC); out: + sctp_update_strreset_result(asoc, result); +err: return sctp_make_strreset_resp(asoc, result, request_seq); } @@ -582,15 +595,19 @@ struct sctp_chunk *sctp_process_strreset_addstrm_out( __u32 result = SCTP_STRRESET_DENIED; struct sctp_stream_in *streamin; __u32 request_seq, incnt; - __u16 in; + __u16 in, i; request_seq = ntohl(addstrm->request_seq); - if (request_seq > asoc->strreset_inseq) { + if (TSN_lt(asoc->strreset_inseq, request_seq) || + TSN_lt(request_seq, asoc->strreset_inseq - 2)) { result = SCTP_STRRESET_ERR_BAD_SEQNO; - goto out; - } else if (request_seq == asoc->strreset_inseq) { - asoc->strreset_inseq++; + goto err; + } else if (TSN_lt(request_seq, asoc->strreset_inseq)) { + i = asoc->strreset_inseq - request_seq - 1; + result = asoc->strreset_result[i]; + goto err; } + asoc->strreset_inseq++; if (!(asoc->strreset_enable & SCTP_ENABLE_CHANGE_ASSOC_REQ)) goto out; @@ -638,6 +655,8 @@ struct sctp_chunk *sctp_process_strreset_addstrm_out( 0, ntohs(addstrm->number_of_streams), 0, GFP_ATOMIC); out: + sctp_update_strreset_result(asoc, result); +err: return sctp_make_strreset_resp(asoc, result, request_seq); } -- 2.1.0 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH net-next 2/3] sctp: process duplicated strreset in and addstrm in requests correctly 2017-04-15 14:00 ` [PATCH net-next 1/3] sctp: process duplicated strreset out and addstrm out requests correctly Xin Long @ 2017-04-15 14:00 ` Xin Long 2017-04-15 14:00 ` [PATCH net-next 3/3] sctp: process duplicated strreset asoc request correctly Xin Long 0 siblings, 1 reply; 5+ messages in thread From: Xin Long @ 2017-04-15 14:00 UTC (permalink / raw) To: network dev, linux-sctp; +Cc: Marcelo Ricardo Leitner, Neil Horman, davem This patch is to fix the replay attack issue for strreset and addstrm in requests. When a duplicated strreset in or addstrm in request is received, reply it with bad seqno if it's seqno < asoc->strreset_inseq - 2, and reply it with the result saved in asoc if it's seqno >= asoc->strreset_inseq - 2. For strreset in or addstrm in request, if the receiver side processes it successfully, a strreset out or addstrm out request(as a response for that request) will be sent back to peer. reconf_time will retransmit the out request even if it's lost. So when receiving a duplicated strreset in or addstrm in request and it's result was performed, it shouldn't reply this request, but drop it instead. Signed-off-by: Xin Long <lucien.xin@gmail.com> --- net/sctp/stream.c | 38 +++++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/net/sctp/stream.c b/net/sctp/stream.c index 6cab7c3..c91d97e 100644 --- a/net/sctp/stream.c +++ b/net/sctp/stream.c @@ -456,12 +456,18 @@ struct sctp_chunk *sctp_process_strreset_inreq( __u32 request_seq; request_seq = ntohl(inreq->request_seq); - if (request_seq > asoc->strreset_inseq) { + if (TSN_lt(asoc->strreset_inseq, request_seq) || + TSN_lt(request_seq, asoc->strreset_inseq - 2)) { result = SCTP_STRRESET_ERR_BAD_SEQNO; - goto out; - } else if (request_seq == asoc->strreset_inseq) { - asoc->strreset_inseq++; + goto err; + } else if (TSN_lt(request_seq, asoc->strreset_inseq)) { + i = asoc->strreset_inseq - request_seq - 1; + result = asoc->strreset_result[i]; + if (result == SCTP_STRRESET_PERFORMED) + return NULL; + goto err; } + asoc->strreset_inseq++; if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ)) goto out; @@ -496,10 +502,14 @@ struct sctp_chunk *sctp_process_strreset_inreq( asoc->strreset_outstanding = 1; sctp_chunk_hold(asoc->strreset_chunk); + result = SCTP_STRRESET_PERFORMED; + *evp = sctp_ulpevent_make_stream_reset_event(asoc, SCTP_STREAM_RESET_INCOMING_SSN, nums, str_p, GFP_ATOMIC); out: + sctp_update_strreset_result(asoc, result); +err: if (!chunk) chunk = sctp_make_strreset_resp(asoc, result, request_seq); @@ -671,15 +681,21 @@ struct sctp_chunk *sctp_process_strreset_addstrm_in( struct sctp_stream_out *streamout; struct sctp_chunk *chunk = NULL; __u32 request_seq, outcnt; - __u16 out; + __u16 out, i; request_seq = ntohl(addstrm->request_seq); - if (request_seq > asoc->strreset_inseq) { + if (TSN_lt(asoc->strreset_inseq, request_seq) || + TSN_lt(request_seq, asoc->strreset_inseq - 2)) { result = SCTP_STRRESET_ERR_BAD_SEQNO; - goto out; - } else if (request_seq == asoc->strreset_inseq) { - asoc->strreset_inseq++; + goto err; + } else if (TSN_lt(request_seq, asoc->strreset_inseq)) { + i = asoc->strreset_inseq - request_seq - 1; + result = asoc->strreset_result[i]; + if (result == SCTP_STRRESET_PERFORMED) + return NULL; + goto err; } + asoc->strreset_inseq++; if (!(asoc->strreset_enable & SCTP_ENABLE_CHANGE_ASSOC_REQ)) goto out; @@ -712,10 +728,14 @@ struct sctp_chunk *sctp_process_strreset_addstrm_in( stream->outcnt = outcnt; + result = SCTP_STRRESET_PERFORMED; + *evp = sctp_ulpevent_make_stream_change_event(asoc, 0, 0, ntohs(addstrm->number_of_streams), GFP_ATOMIC); out: + sctp_update_strreset_result(asoc, result); +err: if (!chunk) chunk = sctp_make_strreset_resp(asoc, result, request_seq); -- 2.1.0 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH net-next 3/3] sctp: process duplicated strreset asoc request correctly 2017-04-15 14:00 ` [PATCH net-next 2/3] sctp: process duplicated strreset in and addstrm in " Xin Long @ 2017-04-15 14:00 ` Xin Long 0 siblings, 0 replies; 5+ messages in thread From: Xin Long @ 2017-04-15 14:00 UTC (permalink / raw) To: network dev, linux-sctp; +Cc: Marcelo Ricardo Leitner, Neil Horman, davem This patch is to fix the replay attack issue for strreset asoc requests. When a duplicated strreset asoc request is received, reply it with bad seqno if it's seqno < asoc->strreset_inseq - 2, and reply it with the result saved in asoc if it's seqno >= asoc->strreset_inseq - 2. But note that if the result saved in asoc is performed, the sender's next tsn and receiver's next tsn for the response chunk should be set. It's safe to get them from asoc. Because if it's changed, which means the peer has received the response already, the new response with wrong tsn won't be accepted by peer. Signed-off-by: Xin Long <lucien.xin@gmail.com> --- net/sctp/stream.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/net/sctp/stream.c b/net/sctp/stream.c index c91d97e..dda53a2 100644 --- a/net/sctp/stream.c +++ b/net/sctp/stream.c @@ -529,12 +529,21 @@ struct sctp_chunk *sctp_process_strreset_tsnreq( __u16 i; request_seq = ntohl(tsnreq->request_seq); - if (request_seq > asoc->strreset_inseq) { + if (TSN_lt(asoc->strreset_inseq, request_seq) || + TSN_lt(request_seq, asoc->strreset_inseq - 2)) { result = SCTP_STRRESET_ERR_BAD_SEQNO; - goto out; - } else if (request_seq == asoc->strreset_inseq) { - asoc->strreset_inseq++; + goto err; + } else if (TSN_lt(request_seq, asoc->strreset_inseq)) { + i = asoc->strreset_inseq - request_seq - 1; + result = asoc->strreset_result[i]; + if (result == SCTP_STRRESET_PERFORMED) { + next_tsn = asoc->next_tsn; + init_tsn = + sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map) + 1; + } + goto err; } + asoc->strreset_inseq++; if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_ASSOC_REQ)) goto out; @@ -591,6 +600,8 @@ struct sctp_chunk *sctp_process_strreset_tsnreq( next_tsn, GFP_ATOMIC); out: + sctp_update_strreset_result(asoc, result); +err: return sctp_make_strreset_tsnresp(asoc, result, request_seq, next_tsn, init_tsn); } -- 2.1.0 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH net-next 0/3] sctp: add proper process for duplicated stream reconf requests 2017-04-15 14:00 [PATCH net-next 0/3] sctp: add proper process for duplicated stream reconf requests Xin Long 2017-04-15 14:00 ` [PATCH net-next 1/3] sctp: process duplicated strreset out and addstrm out requests correctly Xin Long @ 2017-04-18 17:40 ` David Miller 1 sibling, 0 replies; 5+ messages in thread From: David Miller @ 2017-04-18 17:40 UTC (permalink / raw) To: lucien.xin; +Cc: netdev, linux-sctp, marcelo.leitner, nhorman From: Xin Long <lucien.xin@gmail.com> Date: Sat, 15 Apr 2017 22:00:26 +0800 > Now sctp stream reconf will process a request again even if it's seqno > is less than asoc->strreset_inseq. It may cause a replay attack. > > This patchset is to avoid it by add proper process for all duplicated > stream reconf requests. Series applied, thanks. ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2017-04-18 17:40 UTC | newest] Thread overview: 5+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2017-04-15 14:00 [PATCH net-next 0/3] sctp: add proper process for duplicated stream reconf requests Xin Long 2017-04-15 14:00 ` [PATCH net-next 1/3] sctp: process duplicated strreset out and addstrm out requests correctly Xin Long 2017-04-15 14:00 ` [PATCH net-next 2/3] sctp: process duplicated strreset in and addstrm in " Xin Long 2017-04-15 14:00 ` [PATCH net-next 3/3] sctp: process duplicated strreset asoc request correctly Xin Long 2017-04-18 17:40 ` [PATCH net-next 0/3] sctp: add proper process for duplicated stream reconf requests David Miller
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).