vstakhov / libucl

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

heap-use-after-free in ucl_util.c #302

Closed gabe-sherman closed 6 months ago

gabe-sherman commented 7 months ago

A heap-use-after-free error occurs in the below program upon malformed input. This behavior occurs at line 268 in ucl_util.c.

#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include "ucl.h"
#include "ucl_internal.h"
#include <ctype.h>

typedef ucl_object_t* (*ucl_msgpack_test)(void);

int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {

    if(size<3){
        return 0;
    }

    struct ucl_parser *parser;

    ucl_object_t *obj = ucl_object_new_full (UCL_OBJECT, 2);
    obj->type = UCL_OBJECT;

    parser = ucl_parser_new(UCL_PARSER_KEY_LOWERCASE);
    parser->stack = NULL;

    bool res = ucl_parser_add_chunk_full(parser, (const unsigned char*)data, size, 0, UCL_DUPLICATE_APPEND, UCL_PARSE_MSGPACK);

    ucl_parser_free (parser);
    return 0;
}

int main(int argc, char **argv)
{
    FILE *f;
    char *buf = NULL;
    long siz_buf;

    if(argc < 2)
    {
        fprintf(stderr, "no input file\n");
        goto err;
    }

    f = fopen(argv[1], "rb");
    if(f == NULL)
    {
        fprintf(stderr, "error opening input file %s\n", argv[1]);
        goto err;
    }

    fseek(f, 0, SEEK_END);

    siz_buf = ftell(f);
    rewind(f);

    if(siz_buf < 1) goto err;

    buf = (char*)malloc((size_t)siz_buf);
    if(buf == NULL)
    {
        fprintf(stderr, "malloc() failed\n");
        goto err;
    }

    if(fread(buf, (size_t)siz_buf, 1, f) != 1)
    {
        fprintf(stderr, "fread() failed\n");
        goto err;
    }

    (void)LLVMFuzzerTestOneInput((uint8_t*)buf, (size_t)siz_buf);

err:
    free(buf);

    return 0;
}

Test Environment

Ubuntu 22.04, 64bit

How to trigger

./filename poc

Version

Latest: f897d5a0fed3a4474a4c3137c7b92853845fed47

POC File

https://github.com/FuturesLab/POC/blob/main/ucl/oss-poc01

Address Sanitizer Output

=================================================================
==3443134==ERROR: AddressSanitizer: heap-use-after-free on address 0x606000000210 at pc 0x5555556ad9db bp 0x7fffffffcca0 sp 0x7fffffffcc98
READ of size 8 at 0x606000000210 thread T0
    #0 0x5555556ad9da in ucl_object_free_internal /home/gabesherman/harness_test/AutoHarn-Evaluation/ucl/lib_asan/src/ucl_util.c:268:19
    #1 0x5555556f30ba in ucl_object_dtor_unref_single /home/gabesherman/harness_test/AutoHarn-Evaluation/ucl/lib_asan/src/ucl_util.c:235:4
    #2 0x5555556dffd4 in ucl_object_dtor_unref /home/gabesherman/harness_test/AutoHarn-Evaluation/ucl/lib_asan/src/ucl_util.c:248:3
    #3 0x5555556ad9f2 in ucl_object_free_internal /home/gabesherman/harness_test/AutoHarn-Evaluation/ucl/lib_asan/src/ucl_util.c:269:8
    #4 0x5555556b9c7d in ucl_object_unref /home/gabesherman/harness_test/AutoHarn-Evaluation/ucl/lib_asan/src/ucl_util.c:3685:4
    #5 0x5555556b50da in ucl_parser_free /home/gabesherman/harness_test/AutoHarn-Evaluation/ucl/lib_asan/src/ucl_util.c:617:3
    #6 0x5555556ad162 in LLVMFuzzerTestOneInput /home/gabesherman/harness_test/AutoHarn-Results/ucl/ossfuzz-01/reproducer.c:27:2
    #7 0x5555556ad491 in main /home/gabesherman/harness_test/AutoHarn-Results/ucl/ossfuzz-01/reproducer.c:70:11
    #8 0x7ffff7c29d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
    #9 0x7ffff7c29e3f in __libc_start_main csu/../csu/libc-start.c:392:3
    #10 0x5555555ef414 in _start (/home/gabesherman/harness_test/AutoHarn-Results/ucl/ossfuzz-01/reproducer+0x9b414) (BuildId: a1238829e2e956a6367ead39a5e66c3c12e74e04)

