Thanks to visit codestin.com
Credit goes to github.com

Skip to content

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

@ahuo1

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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions