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

[0.H] heap-use-after-free after quitting the game after a fatal error #78607

Open
NetSysFire opened this issue Dec 16, 2024 · 3 comments
Open
Labels
(S1 - Need confirmation) Report waiting on confirmation of reproducibility

Comments

@NetSysFire
Copy link
Member

NetSysFire commented Dec 16, 2024

Describe the bug

image

Attach save file

n/a

Steps to reproduce

  1. Cause a fatal json error that drops you back to the main menu. Remove a , somewhere for example, which I did for this demonstration.
  2. Try to load a game, get error, get dropped back to main menu.
  3. Exit the game in the main menu. Both alt-f4 and normal quit works.
  4. ASan intercepts use-after-free

Edit: Simpler reproduction instructions.

Full ASan output
=================================================================
==2384856==ERROR: AddressSanitizer: heap-use-after-free on address 0x5040009fe6d0 at pc 0x780f5d67d6cf bp 0x7ffc7f8a9030 sp 0x7ffc7f8a87d8
READ of size 33 at 0x5040009fe6d0 thread T0
    #0 0x780f5d67d6ce in MemcmpInterceptorCommon(void*, int (*)(void const*, void const*, unsigned long), void const*, void const*, unsigned long) /usr/src/debug/gcc/gcc/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:813
    #1 0x780f5d67dbac in memcmp /usr/src/debug/gcc/gcc/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:845
    #2 0x780f5d67dbac in memcmp /usr/src/debug/gcc/gcc/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:840
    #3 0x654743c4962a in std::char_traits<char>::compare(char const*, char const*, unsigned long) /usr/include/c++/14.2.1/bits/char_traits.h:381
    #4 0x654743c4962a in bool std::operator==<char, std::char_traits<char>, std::allocator<char> >(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, char const*) /usr/include/c++/14.2.1/bits/basic_string.h:3776
    #5 0x654743c4969c in bool std::operator!=<char, std::char_traits<char>, std::allocator<char> >(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, char const*) /usr/include/c++/14.2.1/bits/basic_string.h:3862
    #6 0x654743c4969c in detail::local_translation_cache<char const*>::operator()(char const*) src/translation_cache.h:85
    #7 0x654744fca75b in operator()<char [34]> src/debug.cpp:326
    #8 0x654744fd32e9 in debug_error_prompt src/debug.cpp:325
    #9 0x654744fd454a in realDebugmsg(char const*, char const*, char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) src/debug.cpp:541
    #10 0x654743e1a91c in void realDebugmsg<char const*>(char const*, char const*, char const*, char const*, char const*&&) src/debug.h:78
    #11 0x65474564e90f in JsonObject::error_skipped_members(std::vector<unsigned long, std::allocator<unsigned long> > const&) const src/flexbuffer_json.cpp:341
    #12 0x65474564f2fe in JsonObject::report_unvisited() const src/flexbuffer_json.cpp:290
    #13 0x654743c4b549 in JsonObject::~JsonObject() src/flexbuffer_json-inl.h:808
    #14 0x654743c51b8a in std::pair<JsonObject, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::~pair() /usr/include/c++/14.2.1/bits/stl_pair.h:284
    #15 0x654743c51b8a in void std::__new_allocator<std::_List_node<std::pair<JsonObject, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >::destroy<std::pair<JsonObject, std::__cxx11::basic_string<char,std::char_traits<char>, std::allocator<char> > > >(std::pair<JsonObject, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >*) /usr/include/c++/14.2.1/bits/new_allocator.h:198
    #16 0x654743c51b8a in void std::allocator_traits<std::allocator<std::_List_node<std::pair<JsonObject, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > >::destroy<std::pair<JsonObject, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >(std::allocator<std::_List_node<std::pair<JsonObject, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >&, std::pair<JsonObject, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >*) /usr/include/c++/14.2.1/bits/alloc_traits.h:554
    #17 0x654743c51b8a in std::__cxx11::_List_base<std::pair<JsonObject, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<JsonObject, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >::_M_clear() /usr/include/c++/14.2.1/bits/list.tcc:77
    #18 0x654747483135 in std::__cxx11::_List_base<std::pair<JsonObject, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<JsonObject, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >::~_List_base() /usr/include/c++/14.2.1/bits/stl_list.h:575
    #19 0x654747483135 in std::__cxx11::list<std::pair<JsonObject, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<JsonObject, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >::~list() /usr/include/c++/14.2.1/bits/stl_list.h:903
    #20 0x654747483135 in generic_factory<mtype>::~generic_factory() src/generic_factory.h:123
    #21 0x654747483156 in generic_factory<mtype>::~generic_factory() src/generic_factory.h:123
    #22 0x65474745fc87 in std::default_delete<generic_factory<mtype> >::operator()(generic_factory<mtype>*) const /usr/include/c++/14.2.1/bits/unique_ptr.h:93
    #23 0x65474745fc87 in std::unique_ptr<generic_factory<mtype>, std::default_delete<generic_factory<mtype> > >::~unique_ptr() /usr/include/c++/14.2.1/bits/unique_ptr.h:398
    #24 0x6547474217c8 in pimpl<generic_factory<mtype> >::~pimpl() src/pimpl.h:37
    #25 0x6547474217c8 in MonsterGenerator::~MonsterGenerator() src/monstergenerator.cpp:198
    #26 0x780f5ce4e890  (/usr/lib/libc.so.6+0x3f890) (BuildId: 98b3d8e0b8c534c769cb871c438b4f8f3a8e4bf3)
    #27 0x780f5ce4e95d in exit (/usr/lib/libc.so.6+0x3f95d) (BuildId: 98b3d8e0b8c534c769cb871c438b4f8f3a8e4bf3)
    #28 0x654748762f25 in CheckMessages src/sdltiles.cpp:3534
    #29 0x6547487631e2 in input_manager::pump_events() src/sdltiles.cpp:3816
    #30 0x654745bbd3c3 in DynamicDataLoader::load_all_from_json(JsonValue const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, loading_ui&, cata_path const&, cata_path const&) src/init.cpp:546
    #31 0x654745bbde81 in DynamicDataLoader::load_data_from_path(cata_path const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, loading_ui&) src/init.cpp:521
    #32 0x654745671d49 in game::load_data_from_dir(cata_path const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, loading_ui&) src/game.cpp:568
    #33 0x6547456f45e3 in game::load_packs(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::vector<string_id<MOD_INFORMATION>, std::allocator<string_id<MOD_INFORMATION> > > const&, loading_ui&) src/game.cpp:3262
    #34 0x65474571f6e0 in game::load_world_modfiles(loading_ui&) src/game.cpp:3232
    #35 0x6547457a6906 in game::setup() src/game.cpp:753
    #36 0x6547467fdd9d in main_menu::new_character_tab() src/main_menu.cpp:996
    #37 0x654746805547 in main_menu::opening_screen() src/main_menu.cpp:874
    #38 0x6547467dbdf3 in main src/main.cpp:845
    #39 0x780f5ce34e07  (/usr/lib/libc.so.6+0x25e07) (BuildId: 98b3d8e0b8c534c769cb871c438b4f8f3a8e4bf3)
    #40 0x780f5ce34ecb in __libc_start_main (/usr/lib/libc.so.6+0x25ecb) (BuildId: 98b3d8e0b8c534c769cb871c438b4f8f3a8e4bf3)
    #41 0x654743c34064 in _start (/usr/bin/cataclysm-tiles+0x1935064) (BuildId: 6821d71700347786c1f47d31c2838f4a54fd27bf)

0x5040009fe6d0 is located 0 bytes inside of 34-byte region [0x5040009fe6d0,0x5040009fe6f2)
freed by thread T0 here:
    #0 0x780f5d6ff0ca in operator delete(void*) /usr/src/debug/gcc/gcc/libsanitizer/asan/asan_new_delete.cpp:152
    #1 0x654743c45705 in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string() /usr/include/c++/14.2.1/bits/basic_string.h:809
    #2 0x654743c45705 in detail::local_translation_cache<char const*>::~local_translation_cache() src/translation_cache.h:73
    #3 0x780f5ce4e890  (/usr/lib/libc.so.6+0x3f890) (BuildId: 98b3d8e0b8c534c769cb871c438b4f8f3a8e4bf3)
    #4 0x780f5ce4e95d in exit (/usr/lib/libc.so.6+0x3f95d) (BuildId: 98b3d8e0b8c534c769cb871c438b4f8f3a8e4bf3)
    #5 0x654748762f25 in CheckMessages src/sdltiles.cpp:3534
    #6 0x6547487631e2 in input_manager::pump_events() src/sdltiles.cpp:3816
    #7 0x654745bbd3c3 in DynamicDataLoader::load_all_from_json(JsonValue const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, loading_ui&, cata_path const&, cata_path const&) src/init.cpp:546
    #8 0x654745bbde81 in DynamicDataLoader::load_data_from_path(cata_path const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, loading_ui&) src/init.cpp:521
    #9 0x654745671d49 in game::load_data_from_dir(cata_path const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, loading_ui&) src/game.cpp:568
    #10 0x6547456f45e3 in game::load_packs(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::vector<string_id<MOD_INFORMATION>, std::allocator<string_id<MOD_INFORMATION> > > const&, loading_ui&) src/game.cpp:3262
    #11 0x65474571f6e0 in game::load_world_modfiles(loading_ui&) src/game.cpp:3232
    #12 0x6547457a6906 in game::setup() src/game.cpp:753
    #13 0x6547467fdd9d in main_menu::new_character_tab() src/main_menu.cpp:996
    #14 0x654746805547 in main_menu::opening_screen() src/main_menu.cpp:874
    #15 0x6547467dbdf3 in main src/main.cpp:845
    #16 0x780f5ce34e07  (/usr/lib/libc.so.6+0x25e07) (BuildId: 98b3d8e0b8c534c769cb871c438b4f8f3a8e4bf3)
    #17 0x780f5ce34ecb in __libc_start_main (/usr/lib/libc.so.6+0x25ecb) (BuildId: 98b3d8e0b8c534c769cb871c438b4f8f3a8e4bf3)
    #18 0x654743c34064 in _start (/usr/bin/cataclysm-tiles+0x1935064) (BuildId: 6821d71700347786c1f47d31c2838f4a54fd27bf)

previously allocated by thread T0 here:
    #0 0x780f5d6fe4f2 in operator new(unsigned long) /usr/src/debug/gcc/gcc/libsanitizer/asan/asan_new_delete.cpp:95
    #1 0x780f5d161dcf in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_mutate(unsi
gned long, unsigned long, char const*, unsigned long) /usr/src/debug/gcc/gcc-build/x86_64-pc-linux-gnu/libstdc++-v3/include/bits/basic_string.tcc:332
    #2 0x780f5d163073 in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_replace(unsigned long, unsigned long, char const*, unsigned long) /usr/src/debug/gcc/gcc-build/x86_64-pc-linux-gnu/libstdc++-v3/include/bits/basic_string.tcc:548
    #3 0x654743c49725 in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::operator=(char const*) /usr/include/c++/14.2.1/bits/basic_string.h:829
    #4 0x654743c49725 in detail::local_translation_cache<char const*>::operator()(char const*) src/translation_cache.h:89
    #5 0x654744fca75b in operator()<char [34]> src/debug.cpp:326
    #6 0x654744fd32e9 in debug_error_prompt src/debug.cpp:325
    #7 0x654744fd454a in realDebugmsg(char const*, char const*, char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) src/debug.cpp:541
    #8 0x654743e1a91c in void realDebugmsg<char const*>(char const*, char const*, char const*, char const*, char const*&&) src/debug.h:78
    #9 0x6547467fe6e2 in main_menu::new_character_tab() src/main_menu.cpp:998
    #10 0x654746805547 in main_menu::opening_screen() src/main_menu.cpp:874
    #11 0x6547467dbdf3 in main src/main.cpp:845
    #12 0x780f5ce34e07  (/usr/lib/libc.so.6+0x25e07) (BuildId: 98b3d8e0b8c534c769cb871c438b4f8f3a8e4bf3)
    #13 0x780f5ce34ecb in __libc_start_main (/usr/lib/libc.so.6+0x25ecb) (BuildId: 98b3d8e0b8c534c769cb871c438b4f8f3a8e4bf3)
    #14 0x654743c34064 in _start (/usr/bin/cataclysm-tiles+0x1935064) (BuildId: 6821d71700347786c1f47d31c2838f4a54fd27bf)

SUMMARY: AddressSanitizer: heap-use-after-free /usr/src/debug/gcc/gcc/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:813 in MemcmpInterceptorCommon(void*, int (*)(void const*, void const*, unsigned long), void const*, voidconst*, unsigned long)
Shadow bytes around the buggy address:
  0x5040009fe400: fa fa fd fd fd fd fd fa fa fa fd fd fd fd fd fa
  0x5040009fe480: fa fa fd fd fd fd fd fa fa fa fd fd fd fd fd fd
  0x5040009fe500: fa fa fd fd fd fd fd fa fa fa fd fd fd fd fd fa
  0x5040009fe580: fa fa fd fd fd fd fd fd fa fa 00 00 00 00 05 fa
  0x5040009fe600: fa fa fd fd fd fd fd fa fa fa fd fd fd fd fd fa
=>0x5040009fe680: fa fa fd fd fd fd fd fa fa fa[fd]fd fd fd fd fa
  0x5040009fe700: fa fa fd fd fd fd fd fa fa fa fd fd fd fd fd fa
  0x5040009fe780: fa fa 00 00 00 00 05 fa fa fa fd fd fd fd fd fa
  0x5040009fe800: fa fa fd fd fd fd fd fa fa fa 00 00 00 00 05 fa
  0x5040009fe880: fa fa fd fd fd fd fd fa fa fa fd fd fd fd fd fa
  0x5040009fe900: fa fa 00 00 00 00 05 fa fa fa fd fd fd fd fd 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
==2384856==ABORTING

Expected behavior

No use-after-free. I am pretty sure this is still present in experimental but imgui is hiding it.

I anticipate the security consequences of this bug to be approximately 0. I triggered this a couple of times by accident though. I do not see any way to exploit this for malicious purposes.

Screenshots

No response

Versions and configuration

  • OS: Linux
    • OS Version: LSB Version: n/a; Distributor ID: Arch; Description: Arch Linux; Release: rolling; Codename: n/a;
  • Game Version: 0.H [64-bit]
  • Graphics Version: Tiles
  • Game Language: English <color_dark_gray>(100.0%) [en]
  • Mods loaded: [
    Dark Days Ahead [dda],
    Disable NPC Needs [no_npc_food],
    Portal Storms Ignore NPCs [personal_portal_storms],
    Slowdown Fungal Growth [no_fungal_growth]
    ]

Additional context

No response

@NetSysFire NetSysFire added the (S1 - Need confirmation) Report waiting on confirmation of reproducibility label Dec 16, 2024
@GuardianDll
Copy link
Member

isn't it something that was fixed by #72522? just need to be backported

@NetSysFire
Copy link
Member Author

I am fairly sure this is not fixed because I applied this very PR in my debugging fork and this still happens.

@NetSysFire
Copy link
Member Author

On a related note: #76000 was also not backported despite it being undoubtfully destructive and littering the home directory of users with files named after binary garbage.

@NetSysFire NetSysFire changed the title [0.H] heap-use-after-free after loading and quitting the game after a fatal error [0.H] heap-use-after-free after quitting the game after a fatal error Dec 17, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
(S1 - Need confirmation) Report waiting on confirmation of reproducibility
Projects
None yet
Development

No branches or pull requests

2 participants