0x606000000210 is located 16 bytes inside of 64-byte region [0x606000000200,0x606000000240)
freed by thread T0 here:
    #0 0x555555671fb2 in free (/home/gabesherman/harness_test/AutoHarn-Results/ucl/ossfuzz-01/reproducer+0x11dfb2) (BuildId: a1238829e2e956a6367ead39a5e66c3c12e74e04)
    #1 0x5555556ae651 in ucl_object_dtor_free /home/gabesherman/harness_test/AutoHarn-Evaluation/ucl/lib_asan/src/ucl_util.c:208:4
    #2 0x5555556dffc6 in ucl_object_dtor_unref /home/gabesherman/harness_test/AutoHarn-Evaluation/ucl/lib_asan/src/ucl_util.c:244:3
    #3 0x5555556ad9f2 in ucl_object_free_internal /home/gabesherman/harness_test/AutoHarn-Evaluation/ucl/lib_asan/src/ucl_util.c:269:8
    #4 0x5555556f30ba in ucl_object_dtor_unref_single /home/gabesherman/harness_test/AutoHarn-Evaluation/ucl/lib_asan/src/ucl_util.c:235:4
    #5 0x5555556dffd4 in ucl_object_dtor_unref /home/gabesherman/harness_test/AutoHarn-Evaluation/ucl/lib_asan/src/ucl_util.c:248:3
    #6 0x5555556ad9f2 in ucl_object_free_internal /home/gabesherman/harness_test/AutoHarn-Evaluation/ucl/lib_asan/src/ucl_util.c:269:8
    #7 0x5555556b9c7d in ucl_object_unref /home/gabesherman/harness_test/AutoHarn-Evaluation/ucl/lib_asan/src/ucl_util.c:3685:4
    #8 0x5555556b50da in ucl_parser_free /home/gabesherman/harness_test/AutoHarn-Evaluation/ucl/lib_asan/src/ucl_util.c:617:3
    #9 0x5555556ad162 in LLVMFuzzerTestOneInput /home/gabesherman/harness_test/AutoHarn-Results/ucl/ossfuzz-01/reproducer.c:27:2
    #10 0x5555556ad491 in main /home/gabesherman/harness_test/AutoHarn-Results/ucl/ossfuzz-01/reproducer.c:70:11
    #11 0x7ffff7c29d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16

previously allocated by thread T0 here:
    #0 0x55555567225e in __interceptor_malloc (/home/gabesherman/harness_test/AutoHarn-Results/ucl/ossfuzz-01/reproducer+0x11e25e) (BuildId: a1238829e2e956a6367ead39a5e66c3c12e74e04)
    #1 0x5555556d5904 in ucl_object_new_full /home/gabesherman/harness_test/AutoHarn-Evaluation/ucl/lib_asan/src/ucl_util.c:3014:9
    #2 0x555555793b26 in ucl_msgpack_consume /home/gabesherman/harness_test/AutoHarn-Evaluation/ucl/lib_asan/src/ucl_msgpack.c:1102:22
    #3 0x555555790104 in ucl_parse_msgpack /home/gabesherman/harness_test/AutoHarn-Evaluation/ucl/lib_asan/src/ucl_msgpack.c:1362:8
    #4 0x5555557135ed in ucl_parser_add_chunk_full /home/gabesherman/harness_test/AutoHarn-Evaluation/ucl/lib_asan/src/ucl_parser.c:3053:12
    #5 0x5555556ad154 in LLVMFuzzerTestOneInput /home/gabesherman/harness_test/AutoHarn-Results/ucl/ossfuzz-01/reproducer.c:25:13
    #6 0x5555556ad491 in main /home/gabesherman/harness_test/AutoHarn-Results/ucl/ossfuzz-01/reproducer.c:70:11
    #7 0x7ffff7c29d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16

SUMMARY: AddressSanitizer: heap-use-after-free /home/gabesherman/harness_test/AutoHarn-Evaluation/ucl/lib_asan/src/ucl_util.c:268:19 in ucl_object_free_internal
Shadow bytes around the buggy address:
  0x0c0c7fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c0c7fff8000: fa fa fa fa 00 00 00 00 00 00 00 00 fa fa fa fa
  0x0c0c7fff8010: 00 00 00 00 00 00 00 00 fa fa fa fa 00 00 00 00
  0x0c0c7fff8020: 00 00 00 07 fa fa fa fa 00 00 00 00 00 00 00 00
  0x0c0c7fff8030: fa fa fa fa 00 00 00 00 00 00 00 00 fa fa fa fa
=>0x0c0c7fff8040: fd fd[fd]fd fd fd fd fd fa fa fa fa fd fd fd fd
  0x0c0c7fff8050: fd fd fd fd fa fa fa fa 00 00 00 00 00 00 00 00
  0x0c0c7fff8060: fa fa fa fa 00 00 00 00 00 00 00 00 fa fa fa fa
  0x0c0c7fff8070: 00 00 00 00 00 00 00 00 fa fa fa fa 00 00 00 00
  0x0c0c7fff8080: 00 00 00 00 fa fa fa fa 00 00 00 00 00 00 00 00
  0x0c0c7fff8090: fa fa fa fa 00 00 00 00 00 00 00 00 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
==3443134==ABORTING
vstakhov commented 7 months ago

It looks like ext type in messagepack is not properly supported in libucl.

gabe-sherman commented 7 months ago

Sounds good. I appreciate the analysis. In your opinion would you consider this crash a false positive? This program was taken from your fuzzing repository so we're just trying to determine whether this crash should be considered real or not: https://github.com/vstakhov/libucl/blob/master/tests/fuzzers/ucl_msgpack_fuzzer.c

vstakhov commented 7 months ago

No, not these two issues: they reveal a very important problem, thank you!