vstakhov / libucl

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

heap-buffer overflow in ucl_util.c #301

Closed gabe-sherman closed 7 months ago

gabe-sherman commented 7 months ago

A heap-buffer overflow occurs in the below program. This behavior occurs at line 212 in ucl_util.c

#include "ucl.h"
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
typedef uint8_t   u8;   
typedef uint16_t  u16;  
typedef uint32_t  u32;  
typedef uint64_t  u64;
typedef unsigned int usize;
typedef int8_t  i8;
typedef int16_t i16;
typedef int32_t i32;
typedef int64_t i64;
typedef int isize;
typedef float f32;
typedef double f64;
int main() {
    i32 v0 = -1026770411; // flags
    struct ucl_parser *v1 = ucl_parser_new(0); // parser
    if (v1 == NULL) return 0;
    struct ucl_parser *v3 = v1; // parser
    struct ucl_object_s *v4 = ucl_object_new(); // head
    if (v4 == NULL) return 0;
    enum ucl_type v7 = { 7,  }; // type_
    u32 v8 = 341; // priority
    struct ucl_object_s *v9 = ucl_object_new_full(v7, v8); // elt
    if (v9 == NULL) return 0;
    struct ucl_object_s *v12 = ucl_elt_append(v4, v9); // paths
    if (v12 == NULL) return 0;
    bool v15 = ucl_set_include_path(v3, v12); // $relative
    if (v15 == false) exit(1);

    u8 v16_tmp[] = {115, 32, 61, 32, 80, 48, 121, 10, 10, 35, 32, 83, 116, 114, 105, 110, 103, 115, 10, 107, 101, 121, 49, 32, 61, 32, 34, 115, 111, 109, 101, 32, 115, 116, 114, 105, 110, 103, 34, 59, 10, 107, 101, 121, 50, 32, 61, 32, 47, 115, 111, 109, 101, 47, 112, 97, 116, 104, 59, 10, 107, 101, 121, 51, 32, 61, 32, 49, 49, 49, 115, 111, 109, 32, 49, 107, 83, 10, 107, 101, 121, 52, 32, 61, 33, 53, 77, 10, 107, 101, 121, 53, 32, 61, 32, 49, 48, 107, 83, 10, 107, 101, 121, 54, 32, 61, 32, 49, 48, 121, 10, 10, 35, 32, 83, 116, 107, 101, 121, 49, 32, 61, 32, 49, 115, 10, 107, 101, 121, 50, 32, 61, 32, 49, 109, 98, 10, 10, 107, 101, 121, 51, 54, 32, 61, 32, 49, 48, 121, 10, 10, 35, 32, 83, 116, 114, 105, 110, 97, 114, 97, 109, 50, 32, 61, 32, 118, 97, 108, 117, 101, 44, 32, 112, 97, 114, 97, 109, 51, 32, 61, 32, 91, 34, 118, 97, 108, 117, 101, 49, 34, 44, 32, 118, 97, 108, 117, 101, 50, 44, 32, 49, 48, 48, 53, 48, 48, 93, 125, 125, 10, 115, 101, 99, 116, 105, 111, 110, 50, 32, 123, 32, 112, 97, 114, 97, 109, 49, 32, 61, 32, 123, 107, 101, 121, 32, 61, 32, 118, 97, 108, 117, 101, 125, 44, 32, 112, 97, 114, 97, 109, 49, 32, 61, 32, 91, 34, 107, 101, 121, 34, 93, 125, 10, 10, 35, 32, 78, 117, 109, 98, 101, 114, 115, 11, 107, 101, 121, 49, 32, 61, 32, 49, 115, 10, 107, 101, 121, 50, 32, 61, 32, 49, 109, 105, 110, 10, 107, 101, 121, 51, 32, 61, 32, 49, 107, 98, 10, 107, 101, 121, 52, 32, 61, 32, 53, 77, 10, 107, 101, 121, 53, 32, 61, 32, 49, 48, 107, 83, 10, 107, 101, 121, 54, 32, 61, 32, 49, 48, 121, 10, 10, 35, 32, 83, 116, 114, 105, 110, 103, 115, 10, 107, 101, 121, 49, 32, 61, 32, 35, 115, 111, 109, 101, 32, 115, 116, 114, 105, 110, 103, 34, 59, 10, 107, 101, 121, 50, 32, 61, 32, 47, 115, 111, 109, 101, 47, 112, 97, 116, 104, 59, 10, 107, 101, 121, 51, 32, 61, 32, 49, 49, 49, 115, 111, 109, 101, 44, 10, 107, 101, 121, 52, 58, 32, 115, 49, 44, 10, 34, 107, 101, 121, 53, 34, 58, 32, 34, 92, 110, 92, 114, 49, 50, 51, 34, 10, 10, 35, 32, 86, 97, 114, 105, 97, 98, 108, 101, 115, 10, 107, 101, 121, 118, 97, 114, 32, 32, 61, 32, 49, 107, 98, 10, 107, 101, 121, 52, 32, 61, 32, 53, 77, 10, 107, 101, 121, 53, 32, 61, 32, 49, 48, 109, 83, 10, 107, 101, 121, 54, 32, 61, 32, 49, 48, 121, 10, 10, 35, 32, 83, 116, 114, 105, 110, 103, 115, 10, 107, 101, 121, 49, 32, 61, 32, 35, 115, 111, 109, 101, 32, 115, 116, 114, 105, 110, 103, 34, 59, 10, 107, 101, 121, 50, 32, 61, 32, 47, 115, 111, 109, 101, 47, 112, 97, 116, 104, 59, 10, 107, 101, 121, 51, 32, 61, 32, 49, 49, 49, 115, 111, 109, 101, 44, 10, 107, 101, 121, 52, 58, 32, 115, 49, 44, 10, 35, 107, 101, 121, 53, 34, 58, 32, 34, 92, 110, 92, 114, 49, 50, 51, 34, 10, 10, 35, 32, 86, 97, 114, 105, 97, 98, 108, 101, 115, 10, 107, 101, 121, 118, 97, 114, 32, 61, 32, 34, 36, 65, 66, 73, 116, 101, 115, 116, 34, 59, 0, }; // data
    u8 *v16 = malloc(sizeof v16_tmp);
    memcpy(v16, v16_tmp, sizeof v16_tmp);
    u8 *v17 = v16; // data
    usize v18 = 627; // len
    u32 v19 = 87; // priority
    bool v20 = ucl_parser_add_chunk_priority(v3, v17, v18, v19); // $relative
    //if (v20 == false) exit(1);

    usize v21 = 627; // len
    u32 v22 = 87; // priority
    bool v23 = ucl_parser_add_chunk_priority(v3, v17, v21, v22); // $relative
    //if (v23 == false) exit(1);

    if (v1 == NULL) exit(0);
    ucl_parser_free(v1); // $target
}

Test Environment

Ubuntu 22.04, 64bit

How to trigger

./filename

Version

Latest: f897d5a0fed3a4474a4c3137c7b92853845fed47

Address Sanitizer Output

=================================================================
==3311835==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x6060000001e0 at pc 0x5555556ae61e bp 0x7fffffffc7d0 sp 0x7fffffffc7c8
READ of size 8 at 0x6060000001e0 thread T0
    #0 0x5555556ae61d in ucl_object_dtor_free /home/gabesherman/harness_test/AutoHarn-Evaluation/ucl/lib_asan/src/ucl_util.c:212:12
    #1 0x5555556dfee6 in ucl_object_dtor_unref /home/gabesherman/harness_test/AutoHarn-Evaluation/ucl/lib_asan/src/ucl_util.c:244:3
    #2 0x5555556adf09 in ucl_object_free_internal /home/gabesherman/harness_test/AutoHarn-Evaluation/ucl/lib_asan/src/ucl_util.c:286:3
    #3 0x5555556f2fda in ucl_object_dtor_unref_single /home/gabesherman/harness_test/AutoHarn-Evaluation/ucl/lib_asan/src/ucl_util.c:235:4
    #4 0x5555556dfef4 in ucl_object_dtor_unref /home/gabesherman/harness_test/AutoHarn-Evaluation/ucl/lib_asan/src/ucl_util.c:248:3
    #5 0x5555556adf09 in ucl_object_free_internal /home/gabesherman/harness_test/AutoHarn-Evaluation/ucl/lib_asan/src/ucl_util.c:286:3
    #6 0x5555556b9b9d in ucl_object_unref /home/gabesherman/harness_test/AutoHarn-Evaluation/ucl/lib_asan/src/ucl_util.c:3685:4
    #7 0x5555556b5158 in ucl_parser_free /home/gabesherman/harness_test/AutoHarn-Evaluation/ucl/lib_asan/src/ucl_util.c:621:3
    #8 0x5555556ad34e in main /home/gabesherman/harness_test/AutoHarn-Results/ucl/hopper-28/reproducer.c:51:5
    #9 0x7ffff7c29d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
    #10 0x7ffff7c29e3f in __libc_start_main csu/../csu/libc-start.c:392:3
    #11 0x5555555ef3e4 in _start (/home/gabesherman/harness_test/AutoHarn-Results/ucl/hopper-28/reproducer+0x9b3e4) (BuildId: b53fb487f27249d4f11f8b4c7d5b9b070f30b5ee)

0x6060000001e0 is located 0 bytes to the right of 64-byte region [0x6060000001a0,0x6060000001e0)
allocated by thread T0 here:
    #0 0x55555567222e in __interceptor_malloc (/home/gabesherman/harness_test/AutoHarn-Results/ucl/hopper-28/reproducer+0x11e22e) (BuildId: b53fb487f27249d4f11f8b4c7d5b9b070f30b5ee)
    #1 0x5555556dd6c4 in ucl_object_copy_internal /home/gabesherman/harness_test/AutoHarn-Evaluation/ucl/lib_asan/src/ucl_util.c:3608:8
    #2 0x5555556df778 in ucl_object_copy_internal /home/gabesherman/harness_test/AutoHarn-Evaluation/ucl/lib_asan/src/ucl_util.c:3658:24
    #3 0x5555556c8149 in ucl_object_copy /home/gabesherman/harness_test/AutoHarn-Evaluation/ucl/lib_asan/src/ucl_util.c:3672:9
    #4 0x5555557233d2 in ucl_set_include_path /home/gabesherman/harness_test/AutoHarn-Evaluation/ucl/lib_asan/src/ucl_parser.c:3173:26
    #5 0x5555556ad1a0 in main /home/gabesherman/harness_test/AutoHarn-Results/ucl/hopper-28/reproducer.c:33:16
    #6 0x7ffff7c29d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16

SUMMARY: AddressSanitizer: heap-buffer-overflow /home/gabesherman/harness_test/AutoHarn-Evaluation/ucl/lib_asan/src/ucl_util.c:212:12 in ucl_object_dtor_free
Shadow bytes around the buggy address:
  0x0c0c7fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  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 06 fa fa fa fa 00 00 00 00
  0x0c0c7fff8020: 00 00 00 00 fa fa fa fa fd fd fd fd fd fd fd fd
=>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 fd fd fd fd fd fd fd fd
  0x0c0c7fff8060: fa fa fa fa fd fd fd fd fd fd fd fd fa fa fa fa
  0x0c0c7fff8070: fd fd fd fd fd fd fd fd fa fa fa fa fd fd fd fd
  0x0c0c7fff8080: fd fd fd fd fa fa fa fa fd fd fd fd fd fd fd fd
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
==3311835==ABORTING
vstakhov commented 7 months ago

You cannot use USERDATA object as normal objects, they are intended just to pass data from and within lua. Again, this is something nobody will use but I should probably add another fool protection here.