uNetworking / uWebSockets

Simple, secure & standards compliant web server for the most demanding of applications
Apache License 2.0
17.24k stars 1.75k forks source link

Segfault when using compression #1164

Closed hellow554 closed 3 years ago

hellow554 commented 3 years ago

Hey everyone,

this seems to be an issue with sub/pub messages and compression enabled.

You can find my somewhat minified example here:

https://gist.github.com/hellow554/bc5b6759ac5dd026b83d3567182d3848

This example uses jsoncpp and libfmt, so you need to have that installed, but it should be available in your package manager.

Here's an asan dump:

``` ================================================================= ==32142==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x604000002332 at pc 0x7f54a6a43480 bp 0x7f54a2ffc960 sp 0x7f54a2ffc108 READ of size 578494337 at 0x604000002332 thread T1 #0 0x7f54a6a4347f (/lib/x86_64-linux-gnu/libasan.so.5+0x9b47f) #1 0x55f3f1d6c695 in memcpy /usr/include/x86_64-linux-gnu/bits/string_fortified.h:34 #2 0x55f3f1d6c695 in formatMessage uWebSockets/src/WebSocketProtocol.h:240 #3 0x55f3f1d6c695 in uWS::WebSocket::send(std::basic_string_view >, uWS::OpCode, bool) uWebSockets/src/WebSocket.h:98 #4 0x55f3f1d6d634 in uWS::WebSocketContextData::WebSocketContextData()::{lambda(uWS::Subscriber*, std::pair >, std::basic_string_view > >)#1}::operator()(uWS::Subscriber*, std::pair >, std::basic_string_view > >) const uWebSockets/src/WebSocketContextData.h:117 #5 0x55f3f1d6d634 in std::_Function_handler >, std::basic_string_view > >), uWS::WebSocketContextData::WebSocketContextData()::{lambda(uWS::Subscriber*, std::pair >, std::basic_string_view > >)#1}>::_M_invoke(std::_Any_data const&, uWS::Subscriber*&&, std::pair >, std::basic_string_view > >&&) /usr/include/c++/9/bits/std_function.h:285 #6 0x55f3f1d71b0b in std::function >, std::basic_string_view > >)>::operator()(uWS::Subscriber*, std::pair >, std::basic_string_view > >) const /usr/include/c++/9/bits/std_function.h:688 #7 0x55f3f1d71b0b in uWS::TopicTree::drain() uWebSockets/src/TopicTree.h:420 #8 0x55f3f1d7638e in uWS::WebSocketContextData::WebSocketContextData()::{lambda(uWS::Loop*)#2}::operator()(uWS::Loop*) const uWebSockets/src/WebSocketContextData.h:152 #9 0x55f3f1d7638e in decltype (((forward::WebSocketContextData()::{lambda(uWS::Loop*)#2}&>)({parm#1}))((forward)({parm#2}))) fu2::abi_400::detail::invocation::invoke::WebSocketContextData()::{lambda(uWS::Loop*)#2}&, uWS::Loop*>(uWS::WebSocketContextData::WebSocketContextData()::{lambda(uWS::Loop*)#2}&, (uWS::WebSocketContextData::WebSocketContextData()::{lambda(uWS::Loop*)#2}&)...) uWebSockets/src/f2/function2.hpp:184 #10 0x55f3f1d7638e in fu2::abi_400::detail::type_erasure::invocation_table::function_trait::internal_invoker::WebSocketContextData()::{lambda(uWS::Loop*)#2}, std::allocator<{lambda(uWS::Loop*)#2}> >, true>::invoke(fu2::abi_400::detail::type_erasure::data_accessor*, unsigned long, uWS::Loop*) uWebSockets/src/f2/function2.hpp:587 #11 0x55f3f1d45fc3 in decltype(auto) fu2::abi_400::detail::type_erasure::tables::vtable >::invoke<0ul, fu2::abi_400::detail::type_erasure::data_accessor*, unsigned long const&, uWS::Loop*>(fu2::abi_400::detail::type_erasure::data_accessor*&&, unsigned long const&, uWS::Loop*&&) const uWebSockets/src/f2/function2.hpp:995 #12 0x55f3f1d45fc3 in decltype(auto) fu2::abi_400::detail::type_erasure::erasure, fu2::abi_400::detail::property >::invoke<0ul, fu2::abi_400::detail::type_erasure::erasure, fu2::abi_400::detail::property >&, uWS::Loop*>(fu2::abi_400::detail::type_erasure::erasure, fu2::abi_400::detail::property >&, uWS::Loop*&&) uWebSockets/src/f2/function2.hpp:1215 #13 0x55f3f1d45fc3 in fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<0ul, fu2::abi_400::detail::function, fu2::abi_400::detail::property >, void (uWS::Loop*)>::operator()(uWS::Loop*) uWebSockets/src/f2/function2.hpp:775 #14 0x55f3f1d45fc3 in uWS::Loop::postCb(us_loop_t*) uWebSockets/src/Loop.h:57 #15 0x55f3f1dea57b in us_loop_run src/loop.c:133 #16 0x55f3f1d3e45f in uWS::Loop::run() uWebSockets/src/Loop.h:159 #17 0x55f3f1d3e45f in uWS::run() uWebSockets/src/Loop.h:176 #18 0x55f3f1d3e45f in uWS::TemplatedApp::run() uWebSockets/src/App.h:336 #19 0x55f3f1d3e45f in operator() /tmp/tmp.pIOFErHQxx/a.cpp:77 #20 0x55f3f1d3f152 in __invoke_impl > /usr/include/c++/9/bits/invoke.h:60 #21 0x55f3f1d3f152 in __invoke > /usr/include/c++/9/bits/invoke.h:95 #22 0x55f3f1d3f152 in _M_invoke<0> /usr/include/c++/9/thread:244 #23 0x55f3f1d3f152 in operator() /usr/include/c++/9/thread:251 #24 0x55f3f1d3f152 in _M_run /usr/include/c++/9/thread:195 #25 0x7f54a684bd83 (/lib/x86_64-linux-gnu/libstdc++.so.6+0xd6d83) #26 0x7f54a6740608 in start_thread /build/glibc-ZN95T4/glibc-2.31/nptl/pthread_create.c:477 #27 0x7f54a6665292 in __clone (/lib/x86_64-linux-gnu/libc.so.6+0x122292) 0x604000002332 is located 0 bytes to the right of 34-byte region [0x604000002310,0x604000002332) allocated by thread T1 here: #0 0x7f54a6ab7947 in operator new(unsigned long) (/lib/x86_64-linux-gnu/libasan.so.5+0x10f947) #1 0x7f54a68b7e7d in std::__cxx11::basic_string, std::allocator >::_M_mutate(unsigned long, unsigned long, char const*, unsigned long) (/lib/x86_64-linux-gnu/libstdc++.so.6+0x142e7d) Thread T1 created by T0 here: #0 0x7f54a69e2805 in pthread_create (/lib/x86_64-linux-gnu/libasan.so.5+0x3a805) #1 0x7f54a684c048 in std::thread::_M_start_thread(std::unique_ptr >, void (*)()) (/lib/x86_64-linux-gnu/libstdc++.so.6+0xd7048) #2 0x55f3f1d31dfa in main /tmp/tmp.pIOFErHQxx/a.cpp:102 #3 0x7f54a656a0b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x270b2) SUMMARY: AddressSanitizer: heap-buffer-overflow (/lib/x86_64-linux-gnu/libasan.so.5+0x9b47f) Shadow bytes around the buggy address: 0x0c087fff8410: fa fa fd fd fd fd fd fa fa fa fd fd fd fd fd fd 0x0c087fff8420: fa fa fd fd fd fd fd fd fa fa 00 00 00 00 00 fa 0x0c087fff8430: fa fa fd fd fd fd fd fa fa fa 00 00 00 00 02 fa 0x0c087fff8440: fa fa 00 00 00 00 02 fa fa fa 00 00 00 00 02 fa 0x0c087fff8450: fa fa 00 00 00 00 02 fa fa fa 00 00 00 00 02 fa =>0x0c087fff8460: fa fa 00 00 00 00[02]fa fa fa fa fa fa fa fa fa 0x0c087fff8470: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c087fff8480: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c087fff8490: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c087fff84a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c087fff84b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe Left alloca redzone: ca Right alloca redzone: cb Shadow gap: cc ==32142==ABORTING ```

As you can see, the heap will overflow. This is because it tries to allocate 578494337 bytes of data, which failes and then it tries to write it nevertheless.

This bug doesn't occur, if you disable compression in the settings.

If you need any further information, please let me know.

ghost commented 3 years ago

Hello, this exact bug was reported in the JS-repo and fixed a minute ago. Please try latest master and I will make a new release.

hellow554 commented 3 years ago

Can confirm it works, thanks for that!

Also funny, that it was reported the same at the other repo :D I wasn't aware of that and it was not on purpose.