justdan96 / tsMuxer

tsMuxer is a transport stream muxer for remuxing/muxing elementary streams, EVO/VOB/MPG, MKV/MKA, MP4/MOV, TS, M2TS to TS to M2TS. Supported video codecs H.264/AVC, H.265/HEVC, VC-1, MPEG2. Supported audio codecs AAC, AC3 / E-AC3(DD+), DTS/ DTS-HD.
Apache License 2.0
829 stars 140 forks source link

heap buffer over read is found in MatroskaDemuxer::matroska_parse_block() #842

Closed JP3BGY closed 3 months ago

JP3BGY commented 3 months ago

Our fuzzer found heap bof in MatroskaDemuxer::matroska_parse_block() in the current main(5f43ab2). PoC is here.

#include "bufferedReaderManager.h"
#include "vod_common.h"
#include "abstractDemuxer.h"
#include "matroskaDemuxer.h"
#include <cstdint>
#include <fs/systemlog.h>

using namespace std;

BufferedReaderManager readManager(2, DEFAULT_FILE_BLOCK_SIZE, DEFAULT_FILE_BLOCK_SIZE + MAX_AV_PACKET_SIZE,
                                  DEFAULT_FILE_BLOCK_SIZE / 2);

int main(int argc, char* argv[]) {
  string fileName = argv[1];
  AbstractDemuxer* demuxer = new MatroskaDemuxer(readManager);

  demuxer->openFile(fileName);
  int64_t discardedSize = 0;
  DemuxedData demuxedData;

  PIDSet acceptedPidSet;

  demuxer->simpleDemuxBlock(demuxedData, acceptedPidSet, discardedSize);

  return 0;
}

Folloing is an output of ASAN. poc.mkv is in curptr_poc.zip.

[!] [ForkServer] Failed to get executor id: Bad file descriptor
        Tips: Is this forkserver attached to client?
        Just executing program...
=================================================================
==74==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60b000000000 at pc 0x558d03c4c1b7 bp 0x7fffb7f6f1b0 sp 0x7fffb7f6e980
READ of size 998136 at 0x60b000000000 thread T0
    #0 0x558d03c4c1b6 in __asan_memcpy (/out/tsmuxer-mkv2+0x19e1b6) (BuildId: 8a3bffd4a84d0e3e)
    #1 0x558d03ec04c2 in MatroskaDemuxer::matroska_parse_block(unsigned char*, int, long, long, long, int, int) /src/tsMuxer/tsMuxer/matroskaDemuxer.cpp:680:21
    #2 0x558d03e9f940 in MatroskaDemuxer::matroska_parse_cluster() /src/tsMuxer/tsMuxer/matroskaDemuxer.cpp:954:23
    #3 0x558d03e9cf2b in MatroskaDemuxer::readPacket(AVPacket&) /src/tsMuxer/tsMuxer/matroskaDemuxer.cpp:1125:28
    #4 0x558d03e9035c in MatroskaDemuxer::simpleDemuxBlock(std::map<int, MemoryBlock, std::less<int>, std::allocator<std::pair<int const, MemoryBlock>>>&, std::set<int, std::less<int>, std::allocator<int>> const&, long&) /src/tsMuxer/tsMuxer/matroskaDemuxer.cpp:2377:29
    #5 0x558d03e8df16 in main /src/tsMuxer/tsMuxer/main.cpp:23:12
    #6 0x7f8c1090cd8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
    #7 0x7f8c1090ce3f in __libc_start_main csu/../csu/libc-start.c:392:3
    #8 0x558d03bc7484 in _start (/out/tsmuxer-mkv2+0x119484) (BuildId: 8a3bffd4a84d0e3e)

0x60b000000000 is located 64 bytes to the left of 104-byte region [0x60b000000040,0x60b0000000a8)
freed by thread T0 here:
    #0 0x558d03c8796d in operator delete(void*) (/out/tsmuxer-mkv2+0x1d996d) (BuildId: 8a3bffd4a84d0e3e)
    #1 0x558d04018dee in __gnu_cxx::new_allocator<std::__detail::_Hash_node_base*>::deallocate(std::__detail::_Hash_node_base**, unsigned long) /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/ext/new_allocator.h:145:2
    #2 0x558d04018dee in std::allocator_traits<std::allocator<std::__detail::_Hash_node_base*>>::deallocate(std::allocator<std::__detail::_Hash_node_base*>&, std::__detail::_Hash_node_base**, unsigned long) /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/alloc_traits.h:496:13
    #3 0x558d04018dee in std::__detail::_Hashtable_alloc<std::allocator<std::__detail::_Hash_node<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const, unsigned int>, true>>>::_M_deallocate_buckets(std::__detail::_Hash_node_base**, unsigned long) /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/hashtable_policy.h:1942:7
    #4 0x558d04018dee in std::_Hashtable<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const, unsigned int>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const, unsigned int>>, std::__detail::_Select1st, std::equal_to<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>, std::hash<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<true, false, true>>::_M_deallocate_buckets(std::__detail::_Hash_node_base**, unsigned long) /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/hashtable.h:449:21
    #5 0x558d04018dee in std::_Hashtable<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const, unsigned int>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const, unsigned int>>, std::__detail::_Select1st, std::equal_to<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>, std::hash<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<true, false, true>>::_M_deallocate_buckets() /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/hashtable.h:454:9
    #6 0x558d04018dee in std::_Hashtable<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const, unsigned int>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const, unsigned int>>, std::__detail::_Select1st, std::equal_to<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>, std::hash<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<true, false, true>>::_M_rehash_aux(unsigned long, std::integral_constant<bool, true>) /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/hashtable.h:2409:7

previously allocated by thread T0 here:
    #0 0x558d03c8710d in operator new(unsigned long) (/out/tsmuxer-mkv2+0x1d910d) (BuildId: 8a3bffd4a84d0e3e)
    #1 0x558d04018b04 in __gnu_cxx::new_allocator<std::__detail::_Hash_node_base*>::allocate(unsigned long, void const*) /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/ext/new_allocator.h:127:27
    #2 0x558d04018b04 in std::allocator_traits<std::allocator<std::__detail::_Hash_node_base*>>::allocate(std::allocator<std::__detail::_Hash_node_base*>&, unsigned long) /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/alloc_traits.h:464:20
    #3 0x558d04018b04 in std::__detail::_Hashtable_alloc<std::allocator<std::__detail::_Hash_node<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const, unsigned int>, true>>>::_M_allocate_buckets(unsigned long) /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/hashtable_policy.h:1927:20
    #4 0x558d04018b04 in std::_Hashtable<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const, unsigned int>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const, unsigned int>>, std::__detail::_Select1st, std::equal_to<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>, std::hash<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<true, false, true>>::_M_allocate_buckets(unsigned long) /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/hashtable.h:440:28
    #5 0x558d04018b04 in std::_Hashtable<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const, unsigned int>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const, unsigned int>>, std::__detail::_Select1st, std::equal_to<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>, std::hash<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<true, false, true>>::_M_rehash_aux(unsigned long, std::integral_constant<bool, true>) /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/hashtable.h:2382:37

SUMMARY: AddressSanitizer: heap-buffer-overflow (/out/tsmuxer-mkv2+0x19e1b6) (BuildId: 8a3bffd4a84d0e3e) in __asan_memcpy
Shadow bytes around the buggy address:
  0x0c167fff7fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c167fff7fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c167fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c167fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c167fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c167fff8000:[fa]fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd
  0x0c167fff8010: fd fd fd fd fd fa fa fa fa fa fa fa fa fa fd fd
  0x0c167fff8020: fd fd fd fd fd fd fd fd fd fd fd fd fa fa fa fa
  0x0c167fff8030: fa fa fa fa 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c167fff8040: 00 fa fa fa fa fa fa fa fa fa fd fd fd fd fd fd
  0x0c167fff8050: fd fd fd fd fd fd fd fd 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
==74==ABORTING

This is caused by this line because slice_size is from user data but there is no boundary check. https://github.com/justdan96/tsMuxer/blob/75c9cb3514815d07378007d36cc90c3f209e7b36/tsMuxer/matroskaDemuxer.cpp#L673

Ricerca Security, Inc.