Opened 3 years ago

Closed 3 years ago

#9003 closed defect (invalid)

TSAN reports heap-user-after-free in ff_h2645_extract_rbsp

Reported by: jsierant-at-vewd Owned by:
Priority: normal Component: avcodec
Version: unspecified Keywords:
Cc: Blocked By:
Blocking: Reproduced by developer: no
Analyzed by developer: no

Description

The problem has been detected in FFmpeg for the chromium project and is reproducable with following code:

std::vector<std::uint8_t> bitstream = {
    0x00, 0x00, 0x00, 0x01, 0x02, 0x01, 0xE0, 0x64, 0x9D, 0x78, 0x24, 0x72,
    0x72, 0x19, 0x9E, 0x40, 0xF5, 0x24, 0x0F, 0x81, 0xE4, 0x1B, 0xA8, 0x87,
    0xB3, 0xCF, 0x84, 0x10, 0x60, 0xFE, 0x1C, 0x5F, 0x80, 0x00, 0x08, 0xE8,
    0x5A, 0x00, 0x02, 0x7E, 0x61, 0x80, 0x20, 0x60, 0x67, 0x00, 0xCD, 0x80,
    0x5D, 0xC5, 0x59, 0x83, 0x44, 0x75, 0x51, 0xC1, 0xEB, 0x24, 0xFF, 0x64,
    0x2F, 0x0D, 0xF2, 0xC5, 0x60, 0x15, 0x21, 0x19};

static const int kIsNalff = 0;
static const int kNalLengthSize = 2;
static const int kSmallPadding = 1;
static const int kUseRef = 0;

::H2645Packet packet{};
::AVCodecContext context{};
::ff_h2645_packet_split(&packet, bitstream.data(), bitstream.size(), &context,
                        kIsNalff, kNalLengthSize, AV_CODEC_ID_HEVC,
                        kSmallPadding, kUseRef);

TSAN report:

WARNING: ThreadSanitizer: heap-use-after-free (pid=422689)
  Read of size 1 at 0x7b140000a958 by main thread:
    #0 ff_h2645_extract_rbsp third_party/ffmpeg/libavcodec/h2645_parse.c:57:17 (libffmpeg.so+0x2d12f7)
    #1 ff_h2645_packet_split third_party/ffmpeg/libavcodec/h2645_parse.c:485:20 (libffmpeg.so+0x2d21af)
    #2 media::FFmpegHevcTest_NalSplit_Test::TestBody() media/ffmpeg/ffmpeg_common_unittest.cc:396:3 (media_unittests+0x14a0039)
    #3 void testing::internal::HandleExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) third_party/googletest/src/googletest/src/gtest.cc (media_unittests+0x15225ed)
    #4 testing::Test::Run() third_party/googletest/src/googletest/src/gtest.cc:2689:5 (media_unittests+0x1522548)
    #5 testing::TestInfo::Run() third_party/googletest/src/googletest/src/gtest.cc:2866:11 (media_unittests+0x1522f9c)
    #6 testing::TestSuite::Run() third_party/googletest/src/googletest/src/gtest.cc:3020:28 (media_unittests+0x1523ac6)
    #7 testing::internal::UnitTestImpl::RunAllTests() third_party/googletest/src/googletest/src/gtest.cc:5730:44 (media_unittests+0x152bf1f)
    #8 bool testing::internal::HandleExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) third_party/googletest/src/googletest/src/gtest.cc (media_unittests+0x152bb79)
    #9 testing::UnitTest::Run() third_party/googletest/src/googletest/src/gtest.cc:5313:10 (media_unittests+0x152ba64)
    #10 RUN_ALL_TESTS() third_party/googletest/src/googletest/include/gtest/gtest.h:2485:46 (media_unittests+0x1fdcb1f)
    #11 base::TestSuite::Run() base/test/test_suite.cc:480:16 (media_unittests+0x1fdc48b)
    #12 Invoke<int (base::TestSuite::*)(), TestSuiteNoAtExit *> base/bind_internal.h:498:12 (media_unittests+0x1483c14)
    #13 int base::internal::InvokeHelper<false, int>::MakeItSo<int (base::TestSuite::*)(), TestSuiteNoAtExit*>(int (base::TestSuite::*&&)(), TestSuiteNoAtExit*&&) base/bind_internal.h:637:12 (media_unittests+0x1483c14)
    #14 int base::internal::Invoker<base::internal::BindState<int (base::TestSuite::*)(), base::internal::UnretainedWrapper<TestSuiteNoAtExit> >, int ()>::RunImpl<int (base::TestSuite::*)(), std::tuple<base::internal::UnretainedWrapper<TestSuiteNoAtExit> >, 0ul>(int (base::TestSuite::*&&)(), std::tuple<base::internal::UnretainedWrapper<TestSuiteNoAtExit> >&&, std::integer_sequence<unsigned long, 0ul>) base/bind_internal.h:710:12 (media_unittests+0x1483b9d)
    #15 base::internal::Invoker<base::internal::BindState<int (base::TestSuite::*)(), base::internal::UnretainedWrapper<TestSuiteNoAtExit> >, int ()>::RunOnce(base::internal::BindStateBase*) base/bind_internal.h:679:12 (media_unittests+0x1483b58)
    #16 base::OnceCallback<int ()>::Run() && base/callback.h:100:12 (media_unittests+0x1b96a63)
    #17 base::(anonymous namespace)::LaunchUnitTestsInternal(base::OnceCallback<int ()>, unsigned long, int, unsigned long, bool, base::OnceCallback<void ()>) base/test/launcher/unit_test_launcher.cc:179:38 (media_unittests+0x200183d)
    #18 base::LaunchUnitTests(int, char**, base::OnceCallback<int ()>, unsigned long) base/test/launcher/unit_test_launcher.cc:249:10 (media_unittests+0x20016d3)
    #19 main media/test/run_all_unittests.cc:55:10 (media_unittests+0x14839a6)

  Previous write of size 8 at 0x7b140000a958 by main thread:
    #0 operator delete(void*) /home/jenkins/shared_ws/opera_work_0/chromium/src/third_party/llvm/compiler-rt/lib/tsan/rtl/tsan_new_delete.cpp:126:3 (media_unittests+0xe4edde)
    #1 ~basic_string tc_cache_workdir/x86_64-gcc5-4.22-2020-10-28-c3cf13530b5fd448252afe7097a212ec/lib/gcc/x86_64-linux-gnu/5.5.0/../../../../include/c++/5.5.0/bits/basic_string.h:559:9 (media_unittests+0x151e917)
    #2 testing::internal::UnitTestOptions::FilterMatchesTest(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) third_party/googletest/src/googletest/src/gtest.cc:727:1 (media_unittests+0x151e917)
    #3 testing::internal::UnitTestImpl::FilterTests(testing::internal::UnitTestImpl::ReactionToSharding) third_party/googletest/src/googletest/src/gtest.cc:5918:35 (media_unittests+0x152d9d6)
    #4 testing::internal::UnitTestImpl::RunAllTests() third_party/googletest/src/googletest/src/gtest.cc:5658:33 (media_unittests+0x152bc23)
    #5 bool testing::internal::HandleExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) third_party/googletest/src/googletest/src/gtest.cc (media_unittests+0x152bb79)
    #6 testing::UnitTest::Run() third_party/googletest/src/googletest/src/gtest.cc:5313:10 (media_unittests+0x152ba64)
    #7 RUN_ALL_TESTS() third_party/googletest/src/googletest/include/gtest/gtest.h:2485:46 (media_unittests+0x1fdcb1f)
    #8 base::TestSuite::Run() base/test/test_suite.cc:480:16 (media_unittests+0x1fdc48b)
    #9 Invoke<int (base::TestSuite::*)(), TestSuiteNoAtExit *> base/bind_internal.h:498:12 (media_unittests+0x1483c14)
    #10 int base::internal::InvokeHelper<false, int>::MakeItSo<int (base::TestSuite::*)(), TestSuiteNoAtExit*>(int (base::TestSuite::*&&)(), TestSuiteNoAtExit*&&) base/bind_internal.h:637:12 (media_unittests+0x1483c14)
    #11 int base::internal::Invoker<base::internal::BindState<int (base::TestSuite::*)(), base::internal::UnretainedWrapper<TestSuiteNoAtExit> >, int ()>::RunImpl<int (base::TestSuite::*)(), std::tuple<base::internal::UnretainedWrapper<TestSuiteNoAtExit> >, 0ul>(int (base::TestSuite::*&&)(), std::tuple<base::internal::UnretainedWrapper<TestSuiteNoAtExit> >&&, std::integer_sequence<unsigned long, 0ul>) base/bind_internal.h:710:12 (media_unittests+0x1483b9d)
    #12 base::internal::Invoker<base::internal::BindState<int (base::TestSuite::*)(), base::internal::UnretainedWrapper<TestSuiteNoAtExit> >, int ()>::RunOnce(base::internal::BindStateBase*) base/bind_internal.h:679:12 (media_unittests+0x1483b58)
    #13 base::OnceCallback<int ()>::Run() && base/callback.h:100:12 (media_unittests+0x1b96a63)
    #14 base::(anonymous namespace)::LaunchUnitTestsInternal(base::OnceCallback<int ()>, unsigned long, int, unsigned long, bool, base::OnceCallback<void ()>) base/test/launcher/unit_test_launcher.cc:179:38 (media_unittests+0x200183d)
    #15 base::LaunchUnitTests(int, char**, base::OnceCallback<int ()>, unsigned long) base/test/launcher/unit_test_launcher.cc:249:10 (media_unittests+0x20016d3)
    #16 main media/test/run_all_unittests.cc:55:10 (media_unittests+0x14839a6)

  Location is heap block of size 68 at 0x7b140000a910 allocated by main thread:
    #0 operator new(unsigned long) /home/jenkins/shared_ws/opera_work_0/chromium/src/third_party/llvm/compiler-rt/lib/tsan/rtl/tsan_new_delete.cpp:64:3 (media_unittests+0xe4e726)
    #1 allocate tc_cache_workdir/x86_64-gcc5-4.22-2020-10-28-c3cf13530b5fd448252afe7097a212ec/lib/gcc/x86_64-linux-gnu/5.5.0/../../../../include/c++/5.5.0/ext/new_allocator.h:104:27 (media_unittests+0x10234a2)
    #2 allocate tc_cache_workdir/x86_64-gcc5-4.22-2020-10-28-c3cf13530b5fd448252afe7097a212ec/lib/gcc/x86_64-linux-gnu/5.5.0/../../../../include/c++/5.5.0/bits/alloc_traits.h:491:20 (media_unittests+0x10234a2)
    #3 std::_Vector_base<unsigned char, std::allocator<unsigned char> >::_M_allocate(unsigned long) tc_cache_workdir/x86_64-gcc5-4.22-2020-10-28-c3cf13530b5fd448252afe7097a212ec/lib/gcc/x86_64-linux-gnu/5.5.0/../../../../include/c++/5.5.0/bits/stl_vector.h:170:20 (media_unittests+0x10234a2)
    #4 void std::vector<unsigned char, std::allocator<unsigned char> >::_M_range_initialize<unsigned char const*>(unsigned char const*, unsigned char const*, std::forward_iterator_tag) tc_cache_workdir/x86_64-gcc5-4.22-2020-10-28-c3cf13530b5fd448252afe7097a212ec/lib/gcc/x86_64-linux-gnu/5.5.0/../../../../include/c++/5.5.0/bits/stl_vector.h:1287:35 (media_unittests+0x10c2e8b)
    #5 vector tc_cache_workdir/x86_64-gcc5-4.22-2020-10-28-c3cf13530b5fd448252afe7097a212ec/lib/gcc/x86_64-linux-gnu/5.5.0/../../../../include/c++/5.5.0/bits/stl_vector.h:377:2 (media_unittests+0x149ffeb)
    #6 media::FFmpegHevcTest_NalSplit_Test::TestBody() media/ffmpeg/ffmpeg_common_unittest.cc:381:41 (media_unittests+0x149ffeb)
    #7 void testing::internal::HandleExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) third_party/googletest/src/googletest/src/gtest.cc (media_unittests+0x15225ed)
    #8 testing::Test::Run() third_party/googletest/src/googletest/src/gtest.cc:2689:5 (media_unittests+0x1522548)
    #9 testing::TestInfo::Run() third_party/googletest/src/googletest/src/gtest.cc:2866:11 (media_unittests+0x1522f9c)
    #10 testing::TestSuite::Run() third_party/googletest/src/googletest/src/gtest.cc:3020:28 (media_unittests+0x1523ac6)
    #11 testing::internal::UnitTestImpl::RunAllTests() third_party/googletest/src/googletest/src/gtest.cc:5730:44 (media_unittests+0x152bf1f)
    #12 bool testing::internal::HandleExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) third_party/googletest/src/googletest/src/gtest.cc (media_unittests+0x152bb79)
    #13 testing::UnitTest::Run() third_party/googletest/src/googletest/src/gtest.cc:5313:10 (media_unittests+0x152ba64)
    #14 RUN_ALL_TESTS() third_party/googletest/src/googletest/include/gtest/gtest.h:2485:46 (media_unittests+0x1fdcb1f)
    #15 base::TestSuite::Run() base/test/test_suite.cc:480:16 (media_unittests+0x1fdc48b)
    #16 Invoke<int (base::TestSuite::*)(), TestSuiteNoAtExit *> base/bind_internal.h:498:12 (media_unittests+0x1483c14)
    #17 int base::internal::InvokeHelper<false, int>::MakeItSo<int (base::TestSuite::*)(), TestSuiteNoAtExit*>(int (base::TestSuite::*&&)(), TestSuiteNoAtExit*&&) base/bind_internal.h:637:12 (media_unittests+0x1483c14)
    #18 int base::internal::Invoker<base::internal::BindState<int (base::TestSuite::*)(), base::internal::UnretainedWrapper<TestSuiteNoAtExit> >, int ()>::RunImpl<int (base::TestSuite::*)(), std::tuple<base::internal::UnretainedWrapper<TestSuiteNoAtExit> >, 0ul>(int (base::TestSuite::*&&)(), std::tuple<base::internal::UnretainedWrapper<TestSuiteNoAtExit> >&&, std::integer_sequence<unsigned long, 0ul>) base/bind_internal.h:710:12 (media_unittests+0x1483b9d)
    #19 base::internal::Invoker<base::internal::BindState<int (base::TestSuite::*)(), base::internal::UnretainedWrapper<TestSuiteNoAtExit> >, int ()>::RunOnce(base::internal::BindStateBase*) base/bind_internal.h:679:12 (media_unittests+0x1483b58)
    #20 base::OnceCallback<int ()>::Run() && base/callback.h:100:12 (media_unittests+0x1b96a63)
    #21 base::(anonymous namespace)::LaunchUnitTestsInternal(base::OnceCallback<int ()>, unsigned long, int, unsigned long, bool, base::OnceCallback<void ()>) base/test/launcher/unit_test_launcher.cc:179:38 (media_unittests+0x200183d)
    #22 base::LaunchUnitTests(int, char**, base::OnceCallback<int ()>, unsigned long) base/test/launcher/unit_test_launcher.cc:249:10 (media_unittests+0x20016d3)
    #23 main media/test/run_all_unittests.cc:55:10 (media_unittests+0x14839a6)

SUMMARY: ThreadSanitizer: heap-use-after-free third_party/ffmpeg/libavcodec/h2645_parse.c:57:17 in ff_h2645_extract_rbsp

The problem originates in ff_h2645_extract_rbsp (line 57 has been marked):

#if HAVE_FAST_64BIT
    for (i = 0; i + 1 < length; i += 9) {
        if (!((~AV_RN64(src + i) & // line 57
               (AV_RN64(src + i) - 0x0100010001000101ULL)) &
              0x8000800080008080ULL))
            continue;
        FIND_FIRST_ZERO;
        STARTCODE_TEST;
        i -= 7;
    }
#else

It seems that when the optimizations are enabled (HAVE_FAST_UNALIGNED and HAVE_FAST_64BIT are set) the size of the provided data src is exceeded (despite that length = 68, byte 72 is read (calculated as 0x7b140000a958 - 0x7b140000a910)).
The same problem will probably be visible when HAVE_FAST_64BIT is not set as the algorithm is the same for 32 bits machines.

Accessing memory outside of allocated space may lead to segmentation fault and an abnormal termination of the process.

The FFmpeg version that has been used is:
Upstream Git: git://source.ffmpeg.org/ffmpeg.git
Last Upstream Merge: 71ec3e4583def61fbb32a4815376773ef7c80dee, Aug 27 2020

The code seems to be same as in latest FFmpeg release (4.3.1) so the problem should also be visible there.

Change History (1)

comment:1 by mkver, 3 years ago

Resolution: invalid
Status: newclosed

Your data is missing its padding - AV_INPUT_BUFFER_PADDING_SIZE of padding is required (to allow to use algorithms that overread slightly).

Note: See TracTickets for help on using tickets.