vstakhov / libucl

Universal configuration library parser
BSD 2-Clause "Simplified" License
1.63k stars 139 forks source link

Heap-buffer-overflow in ucl_maybe_parse_number function of ucl_parser.c:182:11 #275

Closed HotSpurzzZ closed 7 months ago

HotSpurzzZ commented 1 year ago

When I use tests/fuzzers/ucl_add_string_fuzzer.c for fuzz testing, I found Heap-buffer-overflow in ucl_maybe_parse_number function of ucl_parser.c:882:11 This seems similar toissue263 but has not been fixed in the latest version.

Verification steps

CC = clang
CFLAGS = -O1 -fno-omit-frame-pointer -gline-tables-only -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=address -fsanitize-address-use-after-scope -fsanitize=fuzzer-no-link
LIB_FUZZING_ENGINE="-fsanitize=fuzzer"

cd libucl 
./autogen.sh && ./configure
make

$CC $CFLAGS $LIB_FUZZING_ENGINE tests/fuzzers/ucl_add_string_fuzzer.c \
    -DHAVE_CONFIG_H -I./src -I./include src/.libs/libucl.a -I./ \
    -o $OUT/ucl_add_string_fuzzer
./ucl_add_string_fuzzer $poc

POC file

poc_hof.zip

AddressSanitizer output

INFO: Seed: 686354357
INFO: Loaded 1 modules   (3173 inline 8-bit counters): 3173 [0x602950, 0x6035b5),
INFO: Loaded 1 PC tables (3173 PCs): 3173 [0x5b12d8,0x5bd928),
./ucl_add_string_fuzzer: Running 1 inputs 1 time(s) each.
Running: ../libucl_heap_overflow_ucl_maybe_parse_number
=================================================================
==1214584==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x61b000000d41 at pc 0x00000054f029 bp 0x7fffffffd450 sp 0x7fffffffd448
READ of size 1 at 0x61b000000d41 thread T0
    #0 0x54f028 in ucl_maybe_parse_number /home/libucl/src/ucl_parser.c:882:11
    #1 0x5635dc in ucl_lex_number /home/libucl/src/ucl_parser.c:1055:8
    #2 0x55c7aa in ucl_parse_value /home/libucl/src/ucl_parser.c:1928:10
    #3 0x554d62 in ucl_state_machine /home/libucl/src/ucl_parser.c:2538:29
    #4 0x553a7d in ucl_parser_add_chunk_full /home/libucl/src/ucl_parser.c:3026:12
    #5 0x557352 in ucl_parser_add_chunk_priority /home/libucl/src/ucl_parser.c:3061:9
    #6 0x5577af in ucl_parser_add_string_priority /home/libucl/src/ucl_parser.c:3124:9
    #7 0x557804 in ucl_parser_add_string /home/libucl/src/ucl_parser.c:3136:9
    #8 0x54d97e in LLVMFuzzerTestOneInput /home/libucl/tests/fuzzers/ucl_add_string_fuzzer.c:17:2
    #9 0x4586e1 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) (/home/libucl/ucl_add_string_fuzzer+0x4586e1)
    #10 0x443e52 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) (/home/libucl/ucl_add_string_fuzzer+0x443e52)
    #11 0x449906 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) (/home/libucl/ucl_add_string_fuzzer+0x449906)
    #12 0x4725c2 in main (/home/libucl/ucl_add_string_fuzzer+0x4725c2)
    #13 0x7ffff7a6a082 in __libc_start_main /build/glibc-iA3wr8/glibc-2.31/csu/../csu/libc-start.c:308:16
    #14 0x41e51d in _start (/home/libucl/ucl_add_string_fuzzer+0x41e51d)

0x61b000000d41 is located 0 bytes to the right of 1473-byte region [0x61b000000780,0x61b000000d41)
allocated by thread T0 here:
    #0 0x51e24d in malloc (/home/libucl/ucl_add_string_fuzzer+0x51e24d)
    #1 0x432907 in operator new(unsigned long) (/home/libucl/ucl_add_string_fuzzer+0x432907)
    #2 0x443e52 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) (/home/libucl/ucl_add_string_fuzzer+0x443e52)
    #3 0x449906 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) (/home/libucl/ucl_add_string_fuzzer+0x449906)
    #4 0x4725c2 in main (/home/libucl/ucl_add_string_fuzzer+0x4725c2)
    #5 0x7ffff7a6a082 in __libc_start_main /build/glibc-iA3wr8/glibc-2.31/csu/../csu/libc-start.c:308:16

SUMMARY: AddressSanitizer: heap-buffer-overflow /home/libucl/src/ucl_parser.c:882:11 in ucl_maybe_parse_number
Shadow bytes around the buggy address:
  0x0c367fff8150: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c367fff8160: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c367fff8170: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c367fff8180: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c367fff8190: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c367fff81a0: 00 00 00 00 00 00 00 00[01]fa fa fa fa fa fa fa
  0x0c367fff81b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c367fff81c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c367fff81d0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c367fff81e0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c367fff81f0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
  Shadow gap:              cc
==1214584==ABORTING
vstakhov commented 9 months ago

Strange, I cannot reproduce this issue.

vstakhov commented 9 months ago

I think this patch should fix it.