Re: Sequence Number Validation Bug Fixes 2/2

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



| > | + if(after48(seqno, dp->dccps_gsr)){
| > | + dccp_update_gsr(sk, seqno);
| > | + }
| > | 
| > | if (dh->dccph_type != DCCP_PKT_SYNC &&
| > |     ackno != DCCP_PKT_WITHOUT_ACK_SEQ && 
| > 
| > I would like to move that change from dccp_check_seqno() into
| > dccp_update_gsr(), since the latter function is also called for Sync/SyncAck
| > packets, where the same problem exists.
| 
| In the case of Sync/SyncAck packets, RFC 4340 section 7.5.4 requires
| that:
| "On receiving a sequence-valid DCCP-Sync packet, the peer endpoint
| (say, DCCP B) MUST update its GSR variable and reply with a DCCP-
| SyncAck packet.  The DCCP-SyncAck packet's Acknowledgement Number
| will equal the DCCP-Sync's Sequence Number, which is not necessarily
| GSR.  Upon receiving this DCCP-SyncAck, which will be sequence-valid
| since it acknowledges the DCCP-Sync, DCCP A will update its GSR
| variable, and the endpoints will be back in sync."
| 
| Adding the check for > GSR inside dccp_update_gsr() breaks this
| requirement.
| 
I wonder how the requirement breaks, in the above paragraph are several points:
 1. it applies only to sequence-valid DCCP-Sync packets,
 2. need to clarify what "update its GSR variable" means,
 3. DCCP-SyncAck.ackno = DCCP-Sync.seqno (illustrated below),
 4. case for receiving sequence-valid DCCP-SyncAck analogous to (1), (2).

| Further, Sync/SyncAck packets are already checked for sequence validity
| by dccp_check_seqno() before the call to dccp_update_gsr(). The checks
| used follow RFC 4340 section 7.5.3:
| DCCP-Sync        SWL <= seqno             AWL <= ackno <= AWH
| DCCP-SyncAck     SWL <= seqno             AWL <= ackno <= AWH
| 
Yes, I think you refer to step 5 in dccp_check_seqno(), so (1) holds.

Following sketch with (seqno, ackno) packets:

      receiver                               sender
          |                                    |
  packet  |   DCCP-packet(SND.GSS, P.ackno)    |
  invalid +<-----------------------------------|
          |                                    |
          |   DCCP-Sync(RCV.GSS, SND.GSS)      |
          |----------------------------------->+  passes: ackno = SND.GSS = AWH
          |                                    |  set GSR := RCV.GSS (see below)
   OK (*) |   DCCP-SyncAck(SND.GSS, RCV.GSS)   |  set SND.GSS := SND.GSS + 1
   update +<-----------------------------------|
   GSR    |                                    |
          |   DCCP-packet(RCV.GSS+1, SND.GSS)  |  
          |----------------------------------->+

   (*) The SyncAck passes because SWL <= SND.GSS
                          and     AWL <  RCV.GSS = AWH.


With regard to (2), my understanding is that "updating the GSR" or "updating
the GAR" (step 6 in RFC 4340, 8.5) means to update the value if it is greater
than the previous one but not otherwise.

Both variables are defined in terms of 'Greatest' in 7.1, so allowing a
(reordered) packet to reduce these values would be against their definition.

This was the reason for the bug fix on 23 Nov, and I think the same principle
applies here. There are only two cases to consider:

 a) GSR <= seqno 
    This is the expected case, seqno = RCV.GSS is higher than all received
    sequence numbers before.

 b) GSR > seqno
    Due to (1) we have SWL <= seqno < GSR. Due to the adjustment at the end
    of 7.5.1, we further have
    ISR <= SWL = max(GSL + 1 - floor(W/4), ISR) <= seqno < GSR, shorter
    ISR <= seqno < GSR. This means that the seqno on the Sync(Ack) packet
    is below the Greatest Sequence Number Received on the same connection.

    Since per 4.2, "Every DCCP packet increments the sequence number", there
    are only pathological cases where this condition could occur:
    * a delayed DCCP-Sync(Ack) that had been sent earlier,
    * a stray packet from an earlier incarnation of the same connection
      (having the same src/dst port numbers and service code),
    * a sequence number attack.

    For the first case, refer to above figure:
     i) DCCP-Sync: since GSR > seqno, the value of RCV.GSS used in the
        Sync packet is less than the current GSS = AWH at the receiver.
	The SyncAck would pass the [AWL, AWH] test if the difference is
        not too big. A similar problem arises when the Sync(Ack) handshake
        succeeds, and packets arrive from the receiver: the GSS in the packet
	will have a distance > 1 from the one used for the Sync.
    ii) DCCP-SyncAck: I believe this is not possible. If the Sync was sent
        since P.ackno < RCV.AWL = RCV.GSS - W' + 1 then how could the sender
        in the meantime learned a better value for P.ackno other than another
        Sync(Ack) handshake?
        Otherwise, if the Sync was sent due to a failed test for SND.GSS, it
	means that either SND.GSS < SWL <= GSR or SND.GSS > SWH > GSR, where
	the first condition does not apply for packets sent from ISR ... GSR.
	But the second condition contradicts the assumption that seqno < GSR.

    The second case is an exception, due to the Quiet Time in 7.3. The third
    case benefits from not updating the GSR towards lower values, since not
    only would moving GSR backwards help to get the connection out of sync, 
    but it also makes it a bit more difficult to guess valid sequence numbers
    in a DCCP-Sync attack (7.5.5).

In short, I find that allowing DCCP-Sync(Ack) to move the GSR backwards to
sequence number below those already received on acknowledgeable packets on
the same connection creates a complex and counter-intuitive bevaviour which
I think is not warranted (in particular the definition of GSR does no longer
mean 'Greatest', but would change into something like "usually the greatest
sequence number received, when a DCCP-Sync arrives, GSR could be up to W/4
below the greatest sequence number received on the connection").

Lastly, there was another reason for moving the check into dccp_update_gsr():
it is legitimate at any stage during the connection to send a DCCP-Sync. This
is currently used if the packet real estate becomes to small for CCID-specific
options (dccps_sync_scheduled > 0). 

In the sense of 6.6.1 this is in future also planned to update feature values
on an established connection: Sequence Window and Ack Ratio are the only
currently known NN options, for which such a dynamic update would make sense.

Moving the check for GSR into dccp_update_gsr() allows to put the new value
for the feature-remote Sequence Window into the [SWL, SWH] window, as it is
for instance called by dccp_hdlr_seq_win().

Please let me know your thoughts, as said I am not going to submit this at this
stage (it is however in the test tree at the moment).

Gerrit

| > >>>>>>>>>>>>>>>>>>>>>> Patch v2 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
| > dccp: fix bug in updating the GSR
| > 
| > Currently dccp_check_seqno allows any valid packet to update the Greatest
| > Sequence Number Received, even if that packet's sequence number is less than
| > the current GSR. This patch adds a check to make sure that the new packet's
| > sequence number is greater than GSR.
| > 
| > Signed-off-by: Samuel Jero <sj323707@xxxxxxxx>
| > Signed-off-by: Gerrit Renker <gerrit@xxxxxxxxxxxxxx>
| > ---
| >  net/dccp/dccp.h |    3 ++-
| >  1 file changed, 2 insertions(+), 1 deletion(-)
| > 
| > --- a/net/dccp/dccp.h
| > +++ b/net/dccp/dccp.h
| > @@ -426,7 +426,8 @@ static inline void dccp_update_gsr(struc
| >  {
| >  	struct dccp_sock *dp = dccp_sk(sk);
| >  
| > -	dp->dccps_gsr = seq;
| > +	if (after48(seq, dp->dccps_gsr))
| > +		dp->dccps_gsr = seq;
| >  	/* Sequence validity window depends on remote Sequence Window (7.5.1) */
| >  	dp->dccps_swl = SUB48(ADD48(dp->dccps_gsr, 1), dp->dccps_r_seq_win / 4);
| >  	/*



-- 
--
To unsubscribe from this list: send the line "unsubscribe dccp" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Kernel]     [IETF DCCP]     [Linux Networking]     [Git]     [Security]     [Linux Assembly]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]

  Powered by Linux