summaryrefslogtreecommitdiffstats
path: root/net/sctp/stream.c
diff options
context:
space:
mode:
authorXin Long <lucien.xin@gmail.com>2017-04-15 22:00:29 +0800
committerDavid S. Miller <davem@davemloft.net>2017-04-18 13:39:50 -0400
commit6c80138773efff75ee9598b4ebcd7aa0e3a5a2a3 (patch)
tree0f59585517a6666b758588f06c413f12b75c1f89 /net/sctp/stream.c
parentd0f025e611581169c81e3c0fc44b5133d12748dd (diff)
downloadlinux-6c80138773efff75ee9598b4ebcd7aa0e3a5a2a3.tar.gz
linux-6c80138773efff75ee9598b4ebcd7aa0e3a5a2a3.tar.bz2
linux-6c80138773efff75ee9598b4ebcd7aa0e3a5a2a3.zip
sctp: process duplicated strreset asoc request correctly
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> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sctp/stream.c')
-rw-r--r--net/sctp/stream.c19
1 files changed, 15 insertions, 4 deletions
diff --git a/net/sctp/stream.c b/net/sctp/stream.c
index c91d97e5d590..dda53a293986 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);
}