summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSamuel Jero <sj323707@ohio.edu>2012-02-26 20:22:02 -0500
committerGerrit Renker <gerrit@erg.abdn.ac.uk>2012-03-03 11:02:52 -0500
commitf541fb7e20c848f947ca65fbf169efe69400c942 (patch)
tree689f3a7a46ca00b6610667e33313f339645b229d
parent793734b587a670e47a8d65f9e5211ba2188bb904 (diff)
dccp: fix bug in sequence number validation during connection setup
This fixes a bug in the sequence number validation during the initial handshake. The code did not treat the initial sequence numbers ISS and ISR as read-only and did not keep state for GSR and GSS as required by the specification. This causes problems with retransmissions during the initial handshake, causing the budding connection to be reset. This patch now treats ISS/ISR as read-only and tracks GSS/GSR as required. Signed-off-by: Samuel Jero <sj323707@ohio.edu> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
-rw-r--r--include/linux/dccp.h8
-rw-r--r--net/dccp/ipv4.c8
-rw-r--r--net/dccp/ipv6.c8
-rw-r--r--net/dccp/minisocks.c18
-rw-r--r--net/dccp/output.c10
5 files changed, 32 insertions, 20 deletions
diff --git a/include/linux/dccp.h b/include/linux/dccp.h
index 710c04302a15..eaf95a023af4 100644
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -376,8 +376,10 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb)
376/** 376/**
377 * struct dccp_request_sock - represent DCCP-specific connection request 377 * struct dccp_request_sock - represent DCCP-specific connection request
378 * @dreq_inet_rsk: structure inherited from 378 * @dreq_inet_rsk: structure inherited from
379 * @dreq_iss: initial sequence number sent on the Response (RFC 4340, 7.1) 379 * @dreq_iss: initial sequence number, sent on the first Response (RFC 4340, 7.1)
380 * @dreq_isr: initial sequence number received on the Request 380 * @dreq_gss: greatest sequence number sent (for retransmitted Responses)
381 * @dreq_isr: initial sequence number received in the first Request
382 * @dreq_gsr: greatest sequence number received (for retransmitted Request(s))
381 * @dreq_service: service code present on the Request (there is just one) 383 * @dreq_service: service code present on the Request (there is just one)
382 * @dreq_featneg: feature negotiation options for this connection 384 * @dreq_featneg: feature negotiation options for this connection
383 * The following two fields are analogous to the ones in dccp_sock: 385 * The following two fields are analogous to the ones in dccp_sock:
@@ -387,7 +389,9 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb)
387struct dccp_request_sock { 389struct dccp_request_sock {
388 struct inet_request_sock dreq_inet_rsk; 390 struct inet_request_sock dreq_inet_rsk;
389 __u64 dreq_iss; 391 __u64 dreq_iss;
392 __u64 dreq_gss;
390 __u64 dreq_isr; 393 __u64 dreq_isr;
394 __u64 dreq_gsr;
391 __be32 dreq_service; 395 __be32 dreq_service;
392 struct list_head dreq_featneg; 396 struct list_head dreq_featneg;
393 __u32 dreq_timestamp_echo; 397 __u32 dreq_timestamp_echo;
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
index 1c67fe8ff90d..caf6e1734b62 100644
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -300,7 +300,8 @@ static void dccp_v4_err(struct sk_buff *skb, u32 info)
300 */ 300 */
301 WARN_ON(req->sk); 301 WARN_ON(req->sk);
302 302
303 if (seq != dccp_rsk(req)->dreq_iss) { 303 if (!between48(seq, dccp_rsk(req)->dreq_iss,
304 dccp_rsk(req)->dreq_gss)) {
304 NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS); 305 NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS);
305 goto out; 306 goto out;
306 } 307 }
@@ -639,11 +640,12 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
639 * 640 *
640 * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookie 641 * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookie
641 * 642 *
642 * In fact we defer setting S.GSR, S.SWL, S.SWH to 643 * Setting S.SWL/S.SWH to is deferred to dccp_create_openreq_child().
643 * dccp_create_openreq_child.
644 */ 644 */
645 dreq->dreq_isr = dcb->dccpd_seq; 645 dreq->dreq_isr = dcb->dccpd_seq;
646 dreq->dreq_gsr = dreq->dreq_isr;
646 dreq->dreq_iss = dccp_v4_init_sequence(skb); 647 dreq->dreq_iss = dccp_v4_init_sequence(skb);
648 dreq->dreq_gss = dreq->dreq_iss;
647 dreq->dreq_service = service; 649 dreq->dreq_service = service;
648 650
649 if (dccp_v4_send_response(sk, req, NULL)) 651 if (dccp_v4_send_response(sk, req, NULL))
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
index ce903f747e64..4dc588f520e0 100644
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -193,7 +193,8 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
193 */ 193 */
194 WARN_ON(req->sk != NULL); 194 WARN_ON(req->sk != NULL);
195 195
196 if (seq != dccp_rsk(req)->dreq_iss) { 196 if (!between48(seq, dccp_rsk(req)->dreq_iss,
197 dccp_rsk(req)->dreq_gss)) {
197 NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS); 198 NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS);
198 goto out; 199 goto out;
199 } 200 }
@@ -440,11 +441,12 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
440 * 441 *
441 * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookie 442 * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookie
442 * 443 *
443 * In fact we defer setting S.GSR, S.SWL, S.SWH to 444 * Setting S.SWL/S.SWH to is deferred to dccp_create_openreq_child().
444 * dccp_create_openreq_child.
445 */ 445 */
446 dreq->dreq_isr = dcb->dccpd_seq; 446 dreq->dreq_isr = dcb->dccpd_seq;
447 dreq->dreq_gsr = dreq->dreq_isr;
447 dreq->dreq_iss = dccp_v6_init_sequence(skb); 448 dreq->dreq_iss = dccp_v6_init_sequence(skb);
449 dreq->dreq_gss = dreq->dreq_iss;
448 dreq->dreq_service = service; 450 dreq->dreq_service = service;
449 451
450 if (dccp_v6_send_response(sk, req, NULL)) 452 if (dccp_v6_send_response(sk, req, NULL))
diff --git a/net/dccp/minisocks.c b/net/dccp/minisocks.c
index 5a7f90bbffac..ea850ce35d4a 100644
--- a/net/dccp/minisocks.c
+++ b/net/dccp/minisocks.c
@@ -127,9 +127,11 @@ struct sock *dccp_create_openreq_child(struct sock *sk,
127 * activation below, as these windows all depend on the local 127 * activation below, as these windows all depend on the local
128 * and remote Sequence Window feature values (7.5.2). 128 * and remote Sequence Window feature values (7.5.2).
129 */ 129 */
130 newdp->dccps_gss = newdp->dccps_iss = dreq->dreq_iss; 130 newdp->dccps_iss = dreq->dreq_iss;
131 newdp->dccps_gss = dreq->dreq_gss;
131 newdp->dccps_gar = newdp->dccps_iss; 132 newdp->dccps_gar = newdp->dccps_iss;
132 newdp->dccps_gsr = newdp->dccps_isr = dreq->dreq_isr; 133 newdp->dccps_isr = dreq->dreq_isr;
134 newdp->dccps_gsr = dreq->dreq_gsr;
133 135
134 /* 136 /*
135 * Activate features: initialise CCIDs, sequence windows etc. 137 * Activate features: initialise CCIDs, sequence windows etc.
@@ -164,9 +166,9 @@ struct sock *dccp_check_req(struct sock *sk, struct sk_buff *skb,
164 /* Check for retransmitted REQUEST */ 166 /* Check for retransmitted REQUEST */
165 if (dccp_hdr(skb)->dccph_type == DCCP_PKT_REQUEST) { 167 if (dccp_hdr(skb)->dccph_type == DCCP_PKT_REQUEST) {
166 168
167 if (after48(DCCP_SKB_CB(skb)->dccpd_seq, dreq->dreq_isr)) { 169 if (after48(DCCP_SKB_CB(skb)->dccpd_seq, dreq->dreq_gsr)) {
168 dccp_pr_debug("Retransmitted REQUEST\n"); 170 dccp_pr_debug("Retransmitted REQUEST\n");
169 dreq->dreq_isr = DCCP_SKB_CB(skb)->dccpd_seq; 171 dreq->dreq_gsr = DCCP_SKB_CB(skb)->dccpd_seq;
170 /* 172 /*
171 * Send another RESPONSE packet 173 * Send another RESPONSE packet
172 * To protect against Request floods, increment retrans 174 * To protect against Request floods, increment retrans
@@ -186,12 +188,14 @@ struct sock *dccp_check_req(struct sock *sk, struct sk_buff *skb,
186 goto drop; 188 goto drop;
187 189
188 /* Invalid ACK */ 190 /* Invalid ACK */
189 if (DCCP_SKB_CB(skb)->dccpd_ack_seq != dreq->dreq_iss) { 191 if (!between48(DCCP_SKB_CB(skb)->dccpd_ack_seq,
192 dreq->dreq_iss, dreq->dreq_gss)) {
190 dccp_pr_debug("Invalid ACK number: ack_seq=%llu, " 193 dccp_pr_debug("Invalid ACK number: ack_seq=%llu, "
191 "dreq_iss=%llu\n", 194 "dreq_iss=%llu, dreq_gss=%llu\n",
192 (unsigned long long) 195 (unsigned long long)
193 DCCP_SKB_CB(skb)->dccpd_ack_seq, 196 DCCP_SKB_CB(skb)->dccpd_ack_seq,
194 (unsigned long long) dreq->dreq_iss); 197 (unsigned long long) dreq->dreq_iss,
198 (unsigned long long) dreq->dreq_gss);
195 goto drop; 199 goto drop;
196 } 200 }
197 201
diff --git a/net/dccp/output.c b/net/dccp/output.c
index dede3edb8849..787367308797 100644
--- a/net/dccp/output.c
+++ b/net/dccp/output.c
@@ -408,10 +408,10 @@ struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst,
408 skb_dst_set(skb, dst_clone(dst)); 408 skb_dst_set(skb, dst_clone(dst));
409 409
410 dreq = dccp_rsk(req); 410 dreq = dccp_rsk(req);
411 if (inet_rsk(req)->acked) /* increase ISS upon retransmission */ 411 if (inet_rsk(req)->acked) /* increase GSS upon retransmission */
412 dccp_inc_seqno(&dreq->dreq_iss); 412 dccp_inc_seqno(&dreq->dreq_gss);
413 DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_RESPONSE; 413 DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_RESPONSE;
414 DCCP_SKB_CB(skb)->dccpd_seq = dreq->dreq_iss; 414 DCCP_SKB_CB(skb)->dccpd_seq = dreq->dreq_gss;
415 415
416 /* Resolve feature dependencies resulting from choice of CCID */ 416 /* Resolve feature dependencies resulting from choice of CCID */
417 if (dccp_feat_server_ccid_dependencies(dreq)) 417 if (dccp_feat_server_ccid_dependencies(dreq))
@@ -429,8 +429,8 @@ struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst,
429 DCCP_SKB_CB(skb)->dccpd_opt_len) / 4; 429 DCCP_SKB_CB(skb)->dccpd_opt_len) / 4;
430 dh->dccph_type = DCCP_PKT_RESPONSE; 430 dh->dccph_type = DCCP_PKT_RESPONSE;
431 dh->dccph_x = 1; 431 dh->dccph_x = 1;
432 dccp_hdr_set_seq(dh, dreq->dreq_iss); 432 dccp_hdr_set_seq(dh, dreq->dreq_gss);
433 dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), dreq->dreq_isr); 433 dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), dreq->dreq_gsr);
434 dccp_hdr_response(skb)->dccph_resp_service = dreq->dreq_service; 434 dccp_hdr_response(skb)->dccph_resp_service = dreq->dreq_service;
435 435
436 dccp_csum_outgoing(skb); 436 dccp_csum_outgoing(skb);