Skip to content

Fix an off-by-one in loadscpt

here is the trace I'm trying to fix:

jvoisin@grimhilde 18:52 ~/dev/openmw/openmw/build_fuzz_asan_master ./esmtool dump -C -p -q out/default/crashes/id\:000000\,sig\:06\,src\:000002\,time\:21965\,op\:havoc\,rep\:16          master *
Using default (English) font encoding.
Loading file: out/default/crashes/id:000000,sig:06,src:000002,time:21965,op:havoc,rep:16
=================================================================
==1382604==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x607000013a1e at pc 0x00000045ab66 bp 0x7ffd6d12ea70 sp 0x7ffd6d12e230
READ of size 1 at 0x607000013a1e thread T0
    #0 0x45ab65 in strlen (/home/jvoisin/dev/openmw/openmw/build_fuzz_asan_master/esmtool+0x45ab65)
    #1 0x840ec5 in std::char_traits<char>::length(char const*) /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/char_traits.h:357:9
    #2 0x840ec5 in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string<std::allocator<char> >(char const*, std::allocator<char> const&) /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/basic_string.h:527:39
    #3 0x840ec5 in ESM::Script::loadSCVR(ESM::ESMReader&) /home/jvoisin/dev/openmw/openmw/components/esm/loadscpt.cpp:60:28
    #4 0x84b05b in ESM::Script::load(ESM::ESMReader&, bool&) /home/jvoisin/dev/openmw/openmw/components/esm/loadscpt.cpp:103:21
    #5 0x5112f5 in load(Arguments&) /home/jvoisin/dev/openmw/openmw/apps/esmtool/esmtool.cpp:389:21
    #6 0x50aa40 in main /home/jvoisin/dev/openmw/openmw/apps/esmtool/esmtool.cpp:216:20
    #7 0x7ff2d0ffacb1 in __libc_start_main csu/../csu/libc-start.c:314:16
    #8 0x44834d in _start (/home/jvoisin/dev/openmw/openmw/build_fuzz_asan_master/esmtool+0x44834d)

0x607000013a1e is located 0 bytes to the right of 78-byte region [0x6070000139d0,0x607000013a1e)
allocated by thread T0 here:
    #0 0x4f205d in operator new(unsigned long) (/home/jvoisin/dev/openmw/openmw/build_fuzz_asan_master/esmtool+0x4f205d)
    #1 0x83e11c in __gnu_cxx::new_allocator<char>::allocate(unsigned long, void const*) /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/ext/new_allocator.h:115:27
    #2 0x83e11c in std::allocator_traits<std::allocator<char> >::allocate(std::allocator<char>&, unsigned long) /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/alloc_traits.h:460:20
    #3 0x83e11c in std::_Vector_base<char, std::allocator<char> >::_M_allocate(unsigned long) /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/stl_vector.h:346:20
    #4 0x83e11c in std::_Vector_base<char, std::allocator<char> >::_M_create_storage(unsigned long) /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/stl_vector.h:361:33
    #5 0x83e11c in std::_Vector_base<char, std::allocator<char> >::_Vector_base(unsigned long, std::allocator<char> const&) /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/stl_vector.h:305:9
    #6 0x83e11c in std::vector<char, std::allocator<char> >::vector(unsigned long, std::allocator<char> const&) /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/stl_vector.h:511:9
    #7 0x83e11c in ESM::Script::loadSCVR(ESM::ESMReader&) /home/jvoisin/dev/openmw/openmw/components/esm/loadscpt.cpp:17:27
    #8 0x84b05b in ESM::Script::load(ESM::ESMReader&, bool&) /home/jvoisin/dev/openmw/openmw/components/esm/loadscpt.cpp:103:21
    #9 0x5112f5 in load(Arguments&) /home/jvoisin/dev/openmw/openmw/apps/esmtool/esmtool.cpp:389:21
    #10 0x50aa40 in main /home/jvoisin/dev/openmw/openmw/apps/esmtool/esmtool.cpp:216:20
    #11 0x7ff2d0ffacb1 in __libc_start_main csu/../csu/libc-start.c:314:16

SUMMARY: AddressSanitizer: heap-buffer-overflow (/home/jvoisin/dev/openmw/openmw/build_fuzz_asan_master/esmtool+0x45ab65) in strlen
Shadow bytes around the buggy address:
  0x0c0e7fffa6f0: fa fa fa fa fd fd fd fd fd fd fd fd fd fd fa fa
  0x0c0e7fffa700: fa fa 00 00 00 00 00 00 00 00 00 03 fa fa fa fa
  0x0c0e7fffa710: 00 00 00 00 00 00 00 00 00 03 fa fa fa fa fd fd
  0x0c0e7fffa720: fd fd fd fd fd fd fd fd fa fa fa fa 00 00 00 00
  0x0c0e7fffa730: 00 00 00 00 00 03 fa fa fa fa 00 00 00 00 00 00
=>0x0c0e7fffa740: 00 00 00[06]fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c0e7fffa750: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c0e7fffa760: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c0e7fffa770: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c0e7fffa780: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c0e7fffa790: 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
==1382604==ABORTING

but it seems that I'm missing something, since I can still trigger crashes in this area after this MR.

Here is the esp if you want to try: id_000016_sig_06_src_000151_time_122462_op_havoc_rep_8

Edited by jvoisin

Merge request reports

Loading