[krbdev.mit.edu #2409] util_ordering.c bug - wraparound not correct

Wyllys Ingersoll via RT rt-comment at krbdev.mit.edu
Tue Mar 16 15:39:00 EST 2004



I think the logic in g_order_check is incorrect, or
at the very least - very convoluted and hard to read.

Nico and I looked at this and came up with a possible
solution.

Below is an updated g_order_check routine for consideration.

-Wyllys


gss_int32
g_order_check(void **vqueue, gssint_uint64 seqnum)
{
    queue *q;
    int i;
    gssint_uint64 expected;

    q = (queue *) (*vqueue);

    if (!q->do_replay && !q->do_sequence)
       return(GSS_S_COMPLETE);

    /* All checks are done relative to the initial sequence number, to
         avoid (or at least put off) the pain of wrapping.        */

    /* wraparound case */
    if (seqnum < q->firstnum) {
         /* if 32 bit, put seqnum into 64 bit range */
         if (q->mask != ~(gssint_uint64)0) {
                 seqnum |= 0x100000000ULL;
                 seqnum -= q->firstnum;
         } else {
                 /*
                  * 64 bit wraparound, just add the number of
                  * elements before the wraparound point
                  * to get the normalized seqnum.
                  */
                 seqnum += (~(gssint_uint64)0) - q->firstnum;
         }
    } else {
         /*
          * Normally (as long as seqnum >= firstnum), just subtract
          * the firstnum to get the relative 'seqnum'.
          */
         seqnum -= q->firstnum;
    }

    /* rule 1: expected sequence number */

    expected = (QELEM(q,q->start+q->length-1)+1) & q->mask;
    if (seqnum == expected) {
         queue_insert(q, q->start+q->length-1, seqnum);
         return(GSS_S_COMPLETE);
    }

    /* rule 2: > expected sequence number */

    if ((seqnum > expected)) {
         queue_insert(q, q->start+q->length-1, seqnum);
         if (q->do_replay && !q->do_sequence)
          return(GSS_S_COMPLETE);
         else
          return(GSS_S_GAP_TOKEN);
    }

    /* rule 3: seqnum < seqnum(first) */
    if (seqnum < QELEM(q,q->start)) {
       if (q->do_replay)
             return(GSS_S_OLD_TOKEN);
       else
             return(GSS_S_UNSEQ_TOKEN);
    }

    /* rule 4+5: seqnum in [seqnum(first),seqnum(last)]  */

    else {
       if (seqnum == QELEM(q,q->start+q->length-1))
          return(GSS_S_DUPLICATE_TOKEN);

       for (i=q->start; i<q->start+q->length-1; i++) {
          if (seqnum == QELEM(q,i))
             return(GSS_S_DUPLICATE_TOKEN);
          if ((seqnum > QELEM(q,i)) && (seqnum < QELEM(q,i+1))) {
             queue_insert(q, i, seqnum);
             if (q->do_replay && !q->do_sequence)
                return(GSS_S_COMPLETE);
             else
                return(GSS_S_UNSEQ_TOKEN);
          }
       }
    }

    /* this should never happen */
    return(GSS_S_FAILURE);
}



More information about the krb5-bugs mailing list