Skip to content

32bit overflow does not work  #125

Open

Description

@kfessel

dtls_time.h seems to be uint32_t aware:
https://github.com/eclipse/tinydtls/blob/68b2521ca668c632d6febf85fe3f9090d26b7b4e/dtls_time.h#L64

but these lines may produce problems with 32bit overflow:

these calculate possibly overflowing time stamps:
https://github.com/eclipse/tinydtls/blob/68b2521ca668c632d6febf85fe3f9090d26b7b4e/dtls.c#L1763
https://github.com/eclipse/tinydtls/blob/68b2521ca668c632d6febf85fe3f9090d26b7b4e/dtls.c#L4534

these do not deal with overflowing timestamps:
calculating if the timeout happend: (timestamp passed by)
https://github.com/eclipse/tinydtls/blob/68b2521ca668c632d6febf85fe3f9090d26b7b4e/dtls.c#L4596

inserting (sorted) into the netq
https://github.com/eclipse/tinydtls/blob/68b2521ca668c632d6febf85fe3f9090d26b7b4e/netq.c#L96

In #123 @boaks and me pointed that out

reference / line number are current develop branch

Activity

  1. kfessel commented on Feb 7, 2022

    @kfessel
    Author

    read later comment

    (node && (now - node->t) < (((clock_time_t)0 - 1) / 2))
    

    is true if (now > node->t) (taking overflow semantic into account)
    (assuming (clock_time_t is some kind of unsigned integer -> defined overflow)

  2. kfessel commented on Feb 7, 2022

    @kfessel
    Author

    I did a bit of testing using https://godbolt.org/z/qKPeoazhr

    overflow seems to be applied when the whole calculation is done ->

    calculate an offset

    const clock_time_t offset = (((clock_time_t)~0) >> 1);
    

    add offset to difference then cast to _t and compare to offset

    if (node && ((offset + now - node->t) > offset)){
      //now is later than node->t
    }
    

    (this works as well if for any reason clock_time_t would be signed)

  3. boaks commented on Mar 29, 2022

    @boaks
    Contributor
    typedef int32_t clock_time_s_t;
    typedef uint32_t clock_time_u_t;
    
    ...
    
      clock_time_s_t ts1, ts2;
      clock_time_u_t tu1, tu2;
    
      // signed overflow
      ts1 = 0x7ffffff0;
      ts2 = ts1 + 32;
    
      tu1 = 0x7ffffff0;
      tu2 = tu1 + 32;
    
      dtls_warn("signed: %d %d %d %d\n", ts1, ts2, (ts2 - ts1) > 0, (ts2 - ts1) < 0);
      dtls_warn("unsign: %u %u %d %d\n", tu1, tu2, (tu2 - tu1) > 0,  (tu2 - tu1) < 0);
    
      // unsigned overflow
      ts1 = 0xfffffff0;
      ts2 = ts1 + 32;
    
      tu1 = 0xfffffff0;
      tu2 = tu1 + 32;
    
      dtls_warn("signed: %d %d %d %d\n", ts1, ts2, (ts2 - ts1) > 0, (ts2 - ts1) < 0);
      dtls_warn("unsign: %u %u %d %d\n", tu1, tu2, (tu2 - tu1) > 0,  (tu2 - tu1) < 0);
    

    Prints

    signed: 2147483632 -2147483632 1 0
    unsign: 2147483632 2147483664 1 0
    signed: -16 16 1 0
    unsign: 4294967280 16 1 0

    I'm not sure, why (((clock_time_t)0 - 1) / 2) should be used?

  4. boaks commented on Mar 29, 2022

    @boaks
    Contributor

    I'm not sure, why (((clock_time_t)0 - 1) / 2) should be used?#

    OK, it's not that simple as in java ;-).

  5. kfessel commented on Mar 29, 2022

    @kfessel
    Author
    ((offset + now - node->t) > offset
    

    should be used
    instead of

    now - node->t > 0
    

    since the later might lead into UB since singed overflow is not defined and might not work as expected if optimized and the compiler chose to do the substraction and the comparison on an larger type.
    example:
    loop1: is the working one (with magic offset) (magic offset can be written as ((T)~0)>>1 or ((T)0-1)/2)
    loop2: works for signed values
    loop3: is allways kindof wrong

    the c off all loops is expected to equal the number of loops (300) or 0 (if TN_OFFSET if defined negative)

    Details
    #include <stdio.h>
    #include <stdint.h>
    
    #define TN_OFFSET (50)
    
    typedef uint8_t clock_time_t;
    
    int main(void){
        volatile clock_time_t t = 0;
        volatile clock_time_t n = 0;
        const clock_time_t magic_offset = (((clock_time_t)~0) >> 1);
        {
        int c = 0;
        for (int i = 0 ; i < 300; i ++ ){
            //i will overflow into t and n 
            t = i;
            n = i - TN_OFFSET;
            if ((clock_time_t)(magic_offset + n - t) < magic_offset){
                c++;
            }
        }
        printf("loop 1 c:%d \n", c);
        }
    
        {
        int c = 0;
        for (int i = 0 ; i < 300; i ++ ){
            //i will overflow into t and n 
            t = i;
            n = i - TN_OFFSET;
            if ((clock_time_t)(n - t) < 0){
                c++;
            }
        }
        printf("loop 2 c:%d \n", c);
        }
    
        {
        int c = 0;
        for (int i = 0 ; i < 300; i ++ ){
            //i will overflow into t and n 
            t = i;
            n = i - TN_OFFSET;
            if ((n - t) < 0){
                c++;
            }
        }
        printf("loop 3 c:%d \n", c);
        }
    
        printf("%d\n", magic_offset);
        
        return 0;
    }
    
    

    compiler explorer example

  6. obgm commented on May 27, 2022

    @obgm
    Contributor

    @kfessel did you have a change to check with PR #131 merged?

  7. kfessel commented on May 27, 2022

    @kfessel
    Author

    Hi @obgm: since @boaks detected this issue though reading the code, I described it, @boaks developed the fixing PR (hence he solver what he read by writing) and I gave my cent to it (correct overflow handling regardless of singnedness).
    I think we can consider this solved.
    I never had a test for that other than reading. (I think this would require a Multiday session of DTLS)

  8. boaks commented on May 27, 2022

    @boaks
    Contributor

    I think, adding some unit test for the calculation may be an idea. But for now, there is too much other stuff already pending.

  9. obgm commented on May 27, 2022

    @obgm
    Contributor

    @kfessel sorry for the confusion

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions