Skip to content

Null pointer dereference in ImportBlackboardFromJSON when entry creation fails #921

Closed
@cktii

Description

@cktii

Description

A null pointer dereference occurs in ImportBlackboardFromJSON when attempting to use an entry pointer without verifying that the entry was successfully created. This happens because the code assumes createEntry followed by getEntry will always return a valid entry.

void ImportBlackboardFromJSON(const nlohmann::json& json, Blackboard& blackboard)
{
for(auto it = json.begin(); it != json.end(); ++it)
{
if(auto res = JsonExporter::get().fromJson(it.value()))
{
auto entry = blackboard.getEntry(it.key());
if(!entry)
{
blackboard.createEntry(it.key(), res->second);
entry = blackboard.getEntry(it.key());
}
entry->value = res->first;
}
}
}

Found in commit: 48f6c5b

Bug Class

Memory Safety - Null Pointer Dereference

Root Cause

void ImportBlackboardFromJSON(const nlohmann::json& json, Blackboard& blackboard)
{
  for(auto it = json.begin(); it != json.end(); ++it)
  {
    if(auto res = JsonExporter::get().fromJson(it.value()))
    {
      auto entry = blackboard.getEntry(it.key());
      if(!entry)
      {
        blackboard.createEntry(it.key(), res->second);
        entry = blackboard.getEntry(it.key());  // Could still return nullptr
      }
      entry->value = res->first;  // CRASH: Null pointer dereference
    }
  }
}

The issue occurs because:

  • Code checks if initial getEntry returns nullptr
  • Attempts to create entry if it doesn't exist
  • Gets entry again but doesn't verify it's valid
  • Dereferences the entry pointer without checking

GDB

pwndbg> p entry->value
Cannot access memory at address 0x0
pwndbg> p entry
$1 = std::shared_ptr<BT::Blackboard::Entry> (empty) = {
  get() = 0x0
}
pwndbg> p res->first
$2 = {
  _any = {
    storage = {
      dynamic = 0xffffffffe010006e,
      stack = {
        __data = "n\000\020\340\377\377\377\377\000\000\000\000\000\000\000",
        __align = {<No data fields>}
      }
    },
    vtable = 0x555556412f40 <linb::any::vtable_for_type<long>()::table>
  },
  _original_type = {
    _M_target = 0x7ffff7c6e610 <typeinfo for long>
  }
}
pwndbg> p json
$1 = (const nlohmann::json_abi_v3_11_3::json &) @0x7ffff550dc20: {
  <nlohmann::json_abi_v3_11_3::detail::json_default_base> = {<No data fields>},
  members of nlohmann::json_abi_v3_11_3::basic_json<std::map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_11_3::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void>:
  m_data = {
    m_type = nlohmann::json_abi_v3_11_3::detail::value_t::object,
    m_value = {
      object = 0x504000000250,
      array = 0x504000000250,
      string = 0x504000000250,
      binary = 0x504000000250,
      boolean = 80,
      number_integer = 88235808129616,
      number_unsigned = 88235808129616,
      number_float = 4.3594281529883041e-310
    }
  }
}

Stack trace

#0  0x00005555558f5d1e in BT::ImportBlackboardFromJSON (json=..., blackboard=...)

Proposed Fix

void ImportBlackboardFromJSON(const nlohmann::json& json, Blackboard& blackboard)
{
  for(auto it = json.begin(); it != json.end(); ++it)
  {
    if(auto res = JsonExporter::get().fromJson(it.value()))
    {
      auto entry = blackboard.getEntry(it.key());
      if(!entry)
      {
        blackboard.createEntry(it.key(), res->second);
        entry = blackboard.getEntry(it.key());
        if(!entry) {
          // Either throw or continue to next entry
          continue;  
        }
      }
      entry->value = res->first;
    }
  }
}

Impact

Impact

  • Program crash on malformed input
  • Potential security vulnerability if JSON input is untrusted
  • Could be used for denial of service attacks

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions