Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Recursive Stack Frames: HandleCompactMap, HandleMap, HandleFlowSequence, HandleSequence, HandleNode #657

Closed
wcventure opened this issue Jan 2, 2019 · 4 comments

Comments

@wcventure
Copy link

Hi there,

An issue was discovered in singledocparser.cpp, as distributed in yaml-cpp v0.6.2. Stack Exhaustion occurs in the YAML::SingleDocParser, and there is a stack consumption problem caused by recursive stack frames: HandleCompactMap, HandleMap, HandleFlowSequence, HandleSequence, HandleNode.

Here is the POC file. Please use "./parse $POC" to reproduce the bug
POC.zip

$git log

commit abf941b20d21342cd207df0f8ffe09f41a4d3042
Author: Simon Gene Gottlieb <simon@gottliebtfreitag.de>
Date:   Fri Dec 21 15:05:19 2018 +0100

    Fix float precision (#649)

    The issue is that numbers like
    2.01 or 3.01 can not be precisely represented with binary floating point
    numbers.

    This replaces all occurrences of 'std::numeric_limits<T>::digits10 + 1' with
    'std::numeric_limits<T>::max_digits10'.

    Background:
    Using 'std::numeric_limits<T>::digits10 + 1' is not precise enough.
    Converting a 'float' into a 'string' and back to a 'float' will not always
    produce the original 'float' value. To guarantee that the 'string'
    representation has sufficient precision the value
    'std::numeric_limits<T>::max_digits10' has to be used.

I have confirmed them with address sanitizer too.

AddressSanitizer:DEADLYSIGNAL
=================================================================
==79337==ERROR: AddressSanitizer: stack-overflow on address 0x7fff38e3dff8 (pc 0x000000432d12 bp 0x7fff38e3e890 sp 0x7fff38e3e000 T0)
    #0 0x432d11 in __asan::Allocator::Allocate(unsigned long, unsigned long, __sanitizer::BufferedStackTrace*, __asan::AllocType, bool) /home/wencheng/Documents/llvm-6.0.1/projects/compiler-rt/lib/asan/asan_allocator.cc:396
    #1 0x42d247 in __asan::asan_memalign(unsigned long, unsigned long, __sanitizer::BufferedStackTrace*, __asan::AllocType) /home/wencheng/Documents/llvm-6.0.1/projects/compiler-rt/lib/asan/asan_allocator.cc:900
    #2 0x52015f in operator new(unsigned long) /home/wencheng/Documents/llvm-6.0.1/projects/compiler-rt/lib/asan/asan_new_delete.cc:92
    #3 0x54a3d4 in YAML::detail::memory::create_node() /yaml-cpp/src/memory.cpp:17:21
    #4 0x537988 in YAML::detail::memory_holder::create_node() /yaml-cpp/include/yaml-cpp/node/detail/memory.h:37:43
    #5 0x535208 in YAML::NodeBuilder::Push(YAML::Mark const&, unsigned long) /yaml-cpp/src/nodebuilder.cpp:77:35
    #6 0x536389 in YAML::NodeBuilder::OnMapStart(YAML::Mark const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned long, YAML::EmitterStyle::value) /yaml-cpp/src/nodebuilder.cpp:63:24
    #7 0x5c797f in YAML::SingleDocParser::HandleNode(YAML::EventHandler&) /yaml-cpp/src/singledocparser.cpp:120:22
    #8 0x5cac0c in YAML::SingleDocParser::HandleFlowSequence(YAML::EventHandler&) /yaml-cpp/src/singledocparser.cpp:199:5
    #9 0x5c8fcb in YAML::SingleDocParser::HandleSequence(YAML::EventHandler&) /yaml-cpp/src/singledocparser.cpp:143:7
    #10 0x5c706e in YAML::SingleDocParser::HandleNode(YAML::EventHandler&) /yaml-cpp/src/singledocparser.cpp:98:7
    #11 0x5ce59e in YAML::SingleDocParser::HandleCompactMap(YAML::EventHandler&) /yaml-cpp/src/singledocparser.cpp:330:3
    #12 0x5c8412 in YAML::SingleDocParser::HandleMap(YAML::EventHandler&) /yaml-cpp/src/singledocparser.cpp:226:7
    #13 0x5c79c3 in YAML::SingleDocParser::HandleNode(YAML::EventHandler&) /yaml-cpp/src/singledocparser.cpp:121:9
	...
	...
    #222 0x5c8412 in YAML::SingleDocParser::HandleMap(YAML::EventHandler&) /yaml-cpp/src/singledocparser.cpp:226:7
    #223 0x5c79c3 in YAML::SingleDocParser::HandleNode(YAML::EventHandler&) /yaml-cpp/src/singledocparser.cpp:121:9
    #224 0x5cac0c in YAML::SingleDocParser::HandleFlowSequence(YAML::EventHandler&) /yaml-cpp/src/singledocparser.cpp:199:5
    #225 0x5c8fcb in YAML::SingleDocParser::HandleSequence(YAML::EventHandler&) /yaml-cpp/src/singledocparser.cpp:143:7
    #226 0x5c706e in YAML::SingleDocParser::HandleNode(YAML::EventHandler&) /yaml-cpp/src/singledocparser.cpp:98:7
    #227 0x5ce59e in YAML::SingleDocParser::HandleCompactMap(YAML::EventHandler&) /yaml-cpp/src/singledocparser.cpp:330:3
    #228 0x5c8412 in YAML::SingleDocParser::HandleMap(YAML::EventHandler&) /yaml-cpp/src/singledocparser.cpp:226:7
    #229 0x5c79c3 in YAML::SingleDocParser::HandleNode(YAML::EventHandler&) /yaml-cpp/src/singledocparser.cpp:121:9
    #230 0x5cac0c in YAML::SingleDocParser::HandleFlowSequence(YAML::EventHandler&) /yaml-cpp/src/singledocparser.cpp:199:5
    #231 0x5c8fcb in YAML::SingleDocParser::HandleSequence(YAML::EventHandler&) /yaml-cpp/src/singledocparser.cpp:143:7
    #232 0x5c706e in YAML::SingleDocParser::HandleNode(YAML::EventHandler&) /yaml-cpp/src/singledocparser.cpp:98:7
    #233 0x5ce59e in YAML::SingleDocParser::HandleCompactMap(YAML::EventHandler&) /yaml-cpp/src/singledocparser.cpp:330:3
    #234 0x5c8412 in YAML::SingleDocParser::HandleMap(YAML::EventHandler&) /yaml-cpp/src/singledocparser.cpp:226:7
    #235 0x5c79c3 in YAML::SingleDocParser::HandleNode(YAML::EventHandler&) /yaml-cpp/src/singledocparser.cpp:121:9
    #236 0x5cac0c in YAML::SingleDocParser::HandleFlowSequence(YAML::EventHandler&) /yaml-cpp/src/singledocparser.cpp:199:5
    #237 0x5c8fcb in YAML::SingleDocParser::HandleSequence(YAML::EventHandler&) /yaml-cpp/src/singledocparser.cpp:143:7
    #238 0x5c706e in YAML::SingleDocParser::HandleNode(YAML::EventHandler&) /yaml-cpp/src/singledocparser.cpp:98:7
    #239 0x5ce59e in YAML::SingleDocParser::HandleCompactMap(YAML::EventHandler&) /yaml-cpp/src/singledocparser.cpp:330:3
    #240 0x5c8412 in YAML::SingleDocParser::HandleMap(YAML::EventHandler&) /yaml-cpp/src/singledocparser.cpp:226:7
    #241 0x5c79c3 in YAML::SingleDocParser::HandleNode(YAML::EventHandler&) /yaml-cpp/src/singledocparser.cpp:121:9
    #242 0x5cac0c in YAML::SingleDocParser::HandleFlowSequence(YAML::EventHandler&) /yaml-cpp/src/singledocparser.cpp:199:5
    #243 0x5c8fcb in YAML::SingleDocParser::HandleSequence(YAML::EventHandler&) /yaml-cpp/src/singledocparser.cpp:143:7
    #244 0x5c706e in YAML::SingleDocParser::HandleNode(YAML::EventHandler&) /yaml-cpp/src/singledocparser.cpp:98:7
    #245 0x5ce59e in YAML::SingleDocParser::HandleCompactMap(YAML::EventHandler&) /yaml-cpp/src/singledocparser.cpp:330:3
    #246 0x5c8412 in YAML::SingleDocParser::HandleMap(YAML::EventHandler&) /yaml-cpp/src/singledocparser.cpp:226:7
    #247 0x5c79c3 in YAML::SingleDocParser::HandleNode(YAML::EventHandler&) /yaml-cpp/src/singledocparser.cpp:121:9
    #248 0x5cac0c in YAML::SingleDocParser::HandleFlowSequence(YAML::EventHandler&) /yaml-cpp/src/singledocparser.cpp:199:5
    #249 0x5c8fcb in YAML::SingleDocParser::HandleSequence(YAML::EventHandler&) /yaml-cpp/src/singledocparser.cpp:143:7

SUMMARY: AddressSanitizer: stack-overflow /home/wencheng/Documents/llvm-6.0.1/projects/compiler-rt/lib/asan/asan_allocator.cc:396 in __asan::Allocator::Allocate(unsigned long, unsigned long, __sanitizer::BufferedStackTrace*, __asan::AllocType, bool)
==79337==ABORTING
@wcventure
Copy link
Author

This is simply running out of stack space. You can make the number of recursions go up by 11,000 or so by dynamically allocating variables instead of using stack space, but at the end of the day, you can work around this (for this test case) by doing:

ulimit -s 8192

Of course, a much larger (deeper) YAML file will still make it crash. You can thus, make it happen far faster by doing:

ulimit -s 256

The crash does not seem to happen due to any buffer overflows or memory corruption; it's simply the kernel saying "you're out of stack space, please die". One simple way to avoid the crash itself is to do a depth-check of the tree and compare it to some value related to the stack size returned and produce an error if the values are way out of whack.

A more complicated solution would involve removing recursion, which looks like it would not be a trivial fix.

@wcventure
Copy link
Author

Similar cases occur in binutils v2.31, too. Too fix this problem, for example, binutils v2.32 add a recursion limit to libiberty's demangling code. The limit is enabled by default, but can be disabled via a new demangling option.

See
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87335

@wcventure
Copy link
Author

CVE-2019-6292

@LocutusOfBorg
Copy link

hello, can we close this issue now that #660 is merged?
I tested 0.5.2

./build-static/util/parse < ../crash0
Segmentation fault (core dumped)
./build-static/util/parse < ../POC
Segmentation fault (core dumped)

and 0.6.3

 ./build-static/util/parse < crash0 
yaml-cpp: error at line 1, column 1: bad file
./build-static/util/parse < POC    
yaml-cpp: error at line 1, column 1: bad file

@jbeder jbeder closed this as completed May 22, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants