Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

heap-use-after-free/SEGV/heap-buffer-overflow in UncompressedImageCodec::get_luma_bits_per_pixel_from_configuration_unci #1044

Closed
fdu-sec opened this issue Nov 22, 2023 · 1 comment · Fixed by #1049

Comments

@fdu-sec
Copy link

fdu-sec commented Nov 22, 2023

Description

heap-use-after-free/SEGV/heap-buffer-overflow libheif/libheif/uncompressed_image.cc:537 in UncompressedImageCodec::get_luma_bits_per_pixel_from_configuration_unci

Version

commit: 64ece913266609789f5dc70fe7de9eb759badd7f

heif-convert  libheif version: 1.17.5
-------------------------------------------
Usage: heif-convert [options]  <input-image> [output-image]

The program determines the output file format from the output filename suffix.
These suffixes are recognized: jpg, jpeg, png, y4m. If no output filename is specified, 'jpg' is used.

Options:
  -h, --help                     show help
  -v, --version                  show version
  -q, --quality                  quality (for JPEG output)
  -o, --output FILENAME          write output to FILENAME (optional)
  -d, --decoder ID               use a specific decoder (see --list-decoders)
      --with-aux                 also write auxiliary images (e.g. depth images)
      --with-xmp                 write XMP metadata to file (output filename with .xmp suffix)
      --with-exif                write EXIF metadata to file (output filename with .exif suffix)
      --skip-exif-offset         skip EXIF metadata offset bytes
      --no-colons                replace ':' characters in auxiliary image filenames with '_'
      --list-decoders            list all available decoders (built-in and plugins)
      --quiet                    do not output status messages to console
  -C, --chroma-upsampling ALGO   Force chroma upsampling algorithm (nn = nearest-neighbor / bilinear)
      --png-compression-level #  Set to integer between 0 (fastest) and 9 (best). Use -1 for default.

Replay

cd libheif
mkdir build && cd build
CC="gcc -fsanitize=address" CXX="g++ -fsanitize=address" cmake -DCMAKE_BUILD_TYPE=Debug -DWITH_UNCOMPRESSED_CODEC=ON ..
make -j
./examples/heif-convert ./poc test.png

ASAN

I just show the uaf case, you can use my poc to reproduce the others.

==88148==ERROR: AddressSanitizer: heap-use-after-free on address 0x60e000000910 at pc 0x7f7a88d9ab47 bp 0x7ffef17996e0 sp 0x7ffef17996d0
READ of size 2 at 0x60e000000910 thread T0
    #0 0x7f7a88d9ab46 in UncompressedImageCodec::get_luma_bits_per_pixel_from_configuration_unci(HeifFile const&, unsigned int) libheif/libheif/uncompressed_image.cc:537
    #1 0x7f7a88c96f95 in HeifFile::get_luma_bits_per_pixel_from_configuration(unsigned int) const libheif/libheif/file.cc:609
    #2 0x7f7a88c58d54 in HeifContext::Image::get_luma_bits_per_pixel() const libheif/libheif/context.cc:1225
    #3 0x7f7a88c1abf7 in heif_image_handle_get_luma_bits_per_pixel libheif/libheif/heif.cc:846
    #4 0x55fa40c34835 in main libheif/examples/heif_convert.cc:475
    #5 0x7f7a88694082 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x24082)
    #6 0x55fa40c2fadd in _start (libheif/build/examples/heif-convert+0xbadd)

