Skip to content

Stack buffer overflow in ParseScript due to fixed-size error buffer #1006

Description

@ahuo1

Hi, I also found a stack-buffer-overflow vulnerability using my fuzzer.

Environment

  • OS: Ubuntu 22.04
  • Compiler: clang 13.0.1
  • C++ Standard: C++17
  • Sanitizers: AddressSanitizer (ASan) + UndefinedBehaviorSanitizer (UBSan)

Build Instructions

export CXXFLAGS="${CXXFLAGS} -std=c++17 -stdlib=libstdc++ -fsanitize=address -O1 -g"
export CFLAGS="${CFLAGS} -fsanitize=address -O1 -g"
export LDFLAGS="${LDFLAGS} -fsanitize=address"

mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Release -DENABLE_FUZZING=ON -DFORCE_STATIC_LINKING=ON -DBUILD_TESTING=OFF
cmake --build . --parallel

Reproduction

Run the fuzzer with a crafted input file:

./bt_fuzzer poc

Observed Behavior

Program crashes with ASan/UBSan report:

==27299==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffdeab4a080 at pc 0x00000080bef3 bp 0x7ffdeab47c70 sp 0x7ffdeab47c68

    ...
    #24 0x75e930 in BT::ParseScript(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) /root/behavior/behavior_fix/src/script_parser.cpp:20:7
    #25 0x5d3ff8 in auto BT::BehaviorTreeFactory::instantiateTreeNode(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, BT::NodeConfig const&) const::$_3::operator()<std::map<BT::PreCond, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::less<BT::PreCond>, std::allocator<std::pair<BT::PreCond const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > const, std::array<std::function<BT::Any (BT::Ast::Environment&)>, 4ul> >(std::map<BT::PreCond, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::less<BT::PreCond>, std::allocator<std::pair<BT::PreCond const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > const&, std::array<std::function<BT::Any (BT::Ast::Environment&)>, 4ul>&) const /root/behavior/behavior_fix/src/bt_factory.cpp:303:26
    #26 0x5d3ff8 in BT::BehaviorTreeFactory::instantiateTreeNode(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, BT::NodeConfig const&) const /root/behavior/behavior_fix/src/bt_factory.cpp:313:3
    ...

Root Cause Analysis

When parsing scripts, the function ParseScript allocates a fixed-size buffer on the stack:

Expected<ScriptFunction> ParseScript(const std::string& script)
{
char error_msgs_buffer[2048];
auto input = lexy::string_input<lexy::utf8_encoding>(script);
auto result =
lexy::parse<BT::Grammar::stmt>(input, ErrorReport().to(error_msgs_buffer));

However, ErrorReport can produce arbitrarily long diagnostic messages. If the error output exceeds 2048 bytes, it will overflow the stack buffer, causing a stack-buffer-overflow (as detected by AddressSanitizer).

The attached file contains a proof-of-concept.

poc.zip

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions