Uploaded image for project: 'C Driver'
  1. C Driver
  2. CDRIVER-4421

Heap-Buffer-Overflow Bug Report, Fuzzing suggestion

    • Type: Icon: Bug Bug
    • Resolution: Works as Designed
    • Priority: Icon: Unknown Unknown
    • None
    • Affects Version/s: 1.9.0
    • Component/s: BSON
    • Labels:
      None

      Summary

      Heap-Buffer-Overflow Bug in libbson.

      Recommendations

      2 suggestions for security improvements.
      [1] Request CVE number for this bug to inform users to prevent potential security vulnerabilities.
      [2] Register below fuzzer code to ossfuzz for continuous fuzzing.

       

      Environment

      • Commit: ffc8d983ecf6b46d5404f5cc20e756a85dfcbfd2
      • Operating System / Platform : ubuntu 18.04
      • Compiler : clang++ 10.0.1

        How to Reproduce

       

      #include "bson/bson.h"
      #include <string>const std::string input1 {
        0x0e, 0x00, 0x00, 0x00, 0x03, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e,
        0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e,
        0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e,
        0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e,
        0x0e, 0x0e, (char)0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff,
        (char)0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff,
        (char)0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff,
        (char)0xff, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e,
        0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, (char)0x94, 0x0e, 0x0e, 0x0e,
        0x0e, 0x0e, 0x0e, 0x0e, 0x0e, (char)0x9a, (char)0xa3, (char)0xa3, (char)0xa3,
        (char)0xa3, (char)0xa3, 0x2d, (char)0xa3, 0x00, 0x00, 0x00, 0x03 };
      const std::string input2 = "";
      const std::string input3 = "";int main(int argc, char * argv[]) {
        bson_t *b = 0;  b = bson_new();
        if (!b) goto out;  if (!bson_append_regex(
            b, input1.c_str(), input1.size(), input2.c_str(), input3.c_str()))
          goto out;out:
        if (b) bson_destroy(b);
        return 0;
      }

       

      Build Steps

       

      mkdir -p build && cd build
      cmake -DBUILD_SHARED_LIBS=OFF -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_AR=/bin/llvm-ar -DCMAKE_VERBOSE_MAKEFILE=ON -DCMAKE_C_FLAGS=-g -DCMAKE_CXX_FLAGS=-g -DCMAKE_EXE_LINKER_FLAGS=-g -DCMAKE_SHARED_LINKER_FLAGS=-g ..
      make -j16 V=1 

       

       

      Additional Background

      Reason

       

      // bson-private.h:57
      #define BSON_INLINE_DATA_SIZE 120BSON_ALIGNED_BEGIN (128)
      typedef struct {
         bson_flags_t flags;
         uint32_t len;
         uint8_t data[BSON_INLINE_DATA_SIZE]; // data size is 120
      } bson_impl_inline_t BSON_ALIGNED_END (128);// bson.c:379
      static bool
      _bson_append (bson_t *bson,              // bson=0x60c000000100 : {flags = 1, len = 5, padding = "\005\000\000\000\000", '\276' <repeats 115 times>}
                    uint32_t n_pairs,          // n_pairs=5
                    uint32_t n_bytes,          // n_bytes=115
                    uint32_t first_len,        // first_len=1
                    const uint8_t *first_data, // first_data=0x536b60 : '\v'
                    ...)
      {
         va_list args;
         bool ok;   BSON_ASSERT (n_pairs);
         BSON_ASSERT (first_len);
         BSON_ASSERT (first_data);   if (BSON_UNLIKELY (n_bytes > (BSON_MAX_SIZE - bson->len))) {
            return false;
         }   va_start (args, first_data);
         ok = _bson_append_va (bson, n_bytes, n_pairs, first_len, first_data, args); // Called
         va_end (args);   return ok;
      }...// bson.c:310
      static BSON_INLINE bool
      _bson_append_va (bson_t *bson,              // bson=0x60c000000100 : {flags = 1, len = 121, padding = "y\000\000\000\v\016\000\000\000\003", '\016' <repeats 49 times>, '\377' <repeats 18 times>, '\016' <repeats 19 times>, "\224\016\016\016\016\016\016\016\016\232\243\243\243\243\243-\243\000\000\000\003\000\000"}
                       uint32_t n_bytes,          // n_bytes=115
                       uint32_t n_pairs,          // n_pairs=5
                       uint32_t first_len,        // first_len=1
                       const uint8_t *first_data, // first_data=0x536b60 : "\v"
                       va_list args)              // args: { gp_offset = 40, fp_offset = 48, overflow_arg_area = 0x7fffffffe3f0, reg_save_area = 0x7fffffffe2b0 }
      {
         const uint8_t *data;
         uint32_t data_len;
         uint8_t *buf;   BSON_ASSERT (!(bson->flags & BSON_FLAG_IN_CHILD));
         BSON_ASSERT (!(bson->flags & BSON_FLAG_RDONLY));   if (BSON_UNLIKELY (!_bson_grow (bson, n_bytes))) {
            return false;
         }   data = first_data;
         data_len = first_len;   buf = _bson_data (bson) + bson->len - 1; // _bson_data : "\005\000\000\000\000", '\276' <repeats 115 times>,  bson->len : 5   do {
            n_pairs--;
            memcpy (buf, data, data_len); // *data : "\v", data_len : 1
            bson->len += data_len;
            buf += data_len;      if (n_pairs) {
               data_len = va_arg (args, uint32_t); // 112, 1, 1, 1
               data = va_arg (args, const uint8_t *);
            }
         } while (n_pairs);   *buf = '\0'; // Crashed, buf is over the range of bson->data.
                      // Because 5, 112, 1, 1, 1 size of data was assigned, but size of bson->data is 120.   return true;
      } 

       

       

      Address Sanitizer Report

       

      =================================================================
      ==237==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60c000000180 at pc 0x0000004dd932 bp 0x7fff8bf35a50 sp 0x7fff8bf35a48
      WRITE of size 1 at 0x60c000000180 thread T0
          #0 0x4dd931 in _bson_append_va /root/fuzz-test-generation/exp/libbson/src/bson/bson.c:348:9
          #1 0x4c9fcb in _bson_append /root/fuzz-test-generation/exp/libbson/src/bson/bson.c:404:9
          #2 0x4d1c7b in bson_append_regex /root/fuzz-test-generation/exp/libbson/src/bson/bson.c:1575:9
          #3 0x4c6acf in main /root/fuzz-test-generation/AutoFuzz_Exp/archive/libbson/poc1.cpp:25:8
          #4 0x7ff072c51c86 in __libc_start_main /build/glibc-CVJwZb/glibc-2.27/csu/../csu/libc-start.c:310
          #5 0x41c299 in _start (/root/fuzz-test-generation/exp_musang/libbson/poc1+0x41c299)0x60c000000180 is located 0 bytes to the right of 128-byte region [0x60c000000100,0x60c000000180)
      allocated by thread T0 here:
          #0 0x4949dd in malloc (/root/fuzz-test-generation/exp_musang/libbson/poc1+0x4949dd)
          #1 0x5092cf in bson_malloc /root/fuzz-test-generation/exp/libbson/src/bson/bson-memory.c:68:11
          #2 0x4d56ac in bson_new /root/fuzz-test-generation/exp/libbson/src/bson/bson.c:2015:11
          #3 0x4c6a52 in main /root/fuzz-test-generation/AutoFuzz_Exp/archive/libbson/poc1.cpp:22:7
          #4 0x7ff072c51c86 in __libc_start_main /build/glibc-CVJwZb/glibc-2.27/csu/../csu/libc-start.c:310SUMMARY: AddressSanitizer: heap-buffer-overflow /root/fuzz-test-generation/exp/libbson/src/bson/bson.c:348:9 in _bson_append_va
      Shadow bytes around the buggy address:
        0x0c187fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
        0x0c187fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
        0x0c187fff8000: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
        0x0c187fff8010: 00 00 00 00 00 00 01 fa fa fa fa fa fa fa fa fa
        0x0c187fff8020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
      =>0x0c187fff8030:[fa]fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
        0x0c187fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
        0x0c187fff8050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
        0x0c187fff8060: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
        0x0c187fff8070: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
        0x0c187fff8080: 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
      ==237==ABORTING
      Fuzzer Code

       

      #include "Fuzzer/FuzzedDataProvider.h"
      #include "bson/bson.h"
      
      static void test(FuzzedDataProvider &provider) {
        auto input1 = provider.ConsumeRandomLengthString();
        auto input2 = provider.ConsumeRandomLengthString();
        auto input3 = provider.ConsumeRandomLengthString();
      
        for (int i = 0; i < input1.size(); ++i) {
          printf("%02x ", input1[i]);
        }
        printf("1:\n\n");
      
        for (int i = 0; i < input2.size(); ++i) {
          printf("%02x ", input2[i]);
        }
        printf("2:\n\n");
      
        for (int i = 0; i < input3.size(); ++i) {
          printf("%02x ", input3[i]);
        }
        printf("3:\n\n");
      
        bson_t *b = 0;
      
        b = bson_new();
        if (!b) goto out;
      
        if (!bson_append_regex(
            b, input1.c_str(), input1.size(), input2.c_str(), input3.c_str()))
          goto out;
      
      out:
        if (b) bson_destroy(b);
      }
      
      extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, uint32_t size) {
        FuzzedDataProvider provider(data, size);
        test(provider);
        return 0;
      } 

       

       

       

            Assignee:
            ezra.chung@mongodb.com Ezra Chung
            Reporter:
            afosscontact@gmail.com osscontact af
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved: