obgm / libcoap

A CoAP (RFC 7252) implementation in C
Other
799 stars 424 forks source link

Unsigned Overflow in coap_update_token at coap_pdu.c at coap_update_token Function #1351

Closed dqp10515 closed 7 months ago

dqp10515 commented 7 months ago

Environment

libcoap Configuration Summary

libcoap package version : "4.3.4" libcoap package source : "v4.3.4-82-g0a39b6c0" libcoap API version : "3" libcoap ABI version : "3.1.2" libcoap libtool SO version : "4.2.1" libcoap DTLS lib extn : "-gnutls" host system : "x86_64-pc-linux-gnu" build with server support : "yes" build with client support : "yes" build with IPv4 support : "yes" build with IPv6 support : "yes" build with Unix socket support : "yes" build with TCP support : "yes" build DTLS support : "yes" --> GnuTLS around : "yes" (found GnuTLS 3.6.13) GNUTLS_CFLAGS : "-I/usr/include/p11-kit-1" GNUTLS_LIBS : "-lgnutls" add default names : "yes" build Observe Persist : "yes" build using epoll : "yes" enable small stack size : "no" enable separate responses : "yes" enable OSCORE support : "yes" enable Q-Block support : "yes" enable max logging level : "none" enable thread safe code : "yes" enable recursive lock check : "yes" build doxygen pages : "no" build man pages : "no" build unit test binary : "no" build examples : "yes" install examples source : "yes" build with gcov support : "no" build shared library : "no" build static library : "yes"

Problem Description

After sending a sequence of messages to the CoAP server, a runtime error was reported by UndefinedBehaviorSanitizer (UBSan). The error indicated an unsigned integer overflow occurred in coap_pdu.c at the line where an address calculation was being performed. Specifically, an unsigned offset addition to a base address resulted in an overflow, indicating that the calculated address wrapped around to a lower value than the original address. This is a sign of undefined behavior due to integer overflow during pointer arithmetic. This suggests that the resulting address calculation wrapped around, which is indicative of undefined behavior in the program.

Expected Behavior

The server is expected to handle a sequence of incoming messages reliably without encountering arithmetic overflows or other undefined behaviors during address calculations. Memory operations should remain within their allocated bounds, and all pointer arithmetic should result in valid memory addresses that are within the expected range.

Actual Behavior

The server exhibited undefined behavior after processing a sequence of messages, indicating a potential flaw in the address calculation within the coap_update_token function.

Steps to reproduce

  1. Prepare the build environment and compile the libcoap project:
    • Set the environment variables for the compiler and linker to include ASan andUBsan:
      export CC=clang CXX=clang++
      export CFLAGS="-g -fsanitize=address,undefined -fno-omit-frame-pointer"
      export CXXFLAGS="-g -fsanitize=address,undefined -fno-omit-frame-pointer"
      export LDFLAGS="-fsanitize=address,undefined"
    • Navigate to the libcoap directory and clear any previous configurations:
      cd libcoap
      bash ./autogen.sh --clear
    • Generate the new configuration scripts and run the configure script with the desired options:
      bash ./autogen.sh
      bash ./configure --disable-doxygen --disable-manpages --enable-tests --disable-documentation --enable-examples --disable-shared --disable-tests
    • Compile the project:
      make -j
  2. Run the server :
    libcoap/examples/coap-server -A 127.0.0.1 -e -d 100 -v 9 -p 5783
  3. Send a series of hexstreams to the server in sequence, which are stored in the file: hexstream.txt

Debug Logs

log of client : client log.txt

Here is the UBSan report:

src/coap_pdu.c:403:15: runtime error: addition of unsigned offset to 0x603000001068 overflowed to 0x603000001067
    #0 0x6353c9 in coap_update_token libcoap/src/coap_pdu.c:403:15
    #1 0x54f857 in coap_check_update_token libcoap/src/coap_block.c:4054:9
    #2 0x699ff2 in coap_session_disconnected_locked libcoap/src/coap_session.c:932:7
    #3 0x5d2133 in coap_read_session libcoap/src/coap_net.c:2043:7
    #4 0x5e0474 in coap_io_do_epoll_locked libcoap/src/coap_net.c:2248:13
    #5 0x5a63f7 in coap_io_process_with_fds libcoap/src/coap_io.c:1680:5
    #6 0x5a56f7 in coap_io_process_locked libcoap/src/coap_io.c:1489:10
    #7 0x6ff8ba in coap_io_process libcoap/src/coap_threadsafe.c:575:9
    #8 0x4cd98f in main libcoap/examples/coap-client.c:1942:14
    #9 0x7fc0d7e500b2 in __libc_start_main /build/glibc-eX1tMB/glibc-2.31/csu/../csu/libc-start.c:308:16
    #10 0x41ea9d in _start (libcoap/examples/coap-client+0x41ea9d)

SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior src/coap_pdu.c:403:15 in 
mrdeep1 commented 7 months ago

Given that the hexstream is being sent to the running server, this is not getting done by the examples client, so I am not able to reproduce the client issue.

However, one of the hexstream values is invalid, which the examples server correctly reports there are issues with the data, but the Sanitizer does not complain. The bad hexstream entry is

hexstream 13:
d50301b831e281a9616578616d706c6532e4000c91425634
dqp10515 commented 7 months ago

Thank you for your reply. The hexstream was sent to the server using the following command: echo -n "hexstream" | xxd -r -p | nc -u 127.0.0.1 5783

mrdeep1 commented 7 months ago

Doing that only exercises the server logic (the -u option is invalid for ncas the data is larger that a UDP packet size), and not the client logic where you were reporting the error. The server rightly complains about the hexstream 13 record.

The issue in the coap_update_token() function is only likely to occur on the client side logic and that needs to be reproducible somehow.

mrdeep1 commented 7 months ago

Please see #1352 for a fix. Please confirm this fixes what you are trying to do as I cannot reproduce your client side actual issue with the information you have given us.

Please note that this is a false positive that is reported.

dqp10515 commented 7 months ago

I tried to reproduce the crash again and no error was found. Thanks for the fix.

mrdeep1 commented 7 months ago

Thanks for the feedback. Changes now merged into the develop branch.

kittener commented 2 weeks ago

Hello, when I tried to reproduce this vulnerability, I sent the data packet to the server through the following script

import subprocess
import time

with open('hexstream.txt', 'r') as file:
    hexstreams = file.readlines()

hexstreams = [hexstream.strip() for hexstream in hexstreams]

for hexstream in hexstreams:
    if hexstream:  
        command = f"echo -n {hexstream} | xxd -r -p | nc -u 127.0.0.1 5783"
        print(f"Executing: {command}")
        #time.sleep(2)
        process = subprocess.Popen(command, shell=True)

I have observed that the server is constantly creating new sessions, which seems inconsistent with the behavior recorded in client.log.

Oct 17 01:21:11.504 DEBG ***127.0.0.1:5783 <-> 127.0.0.1:50912 (if1) UDP : session 0x617000006600: new incoming session
Oct 17 01:21:11.504 DEBG ***EVENT: COAP_EVENT_SERVER_SESSION_NEW
Oct 17 01:21:11.504 DEBG *  127.0.0.1:5783 <-> 127.0.0.1:50912 (if1) UDP : netif: recv    7 bytes
v:1 t:NON c:CSM i:2380 {} [ 0:, Max-Message-Size:0 ]
Oct 17 01:21:11.504 INFO coap_dispatch: Received invalid PDU code (7.01)
Oct 17 01:21:11.504 DEBG ***EVENT: COAP_EVENT_BAD_PACKET
Oct 17 01:21:13.507 DEBG ***127.0.0.1:5783 <-> 127.0.0.1:40207 (if1) UDP : session 0x617000006980: new incoming session
Oct 17 01:21:13.507 DEBG ***EVENT: COAP_EVENT_SERVER_SESSION_NEW
Oct 17 01:21:13.507 DEBG *  127.0.0.1:5783 <-> 127.0.0.1:40207 (if1) UDP : netif: recv   24 bytes
Oct 17 01:21:13.507 DEBG coap_pdu_parse: UDP version not supported
Oct 17 01:21:13.507 DEBG ***EVENT: COAP_EVENT_BAD_PACKET
Oct 17 01:21:13.507 WARN discard malformed PDU
Oct 17 01:21:13.507 DEBG *  127.0.0.1:5783 <-> 127.0.0.1:40207 (if1) UDP : netif: sent    4 bytes

Is there something wrong with my sending script?

mrdeep1 commented 2 weeks ago

If you look at the server output, you will see that the source port (50912 40207) is changing per nc execution.

Try using the -p port nc option to keep the source port the same.