enzo1982 / mp4v2

Reviving the MP4v2 project...
https://mp4v2.org
Other
135 stars 50 forks source link

SEGV on unknown address mp4file.cpp:2662 in MP4File::GetChapters #53

Open mugichiya opened 2 weeks ago

mugichiya commented 2 weeks ago

Hi, I found segfault on unknown address in mp4file.cpp:2662. It seems to occur because sample could not get a valid reference in pChapterTrack->ReadSample on line 2655.

Abstract

Segmentation fault (maybe null pointer reference) on mp4chaps(libmp4v2.so.2).

Environment

OS: Ubuntu 22.04.4 LTS Compiler: gcc version 11.4.0

Build

cd /opt
git clone https://github.com/enzo1982/mp4v2.git -b 2.1.3 --depth 1
cd ./mp4v2
mkdir build
cmake -DCMAKE_BUILD_TYPE=Debug ../
cmake --build . -j 10

To enable Address Sanitizer, add the following options to CMakeFiles.txt.

add_compile_options(-fsanitize=address)
add_link_options(-fsanitize=address)

PoC

See testcases.

git clone https://github.com/mugichiya/pockey.git
cp -r ./pockey/projects/mp4v2_np/testcases .
./mp4chaps --list ./testcases/0000000000.mp4

ASAN output

banjo@ttc:/tmp/mp4v2/build$ ./mp4chaps --list ./testcases/0000000000.mp4
ReadAtom: "./testcases/0000000000.mp4": invalid atom size, extends outside parent atom - skipping to end of "stbl" "stco" 159384830 vs 1298
AddressSanitizer:DEADLYSIGNAL
=================================================================
==3389808==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x7f74e82f270b bp 0x7fff39dcd780 sp 0x7fff39dcd5b0 T0)
==3389808==The signal is caused by a READ memory access.
==3389808==Hint: address points to the zero page.
    #0 0x7f74e82f270b in mp4v2::impl::MP4File::GetChapters(MP4Chapter_s**, unsigned int*, MP4ChapterType) /opt/mp4v2/src/mp4file.cpp:2662
    #1 0x7f74e82c1294 in MP4GetChapters /opt/mp4v2/src/mp4.cpp:1647
    #2 0x5620329500df in mp4v2::util::ChapterUtility::actionList(mp4v2::util::Utility::JobContext&) /opt/mp4v2/util/mp4chaps.cpp:182
    #3 0x562032956476 in mp4v2::util::ChapterUtility::utility_job(mp4v2::util::Utility::JobContext&) /opt/mp4v2/util/mp4chaps.cpp:664
    #4 0x7f74e81db528 in mp4v2::util::Utility::job(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) /opt/mp4v2/libutil/Utility.cpp:298
    #5 0x7f74e81d9626 in mp4v2::util::Utility::batch(int) /opt/mp4v2/libutil/Utility.cpp:105
    #6 0x7f74e81de155 in mp4v2::util::Utility::process_impl() /opt/mp4v2/libutil/Utility.cpp:565
    #7 0x7f74e81dd24e in mp4v2::util::Utility::process() /opt/mp4v2/libutil/Utility.cpp:449
    #8 0x56203295957c in main /opt/mp4v2/util/mp4chaps.cpp:1188
    #9 0x7f74e7823a8f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
    #10 0x7f74e7823b48 in __libc_start_main_impl ../csu/libc-start.c:360
    #11 0x56203294c144 in _start (/opt/mp4v2/build2/mp4chaps+0xf144) (BuildId: 6362905fe8ce5624b29ef2869e210553dee47e65)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV /opt/mp4v2/src/mp4file.cpp:2662 in mp4v2::impl::MP4File::GetChapters(MP4Chapter_s**, unsigned int*, MP4ChapterType)
==3389808==ABORTING

Solution

It is recommended to insert a null pointer judgment, and take other instruction (if-else/exception handling) if sample is NULL. For example, if branch inserted line 2662 in src/mp4file.cpp can prevent the segfault.

                  // we know that sample+2 contains the title (sample[0] and sample[1] is the length)
                    const char * title = (const char *)&(sample[2]);
+                  if (sample == NULL) {
+                                        ...
+                     }
                    int titleLen = min((uint32_t)((sample[0] << 8) | sample[1]), (uint32_t)MP4V2_CHAPTER_TITLE_MAX);
                    strncpy(chapters[i].title, title, titleLen);
                    chapters[i].title[titleLen] = 0;

ty

mugichiya commented 1 week ago

I also found heap-based buffer overflow in mp4file.cpp:2662.

PoC

See testcases.

git clone https://github.com/mugichiya/pockey.git
cp -r ./pockey/projects/mp4v2_hof/testcases .
./mp4chaps --list ./testcases/0000000000.mp4

ASAN output

banjo@ttc:/opt/mp4v2/build$ ./mp4chaps --list ../../0000000000.mp4 
ReadAtom: "../../0000000000.mp4": invalid atom size, extends outside parent atom - skipping to end of "stbl" "stco" 150996203 vs 1279
=================================================================
==5147==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000003b11 at pc 0x7f562f5e80f7 bp 0x7ffe6f3c6680 sp 0x7ffe6f3c6670
READ of size 1 at 0x602000003b11 thread T0
    #0 0x7f562f5e80f6 in mp4v2::impl::MP4File::GetChapters(MP4Chapter_s**, unsigned int*, MP4ChapterType) /opt/mp4v2/src/mp4file.cpp:2662
    #1 0x7f562f5b7177 in MP4GetChapters /opt/mp4v2/src/mp4.cpp:1647
    #2 0x555e9921415a in mp4v2::util::ChapterUtility::actionList(mp4v2::util::Utility::JobContext&) /opt/mp4v2/util/mp4chaps.cpp:182
    #3 0x555e9921a581 in mp4v2::util::ChapterUtility::utility_job(mp4v2::util::Utility::JobContext&) /opt/mp4v2/util/mp4chaps.cpp:664
    #4 0x7f562f4e44c5 in mp4v2::util::Utility::job(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) /opt/mp4v2/libutil/Utility.cpp:298
    #5 0x7f562f4e2595 in mp4v2::util::Utility::batch(int) /opt/mp4v2/libutil/Utility.cpp:105
    #6 0x7f562f4e718d in mp4v2::util::Utility::process_impl() /opt/mp4v2/libutil/Utility.cpp:565
    #7 0x7f562f4e6252 in mp4v2::util::Utility::process() /opt/mp4v2/libutil/Utility.cpp:449
    #8 0x555e9921d794 in main /opt/mp4v2/util/mp4chaps.cpp:1188
    #9 0x7f562edf0082 in __libc_start_main ../csu/libc-start.c:308
    #10 0x555e9921012d in _start (/opt/mp4v2/build2/mp4chaps+0xf12d)

0x602000003b11 is located 0 bytes to the right of 1-byte region [0x602000003b10,0x602000003b11)
allocated by thread T0 here:
    #0 0x7f562f948808 in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cc:144
    #1 0x7f562f4d9392 in mp4v2::impl::MP4Malloc(unsigned long) /opt/mp4v2/src/mp4util.h:63
    #2 0x7f562f615dbc in mp4v2::impl::MP4Track::ReadSample(unsigned int, unsigned char**, unsigned int*, unsigned long*, unsigned long*, unsigned long*, bool*, bool*, unsigned int*) /opt/mp4v2/src/mp4track.cpp:323
    #3 0x7f562f5e8016 in mp4v2::impl::MP4File::GetChapters(MP4Chapter_s**, unsigned int*, MP4ChapterType) /opt/mp4v2/src/mp4file.cpp:2655
    #4 0x7f562f5b7177 in MP4GetChapters /opt/mp4v2/src/mp4.cpp:1647
    #5 0x555e9921415a in mp4v2::util::ChapterUtility::actionList(mp4v2::util::Utility::JobContext&) /opt/mp4v2/util/mp4chaps.cpp:182
    #6 0x555e9921a581 in mp4v2::util::ChapterUtility::utility_job(mp4v2::util::Utility::JobContext&) /opt/mp4v2/util/mp4chaps.cpp:664
    #7 0x7f562f4e44c5 in mp4v2::util::Utility::job(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) /opt/mp4v2/libutil/Utility.cpp:298
    #8 0x7f562f4e2595 in mp4v2::util::Utility::batch(int) /opt/mp4v2/libutil/Utility.cpp:105
    #9 0x7f562f4e718d in mp4v2::util::Utility::process_impl() /opt/mp4v2/libutil/Utility.cpp:565
    #10 0x7f562f4e6252 in mp4v2::util::Utility::process() /opt/mp4v2/libutil/Utility.cpp:449
    #11 0x555e9921d794 in main /opt/mp4v2/util/mp4chaps.cpp:1188
    #12 0x7f562edf0082 in __libc_start_main ../csu/libc-start.c:308

SUMMARY: AddressSanitizer: heap-buffer-overflow /opt/mp4v2/src/mp4file.cpp:2662 in mp4v2::impl::MP4File::GetChapters(MP4Chapter_s**, unsigned int*, MP4ChapterType)
Shadow bytes around the buggy address:
  0x0c047fff8710: fa fa 04 fa fa fa 04 fa fa fa fd fa fa fa fd fd
  0x0c047fff8720: fa fa fd fa fa fa fd fa fa fa fd fa fa fa 04 fa
  0x0c047fff8730: fa fa 04 fa fa fa 04 fa fa fa 04 fa fa fa 01 fa
  0x0c047fff8740: fa fa fd fd fa fa 04 fa fa fa 04 fa fa fa fd fa
  0x0c047fff8750: fa fa 00 00 fa fa 04 fa fa fa 00 fa fa fa 00 00
=>0x0c047fff8760: fa fa[01]fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff8770: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff8780: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff8790: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff87a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff87b0: 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
==5147==ABORTING

ty