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 getLastPCR (programStreamDemuxer.cpp) #836

Closed iwashiira closed 3 months ago

iwashiira commented 3 months ago

Our fuzzer found heap buffer over-read in programStreamDemuxer. in the current master(75c9cb3). PoC is here.

#include "bufferedReaderManager.h"
#include "vod_common.h"
#include "abstractDemuxer.h"
#include "programStreamDemuxer.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 ProgramStreamDemuxer(readManager);

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

    PIDSet acceptedPidSet;

    int64_t fileDuration = demuxer->getFileDurationNano();

    return 0;
}

Folloing is an output of valgrind. vuln17.vob is in poc17.zip

==25736== Memcheck, a memory error detector
==25736== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==25736== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==25736== Command: ../tsMuxer/build/tsMuxer/tsmuxer ./crash/vuln17.vob
==25736== 
==25736== Warning: invalid file descriptor -1 in syscall close()
==25736== Invalid read of size 1
==25736==    at 0x360170: get_pts(unsigned char const*) (pesPacket.h:13)
==25736==    by 0x362359: PESPacket::getPts() (pesPacket.h:162)
==25736==    by 0x361E25: getLastPCR(File const&, int, long) (programStreamDemuxer.cpp:367)
==25736==    by 0x362034: getPSDuration(char const*) (programStreamDemuxer.cpp:422)
==25736==    by 0x3620FD: ProgramStreamDemuxer::getFileDurationNano() const (programStreamDemuxer.cpp:438)
==25736==    by 0x2E688D: main (main.cpp:25)
==25736==  Address 0x5184140 is 0 bytes after a block of size 262,144 alloc'd
==25736==    at 0x484A2F3: operator new[](unsigned long) (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==25736==    by 0x361D73: getLastPCR(File const&, int, long) (programStreamDemuxer.cpp:350)
==25736==    by 0x362034: getPSDuration(char const*) (programStreamDemuxer.cpp:422)
==25736==    by 0x3620FD: ProgramStreamDemuxer::getFileDurationNano() const (programStreamDemuxer.cpp:438)
==25736==    by 0x2E688D: main (main.cpp:25)
==25736== 
==25736== Invalid read of size 1
==25736==    at 0x360198: get_pts(unsigned char const*) (pesPacket.h:14)
==25736==    by 0x362359: PESPacket::getPts() (pesPacket.h:162)
==25736==    by 0x361E25: getLastPCR(File const&, int, long) (programStreamDemuxer.cpp:367)
==25736==    by 0x362034: getPSDuration(char const*) (programStreamDemuxer.cpp:422)
==25736==    by 0x3620FD: ProgramStreamDemuxer::getFileDurationNano() const (programStreamDemuxer.cpp:438)
==25736==    by 0x2E688D: main (main.cpp:25)
==25736==  Address 0x5184141 is 1 bytes after a block of size 262,144 alloc'd
==25736==    at 0x484A2F3: operator new[](unsigned long) (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==25736==    by 0x361D73: getLastPCR(File const&, int, long) (programStreamDemuxer.cpp:350)
==25736==    by 0x362034: getPSDuration(char const*) (programStreamDemuxer.cpp:422)
==25736==    by 0x3620FD: ProgramStreamDemuxer::getFileDurationNano() const (programStreamDemuxer.cpp:438)
==25736==    by 0x2E688D: main (main.cpp:25)
==25736== 
==25736== Invalid read of size 1
==25736==    at 0x3601AB: get_pts(unsigned char const*) (pesPacket.h:14)
==25736==    by 0x362359: PESPacket::getPts() (pesPacket.h:162)
==25736==    by 0x361E25: getLastPCR(File const&, int, long) (programStreamDemuxer.cpp:367)
==25736==    by 0x362034: getPSDuration(char const*) (programStreamDemuxer.cpp:422)
==25736==    by 0x3620FD: ProgramStreamDemuxer::getFileDurationNano() const (programStreamDemuxer.cpp:438)
==25736==    by 0x2E688D: main (main.cpp:25)
==25736==  Address 0x5184142 is 2 bytes after a block of size 262,144 alloc'd
==25736==    at 0x484A2F3: operator new[](unsigned long) (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==25736==    by 0x361D73: getLastPCR(File const&, int, long) (programStreamDemuxer.cpp:350)
==25736==    by 0x362034: getPSDuration(char const*) (programStreamDemuxer.cpp:422)
==25736==    by 0x3620FD: ProgramStreamDemuxer::getFileDurationNano() const (programStreamDemuxer.cpp:438)
==25736==    by 0x2E688D: main (main.cpp:25)
==25736== 
==25736== Invalid read of size 1
==25736==    at 0x3601CC: get_pts(unsigned char const*) (pesPacket.h:16)
==25736==    by 0x362359: PESPacket::getPts() (pesPacket.h:162)
==25736==    by 0x361E25: getLastPCR(File const&, int, long) (programStreamDemuxer.cpp:367)
==25736==    by 0x362034: getPSDuration(char const*) (programStreamDemuxer.cpp:422)
==25736==    by 0x3620FD: ProgramStreamDemuxer::getFileDurationNano() const (programStreamDemuxer.cpp:438)
==25736==    by 0x2E688D: main (main.cpp:25)
==25736==  Address 0x5184143 is 3 bytes after a block of size 262,144 alloc'd
==25736==    at 0x484A2F3: operator new[](unsigned long) (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==25736==    by 0x361D73: getLastPCR(File const&, int, long) (programStreamDemuxer.cpp:350)
==25736==    by 0x362034: getPSDuration(char const*) (programStreamDemuxer.cpp:422)
==25736==    by 0x3620FD: ProgramStreamDemuxer::getFileDurationNano() const (programStreamDemuxer.cpp:438)
==25736==    by 0x2E688D: main (main.cpp:25)
==25736== 
==25736== Invalid read of size 1
==25736==    at 0x3601DF: get_pts(unsigned char const*) (pesPacket.h:16)
==25736==    by 0x362359: PESPacket::getPts() (pesPacket.h:162)
==25736==    by 0x361E25: getLastPCR(File const&, int, long) (programStreamDemuxer.cpp:367)
==25736==    by 0x362034: getPSDuration(char const*) (programStreamDemuxer.cpp:422)
==25736==    by 0x3620FD: ProgramStreamDemuxer::getFileDurationNano() const (programStreamDemuxer.cpp:438)
==25736==    by 0x2E688D: main (main.cpp:25)
==25736==  Address 0x5184144 is 4 bytes after a block of size 262,144 alloc'd
==25736==    at 0x484A2F3: operator new[](unsigned long) (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==25736==    by 0x361D73: getLastPCR(File const&, int, long) (programStreamDemuxer.cpp:350)
==25736==    by 0x362034: getPSDuration(char const*) (programStreamDemuxer.cpp:422)
==25736==    by 0x3620FD: ProgramStreamDemuxer::getFileDurationNano() const (programStreamDemuxer.cpp:438)
==25736==    by 0x2E688D: main (main.cpp:25)
==25736== 
==25736== 
==25736== HEAP SUMMARY:
==25736==     in use at exit: 2,047 bytes in 2 blocks
==25736==   total heap usage: 265 allocs, 263 frees, 4,896,926 bytes allocated
==25736== 
==25736== LEAK SUMMARY:
==25736==    definitely lost: 2,016 bytes in 1 blocks
==25736==    indirectly lost: 31 bytes in 1 blocks
==25736==      possibly lost: 0 bytes in 0 blocks
==25736==    still reachable: 0 bytes in 0 blocks
==25736==         suppressed: 0 bytes in 0 blocks
==25736== Rerun with --leak-check=full to see details of leaked memory
==25736== 
==25736== For lists of detected and suppressed errors, rerun with: -s
==25736== ERROR SUMMARY: 5 errors from 5 contexts (suppressed: 0 from 0)

It is caused by this line. https://github.com/justdan96/tsMuxer/blob/75c9cb3514815d07378007d36cc90c3f209e7b36/tsMuxer/programStreamDemuxer.cpp#L359

The internal function get_pts(), which is executed in getPts(), considers the area beyond CurPos+9 to be the 8-byte area where pts are stored and reads 8 bytes, which causes OOB (heap buffer over-read).

https://github.com/justdan96/tsMuxer/blob/75c9cb3514815d07378007d36cc90c3f209e7b36/tsMuxer/programStreamDemuxer.cpp#L367

Ricerca Security, Inc.