0x60e000000910 is located 16 bytes inside of 160-byte region [0x60e000000900,0x60e0000009a0)
freed by thread T0 here:
    #0 0x7f7a88f6c0d0 in operator delete(void*) (/lib/x86_64-linux-gnu/libasan.so.4+0xe20d0)
    #1 0x7f7a88c038d9 in __gnu_cxx::new_allocator<std::_Sp_counted_ptr_inplace<Box_hdlr, std::allocator<Box_hdlr>, (__gnu_cxx::_Lock_policy)2> >::deallocate(std::_Sp_counted_ptr_inplace<Box_hdlr, std::allocator<Box_hdlr>, (__gnu_cxx::_Lock_policy)2>*, unsigned long) /usr/include/c++/7/ext/new_allocator.h:125
    #2 0x7f7a88bfef61 in std::allocator_traits<std::allocator<std::_Sp_counted_ptr_inplace<Box_hdlr, std::allocator<Box_hdlr>, (__gnu_cxx::_Lock_policy)2> > >::deallocate(std::allocator<std::_Sp_counted_ptr_inplace<Box_hdlr, std::allocator<Box_hdlr>, (__gnu_cxx::_Lock_policy)2> >&, std::_Sp_counted_ptr_inplace<Box_hdlr, std::allocator<Box_hdlr>, (__gnu_cxx::_Lock_policy)2>*, unsigned long) /usr/include/c++/7/bits/alloc_traits.h:462
    #3 0x7f7a88bf4553 in std::__allocated_ptr<std::allocator<std::_Sp_counted_ptr_inplace<Box_hdlr, std::allocator<Box_hdlr>, (__gnu_cxx::_Lock_policy)2> > >::~__allocated_ptr() /usr/include/c++/7/bits/allocated_ptr.h:73
    #4 0x7f7a88c1019d in std::_Sp_counted_ptr_inplace<Box_hdlr, std::allocator<Box_hdlr>, (__gnu_cxx::_Lock_policy)2>::_M_destroy() /usr/include/c++/7/bits/shared_ptr_base.h:543
    #5 0x7f7a88b94163 in std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release() /usr/include/c++/7/bits/shared_ptr_base.h:170
    #6 0x7f7a88b938c3 in std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count() /usr/include/c++/7/bits/shared_ptr_base.h:684
    #7 0x7f7a88bc23e3 in std::__shared_ptr<Box, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr() /usr/include/c++/7/bits/shared_ptr_base.h:1123
    #8 0x7f7a88bc24a3 in std::shared_ptr<Box>::~shared_ptr() /usr/include/c++/7/bits/shared_ptr.h:93
    #9 0x7f7a88be9854 in void std::_Destroy<std::shared_ptr<Box> >(std::shared_ptr<Box>*) /usr/include/c++/7/bits/stl_construct.h:98
    #10 0x7f7a88be4eb8 in void std::_Destroy_aux<false>::__destroy<std::shared_ptr<Box>*>(std::shared_ptr<Box>*, std::shared_ptr<Box>*) /usr/include/c++/7/bits/stl_construct.h:108
    #11 0x7f7a88bdafef in void std::_Destroy<std::shared_ptr<Box>*>(std::shared_ptr<Box>*, std::shared_ptr<Box>*) /usr/include/c++/7/bits/stl_construct.h:137
    #12 0x7f7a88bce3b8 in void std::_Destroy<std::shared_ptr<Box>*, std::shared_ptr<Box> >(std::shared_ptr<Box>*, std::shared_ptr<Box>*, std::allocator<std::shared_ptr<Box> >&) /usr/include/c++/7/bits/stl_construct.h:206
    #13 0x7f7a88bc3acf in std::vector<std::shared_ptr<Box>, std::allocator<std::shared_ptr<Box> > >::~vector() /usr/include/c++/7/bits/stl_vector.h:434
    #14 0x7f7a88bc02f8 in Box::~Box() (libheif/build/libheif/libheif.so.1+0xa22f8)
    #15 0x7f7a88bc053e in FullBox::~FullBox() (libheif/build/libheif/libheif.so.1+0xa253e)
    #16 0x7f7a88c09a8c in Box_meta::~Box_meta() (libheif/build/libheif/libheif.so.1+0xeba8c)
    #17 0x7f7a88c12579 in void __gnu_cxx::new_allocator<Box_meta>::destroy<Box_meta>(Box_meta*) /usr/include/c++/7/ext/new_allocator.h:140
    #18 0x7f7a88c111de in void std::allocator_traits<std::allocator<Box_meta> >::destroy<Box_meta>(std::allocator<Box_meta>&, Box_meta*) /usr/include/c++/7/bits/alloc_traits.h:487
    #19 0x7f7a88c10310 in std::_Sp_counted_ptr_inplace<Box_meta, std::allocator<Box_meta>, (__gnu_cxx::_Lock_policy)2>::_M_dispose() /usr/include/c++/7/bits/shared_ptr_base.h:535
    #20 0x7f7a88b940ec in std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release() /usr/include/c++/7/bits/shared_ptr_base.h:154
    #21 0x7f7a88b938c3 in std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count() /usr/include/c++/7/bits/shared_ptr_base.h:684
    #22 0x7f7a88bc23e3 in std::__shared_ptr<Box, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr() /usr/include/c++/7/bits/shared_ptr_base.h:1123
    #23 0x7f7a88bc24a3 in std::shared_ptr<Box>::~shared_ptr() /usr/include/c++/7/bits/shared_ptr.h:93
    #24 0x7f7a88b9d8b5 in Box::read(BitstreamRange&, std::shared_ptr<Box>*) libheif/libheif/box.cc:436
    #25 0x7f7a88b9edac in Box::read_children(BitstreamRange&, int) libheif/libheif/box.cc:749
    #26 0x7f7a88bab707 in Box_iprp::parse(BitstreamRange&) libheif/libheif/box.cc:1731
    #27 0x7f7a88b9d7eb in Box::read(BitstreamRange&, std::shared_ptr<Box>*) libheif/libheif/box.cc:672
    #28 0x7f7a88b9edac in Box::read_children(BitstreamRange&, int) libheif/libheif/box.cc:749
    #29 0x7f7a88ba14a0 in Box_meta::parse(BitstreamRange&) libheif/libheif/box.cc:920

previously allocated by thread T0 here:
    #0 0x7f7a88f6b258 in operator new(unsigned long) (/lib/x86_64-linux-gnu/libasan.so.4+0xe1258)
    #1 0x7f7a88c038a8 in __gnu_cxx::new_allocator<std::_Sp_counted_ptr_inplace<Box_hdlr, std::allocator<Box_hdlr>, (__gnu_cxx::_Lock_policy)2> >::allocate(unsigned long, void const*) /usr/include/c++/7/ext/new_allocator.h:111
    #2 0x7f7a88bfeeb4 in std::allocator_traits<std::allocator<std::_Sp_counted_ptr_inplace<Box_hdlr, std::allocator<Box_hdlr>, (__gnu_cxx::_Lock_policy)2> > >::allocate(std::allocator<std::_Sp_counted_ptr_inplace<Box_hdlr, std::allocator<Box_hdlr>, (__gnu_cxx::_Lock_policy)2> >&, unsigned long) /usr/include/c++/7/bits/alloc_traits.h:436
    #3 0x7f7a88bf44b9 in std::__allocated_ptr<std::allocator<std::_Sp_counted_ptr_inplace<Box_hdlr, std::allocator<Box_hdlr>, (__gnu_cxx::_Lock_policy)2> > > std::__allocate_guarded<std::allocator<std::_Sp_counted_ptr_inplace<Box_hdlr, std::allocator<Box_hdlr>, (__gnu_cxx::_Lock_policy)2> > >(std::allocator<std::_Sp_counted_ptr_inplace<Box_hdlr, std::allocator<Box_hdlr>, (__gnu_cxx::_Lock_policy)2> >&) /usr/include/c++/7/bits/allocated_ptr.h:104
    #4 0x7f7a88bea393 in std::__shared_count<(__gnu_cxx::_Lock_policy)2>::__shared_count<Box_hdlr, std::allocator<Box_hdlr>>(std::_Sp_make_shared_tag, Box_hdlr*, std::allocator<Box_hdlr> const&) /usr/include/c++/7/bits/shared_ptr_base.h:635
    #5 0x7f7a88be5955 in std::__shared_ptr<Box_hdlr, (__gnu_cxx::_Lock_policy)2>::__shared_ptr<std::allocator<Box_hdlr>>(std::_Sp_make_shared_tag, std::allocator<Box_hdlr> const&) /usr/include/c++/7/bits/shared_ptr_base.h:1295
    #6 0x7f7a88bdc441 in std::shared_ptr<Box_hdlr>::shared_ptr<std::allocator<Box_hdlr>>(std::_Sp_make_shared_tag, std::allocator<Box_hdlr> const&) /usr/include/c++/7/bits/shared_ptr.h:344
    #7 0x7f7a88bcf8a2 in std::shared_ptr<Box_hdlr> std::allocate_shared<Box_hdlr, std::allocator<Box_hdlr>>(std::allocator<Box_hdlr> const&) /usr/include/c++/7/bits/shared_ptr.h:691
    #8 0x7f7a88bc4768 in std::shared_ptr<Box_hdlr> std::make_shared<Box_hdlr>() /usr/include/c++/7/bits/shared_ptr.h:707
    #9 0x7f7a88b9bcf3 in Box::read(BitstreamRange&, std::shared_ptr<Box>*) libheif/libheif/box.cc:448
    #10 0x7f7a88b9edac in Box::read_children(BitstreamRange&, int) libheif/libheif/box.cc:749
    #11 0x7f7a88ba14a0 in Box_meta::parse(BitstreamRange&) libheif/libheif/box.cc:920
    #12 0x7f7a88b9d7eb in Box::read(BitstreamRange&, std::shared_ptr<Box>*) libheif/libheif/box.cc:672
    #13 0x7f7a88b9edac in Box::read_children(BitstreamRange&, int) libheif/libheif/box.cc:749
    #14 0x7f7a88bab707 in Box_iprp::parse(BitstreamRange&) libheif/libheif/box.cc:1731
    #15 0x7f7a88b9d7eb in Box::read(BitstreamRange&, std::shared_ptr<Box>*) libheif/libheif/box.cc:672
    #16 0x7f7a88b9edac in Box::read_children(BitstreamRange&, int) libheif/libheif/box.cc:749
    #17 0x7f7a88ba14a0 in Box_meta::parse(BitstreamRange&) libheif/libheif/box.cc:920
    #18 0x7f7a88b9d7eb in Box::read(BitstreamRange&, std::shared_ptr<Box>*) libheif/libheif/box.cc:672
    #19 0x7f7a88b9edac in Box::read_children(BitstreamRange&, int) libheif/libheif/box.cc:749
    #20 0x7f7a88ba14a0 in Box_meta::parse(BitstreamRange&) libheif/libheif/box.cc:920
    #21 0x7f7a88b9d7eb in Box::read(BitstreamRange&, std::shared_ptr<Box>*) libheif/libheif/box.cc:672
    #22 0x7f7a88c9217e in HeifFile::parse_heif_file(BitstreamRange&) libheif/libheif/file.cc:254
    #23 0x7f7a88c8ffc6 in HeifFile::read(std::shared_ptr<StreamReader> const&) libheif/libheif/file.cc:107
    #24 0x7f7a88c8f8c6 in HeifFile::read_from_file(char const*) libheif/libheif/file.cc:88
    #25 0x7f7a88c4b3d7 in HeifContext::read_from_file(char const*) libheif/libheif/context.cc:429
    #26 0x7f7a88c163ff in heif_context_read_from_file libheif/libheif/heif.cc:451
    #27 0x55fa40c33e68 in main libheif/examples/heif_convert.cc:410
    #28 0x7f7a88694082 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x24082)

SUMMARY: AddressSanitizer: heap-use-after-free libheif/libheif/uncompressed_image.cc:537 in UncompressedImageCodec::get_luma_bits_per_pixel_from_configuration_unci(HeifFile const&, unsigned int)
Shadow bytes around the buggy address:
  0x0c1c7fff80d0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c1c7fff80e0: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd
  0x0c1c7fff80f0: fd fd fd fd fd fd fd fd fd fd fd fd fa fa fa fa
  0x0c1c7fff8100: fa fa fa fa fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c1c7fff8110: fd fd fd fd fd fd fd fa fa fa fa fa fa fa fa fa
=>0x0c1c7fff8120: fd fd[fd]fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c1c7fff8130: fd fd fd fd fa fa fa fa fa fa fa fa fd fd fd fd
  0x0c1c7fff8140: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fa
  0x0c1c7fff8150: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd
  0x0c1c7fff8160: fd fd fd fd fd fd fd fd fd fd fd fd fa fa fa fa
  0x0c1c7fff8170: fa fa fa fa fd fd fd fd fd fd fd fd fd fd fd fd
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
==88148==ABORTING

POC

Environment

Description:	Ubuntu 22.04.2 LTS
gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0

Credit

Yuchuan Meng (Fudan University)

@carnil
Copy link

carnil commented Dec 7, 2023

This appears to be CVE-2023-49464

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants