strukturag / libde265

Open h.265 video codec implementation.
Other
1.7k stars 457 forks source link

A heap-buffer-overflow has occurred when running program dec265 in function derive_collocated_motion_vectors at motion.cc #394

Closed blu3sh0rk closed 1 year ago

blu3sh0rk commented 1 year ago

Desctiption

A heap-buffer-overflow has occurred when running program dec265 in function derive_collocated_motion_vectors at motion.cc:1259:41

Version

dec265  v1.0.11

git log
commit fef32a7761993702c699dfbe3699e44374eb44b5 (HEAD -> master, origin/master, origin/HEAD)
Merge: 3aea5a45 c2b60f1c
Author: Dirk Farin <dirk.farin@gmail.com>
Date:   Thu Feb 9 11:13:24 2023 +0100

Steps to reproduce

git clone https://github.com/strukturag/libde265.git
cd libde265
./autogen.sh
export CFLAGS="-g -O0 -lpthread -fsanitize=address"
export CXXFLAGS="-g -O0 -lpthread -fsanitize=address"
export LDFLAGS="-fsanitize=address"
./configure --disable-shared
make -j
cd dec265
./dec265 Heap-overflow-POC1
WARNING: Bit-depth of current image does not match SPS
WARNING: Bit-depth of current image does not match SPS
WARNING: Too many warnings queued
=================================================================
==137060==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x6020000000a8 at pc 0x0000006cc0b4 bp 0x7fff28554e90 sp 0x7fff28554e88
READ of size 8 at 0x6020000000a8 thread T0
    #0 0x6cc0b3 in derive_collocated_motion_vectors(base_context*, de265_image*, slice_segment_header const*, int, int, int, int, int, int, int, MotionVector*, unsigned char*) /home/lzy/fuzz/oss/libde265/libde265/motion.cc:1259:41
    #1 0x6cd4cf in derive_temporal_luma_vector_prediction(base_context*, de265_image*, slice_segment_header const*, int, int, int, int, int, int, MotionVector*, unsigned char*) /home/lzy/fuzz/oss/libde265/libde265/motion.cc:1388:5
    #2 0x6cf16c in get_merge_candidate_list_without_step_9(base_context*, slice_segment_header const*, MotionVectorAccess const&, de265_image*, int, int, int, int, int, int, int, int, int, PBMotion*) /home/lzy/fuzz/oss/libde265/libde265/motion.cc:1523:5
    #3 0x6d052b in derive_luma_motion_merge_mode(base_context*, slice_segment_header const*, de265_image*, int, int, int, int, int, int, int, int, int, PBMotion*) /home/lzy/fuzz/oss/libde265/libde265/motion.cc:1612:3
    #4 0x6d80d6 in motion_vectors_and_ref_indices(base_context*, slice_segment_header const*, de265_image*, PBMotionCoding const&, int, int, int, int, int, int, int, int, PBMotion*) /home/lzy/fuzz/oss/libde265/libde265/motion.cc:2088:7
    #5 0x6d9435 in decode_prediction_unit(base_context*, slice_segment_header const*, de265_image*, PBMotionCoding const&, int, int, int, int, int, int, int, int) /home/lzy/fuzz/oss/libde265/libde265/motion.cc:2171:3
    #6 0x5bf634 in read_prediction_unit(thread_context*, int, int, int, int, int, int, int, int, int) /home/lzy/fuzz/oss/libde265/libde265/slice.cc:4136:3
    #7 0x5c233c in read_coding_unit(thread_context*, int, int, int, int) /home/lzy/fuzz/oss/libde265/libde265/slice.cc:4504:9
    #8 0x5b17db in read_coding_quadtree(thread_context*, int, int, int, int) /home/lzy/fuzz/oss/libde265/libde265/slice.cc:4652:5
    #9 0x5b0887 in read_coding_tree_unit(thread_context*) /home/lzy/fuzz/oss/libde265/libde265/slice.cc:2861:3
    #10 0x5c7fe8 in decode_substream(thread_context*, bool, bool) /home/lzy/fuzz/oss/libde265/libde265/slice.cc:4741:5
    #11 0x5cb648 in read_slice_segment_data(thread_context*) /home/lzy/fuzz/oss/libde265/libde265/slice.cc:5054:14
    #12 0x4e8254 in decoder_context::decode_slice_unit_sequential(image_unit*, slice_unit*) /home/lzy/fuzz/oss/libde265/libde265/decctx.cc:853:7
    #13 0x4e614f in decoder_context::decode_slice_unit_parallel(image_unit*, slice_unit*) /home/lzy/fuzz/oss/libde265/libde265/decctx.cc:955:11    #14 0x4e4b1f in decoder_context::decode_some(bool*) /home/lzy/fuzz/oss/libde265/libde265/decctx.cc:740:13
    #15 0x4e1a3f in decoder_context::read_slice_NAL(bitreader&, NAL_unit*, nal_header&) /home/lzy/fuzz/oss/libde265/libde265/decctx.cc:698:9
    #16 0x4eb7f1 in decoder_context::decode_NAL(NAL_unit*) /home/lzy/fuzz/oss/libde265/libde265/decctx.cc:1240:11
    #17 0x4ec6a1 in decoder_context::decode(int*) /home/lzy/fuzz/oss/libde265/libde265/decctx.cc:1328:16
    #18 0x4d3645 in de265_decode /home/lzy/fuzz/oss/libde265/libde265/de265.cc:367:15
    #19 0x4d0363 in main /home/lzy/fuzz/oss/libde265/dec265/dec265.cc:764:17
    #20 0x7fccbc3e8082 in __libc_start_main /build/glibc-KZwQYS/glibc-2.31/csu/../csu/libc-start.c:308:16
    #21 0x41e5bd in _start (/home/lzy/fuzz/oss/libde265/dec265/dec265+0x41e5bd)

0x6020000000a8 is located 16 bytes to the right of 8-byte region [0x602000000090,0x602000000098)
allocated by thread T0 here:
    #0 0x4ca8dd in operator new(unsigned long) (/home/lzy/fuzz/oss/libde265/dec265/dec265+0x4ca8dd)
    #1 0x500842 in __gnu_cxx::new_allocator<slice_segment_header*>::allocate(unsigned long, void const*) /usr/lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/ext/new_allocator.h:114:27
    #2 0x500751 in std::allocator_traits<std::allocator<slice_segment_header*> >::allocate(std::allocator<slice_segment_header*>&, unsigned long) /usr/lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/alloc_traits.h:443:20
    #3 0x4ffef1 in std::_Vector_base<slice_segment_header*, std::allocator<slice_segment_header*> >::_M_allocate(unsigned long) /usr/lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/stl_vector.h:343:20
    #4 0x4ff227 in void std::vector<slice_segment_header*, std::allocator<slice_segment_header*> >::_M_realloc_insert<slice_segment_header* const&>(__gnu_cxx::__normal_iterator<slice_segment_header**, std::vector<slice_segment_header*, std::allocator<slice_segment_header*> > >, slice_segment_header* const&) /usr/lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/vector.tcc:440:33
    #5 0x4feea3 in std::vector<slice_segment_header*, std::allocator<slice_segment_header*> >::push_back(slice_segment_header* const&) /usr/lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/stl_vector.h:1195:4
    #6 0x4e4066 in de265_image::add_slice_segment_header(slice_segment_header*) /home/lzy/fuzz/oss/libde265/libde265/../libde265/image.h:326:12    #7 0x4e12ba in decoder_context::read_slice_NAL(bitreader&, NAL_unit*, nal_header&) /home/lzy/fuzz/oss/libde265/libde265/decctx.cc:657:14
    #8 0x4eb7f1 in decoder_context::decode_NAL(NAL_unit*) /home/lzy/fuzz/oss/libde265/libde265/decctx.cc:1240:11
    #9 0x4ec6a1 in decoder_context::decode(int*) /home/lzy/fuzz/oss/libde265/libde265/decctx.cc:1328:16
    #10 0x4d3645 in de265_decode /home/lzy/fuzz/oss/libde265/libde265/de265.cc:367:15
    #11 0x4d0363 in main /home/lzy/fuzz/oss/libde265/dec265/dec265.cc:764:17
    #12 0x7fccbc3e8082 in __libc_start_main /build/glibc-KZwQYS/glibc-2.31/csu/../csu/libc-start.c:308:16

SUMMARY: AddressSanitizer: heap-buffer-overflow /home/lzy/fuzz/oss/libde265/libde265/motion.cc:1259:41 in derive_collocated_motion_vectors(base_context*, de265_image*, slice_segment_header const*, int, int, int, int, int, int, int, MotionVector*, unsigned char*)
Shadow bytes around the buggy address:
  0x0c047fff7fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c047fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c047fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c047fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c047fff8000: fa fa fd fa fa fa fd fd fa fa fd fa fa fa fd fa
=>0x0c047fff8010: fa fa 00 fa fa[fa]fd fa fa fa fd fa fa fa fd fa
  0x0c047fff8020: fa fa fd fd fa fa fd fa fa fa fd fa fa fa fd fa
  0x0c047fff8030: fa fa fd fd fa fa fd fa fa fa fd fd fa fa fd fa
  0x0c047fff8040: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa
  0x0c047fff8050: fa fa 04 fa fa fa fd fa fa fa 00 00 fa fa fd fa
  0x0c047fff8060: fa fa 00 fa fa fa 00 00 fa fa 00 00 fa fa 04 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
==137060==ABORTING

POC

https://github.com/blu3sh0rk/Fuzzing-crash/blob/main/Heap-overflow-POC1.zip

Code in function derive_collocated_motion_vectors at motion.cc:1259:41

if (allRefFramesBeforeCurrentFrame) {
      mvCol = mvi.mv[X];
      refIdxCol = mvi.refIdx[X];
      listCol = X;
    }
    else {
      int N = shdr->collocated_from_l0_flag;
      mvCol = mvi.mv[N];
      refIdxCol = mvi.refIdx[N];
      listCol = N;
    }
  }

  1259 const slice_segment_header* colShdr = colImg->slices[ colImg->get_SliceHeaderIndex(xColPb,yColPb) ];

Impact

Potentially causing DoS and RCE

farindk commented 1 year ago

Thank you

mf1632015 commented 1 year ago

This vulnerability has an CVE NO. CVE-2023-27103 Has this been fixed?

giancorderoortiz commented 1 year ago

Could you please generate a new version of this library (i.e. 1.0.12) with the fix in https://github.com/strukturag/libde265/commit/d6bf73e765b7a23627bfd7a8645c143fd9097995 ?