google / leveldb

LevelDB is a fast key-value storage library written at Google that provides an ordered mapping from string keys to string values.
BSD 3-Clause "New" or "Revised" License
35.69k stars 7.72k forks source link

Null Pointer Dereference Vulnerability in leveldb_open #1183

Open YancyLii opened 2 months ago

YancyLii commented 2 months ago

Description

The leveldb_open function in LevelDB is vulnerable to a null pointer dereference issue, where it directly converts a const char* name to a std::string without null checks. This can lead to a std::logic_error being thrown if name is nullptr.

Steps to Reproduce

  1. Call leveldb_open with name set to nullptr.
  2. Observe a crash due to unhandled std::logic_error.

Expected Behavior

The function should handle nullptr inputs gracefully, either by returning an error or by rejecting the operation without crashing.

Suggested Fix

Implement a null check before using the name variable:


if (name == nullptr) {
  if (errptr != nullptr) {
    *errptr = strdup("Database name is null");
  }
  return nullptr;
}

##My Fuzzer
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
  leveldb_options_t* options = nullptr;
  const char* path = nullptr;
  char** error = nullptr;
  leveldb_t* db = leveldb_open(options, path, error);
  if (db != nullptr) {
    leveldb_create_snapshot(db);
  }
  return 0;
}

root@2300d4f25744:/volume/PromptDriver# ./results/leveldb/fuzzer/Test_leveldb_Id56 ./results/leveldb/fuzzing/run1/out/Test_leveldb_Id56crash-da39a3ee5e6b4b0d3255bfef95601890afd80709 
INFO: Seed: 1250284794
INFO: Loaded 1 modules   (5466 inline 8-bit counters): 5466 [0x703f3f, 0x705499), 
INFO: Loaded 1 PC tables (5466 PCs): 5466 [0x68d6d0,0x6a2c70), 
./results/leveldb/fuzzer/Test_leveldb_Id56: Running 1 inputs 1 time(s) each.
Running: ./results/leveldb/fuzzing/run1/out/Test_leveldb_Id56crash-da39a3ee5e6b4b0d3255bfef95601890afd80709
terminate called after throwing an instance of 'std::logic_error'
  what():  basic_string::_M_construct null not valid
==325550== ERROR: libFuzzer: deadly signal
    #0 0x5292b1 in __sanitizer_print_stack_trace (/volume/PromptDriver/results/leveldb/fuzzer/Test_leveldb_Id56+0x5292b1)
    #1 0x474418 in fuzzer::PrintStackTrace() (/volume/PromptDriver/results/leveldb/fuzzer/Test_leveldb_Id56+0x474418)
    #2 0x459563 in fuzzer::Fuzzer::CrashCallback() (/volume/PromptDriver/results/leveldb/fuzzer/Test_leveldb_Id56+0x459563)
    #3 0x7fd3a5ac241f  (/lib/x86_64-linux-gnu/libpthread.so.0+0x1441f)
    #4 0x7fd3a58d200a in raise (/lib/x86_64-linux-gnu/libc.so.6+0x4300a)
    #5 0x7fd3a58b1858 in abort (/lib/x86_64-linux-gnu/libc.so.6+0x22858)
    #6 0x7fd3a5cbe8d0  (/lib/x86_64-linux-gnu/libstdc++.so.6+0x9e8d0)
    #7 0x7fd3a5cca37b  (/lib/x86_64-linux-gnu/libstdc++.so.6+0xaa37b)
    #8 0x7fd3a5cca3e6 in std::terminate() (/lib/x86_64-linux-gnu/libstdc++.so.6+0xaa3e6)
    #9 0x7fd3a5cca698 in __cxa_throw (/lib/x86_64-linux-gnu/libstdc++.so.6+0xaa698)
    #10 0x7fd3a5cc11db in std::__throw_logic_error(char const*) (/lib/x86_64-linux-gnu/libstdc++.so.6+0xa11db)
    #11 0x7fd3a5d65d9a in void std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_construct<char const*>(char const*, char const*, std::forward_iterator_tag) (/lib/x86_64-linux-gnu/libstdc++.so.6+0x145d9a)
    #12 0x552aaf in leveldb_open /mnt/UTopia/exp/leveldb/src/db/c.cc:171:48
    #13 0x55281e in LLVMFuzzerTestOneInput /mnt/PromptDriver/results/leveldb/driver/Test_leveldb_Id56.cc:52:19
    #14 0x45ac21 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) (/volume/PromptDriver/results/leveldb/fuzzer/Test_leveldb_Id56+0x45ac21)
    #15 0x446392 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) (/volume/PromptDriver/results/leveldb/fuzzer/Test_leveldb_Id56+0x446392)
    #16 0x44be46 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) (/volume/PromptDriver/results/leveldb/fuzzer/Test_leveldb_Id56+0x44be46)
    #17 0x474b02 in main (/volume/PromptDriver/results/leveldb/fuzzer/Test_leveldb_Id56+0x474b02)
    #18 0x7fd3a58b3082 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x24082)
    #19 0x420a3d in _start (/volume/PromptDriver/results/leveldb/fuzzer/Test_leveldb_Id56+0x420a3d)

NOTE: libFuzzer has rudimentary signal handlers.
      Combine libFuzzer with AddressSanitizer or similar for better crash reports.
SUMMARY: libFuzzer: deadly signal
fmorgner commented 1 month ago

The documentation of the C API for leveldb, found here, clearly states that all pointer arguments must never be NULL. It is the responsibility of the caller to ensure that they never pass a null pointer to any of the C API functions. Violating this requirement is a programmer error.