libheif
libheif copied to clipboard
Invalid read of size 2 in Op_YCbCr420_to_RRGGBBaa::convert_colorspace
Hello,
I saw a fuzzer report regarding 2 byte read in Op_YCbCr420_to_RRGGBBaa::convert_colorspace
READ of size 2 at 0x52800000ff0e thread T0
#0 0x5ae3c9b5714e in Op_YCbCr420_to_RRGGBBaa::convert_colorspace(std::__1::shared_ptr<HeifPixelImage const> const&, ColorState const&, ColorState const&, heif_color_conversion_options const&, heif_color_conversion_options_ext const&, heif_security_limits const*) const libheif/libheif/color-conversion/yuv2rgb.cc:674:63
#1 0x5ae3c9b19b83 in ColorConversionPipeline::convert_image(std::__1::shared_ptr<HeifPixelImage> const&, heif_security_limits const*) libheif/libheif/color-conversion/colorconversion.cc:447:38
#2 0x5ae3c9b1c4a9 in convert_colorspace(std::__1::shared_ptr<HeifPixelImage> const&, heif_colorspace, heif_chroma, nclx_profile const&, int, heif_color_conversion_options const&, heif_color_conversion_options_ext const*, heif_security_limits const*) libheif/libheif/color-conversion/colorconversion.cc:623:21
#3 0x5ae3c9c8def1 in HeifContext::convert_to_output_colorspace(std::__1::shared_ptr<HeifPixelImage>, heif_colorspace, heif_chroma, heif_decoding_options const&) const libheif/libheif/context.cc:1388:12
#4 0x5ae3c9c8ca21 in HeifContext::decode_image(unsigned int, heif_colorspace, heif_chroma, heif_decoding_options const&, bool, unsigned int, unsigned int) const libheif/libheif/context.cc:1300:21
#5 0x5ae3c9a7f6ca in heif_decode_image libheif/libheif/api/libheif/heif_decoding.cc:236:81
#6 0x5ae3c9906a29 in HEIFHandler::ensureDecoder() /src/kimageformats/src/imageformats/heif.cpp:599:11
#7 0x5ae3c98fef73 in HEIFHandler::ensureParsed() const /src/kimageformats/src/imageformats/heif.cpp:503:26
#8 0x5ae3c98fef73 in HEIFHandler::read(QImage*) /src/kimageformats/src/imageformats/heif.cpp:111:10
#9 0x5ae3c98fd691 in LLVMFuzzerTestOneInput /src/kimgio_fuzzer.cc:69:14
#10 0x5ae3cd4bd5e9 in ExecuteFilesOnyByOne /src/aflplusplus/utils/aflpp_driver/aflpp_driver.c:255:7
#11 0x5ae3cd4bd3e5 in LLVMFuzzerRunDriver /src/aflplusplus/utils/aflpp_driver/aflpp_driver.c:0
#12 0x5ae3cd4bcf9d in main /src/aflplusplus/utils/aflpp_driver/aflpp_driver.c:311:10
#13 0x7ba68bf5e082 in __libc_start_main /build/glibc-LcI20x/glibc-2.31/csu/libc-start.c:308:16
#14 0x5ae3c9824d5d in _start
valgrind --leak-check=yes --track-origins=yes heif-dec clusterfuzz-testcase-minimized-kimgio_heif_fuzzer-5427590325403648 outut.png
shows following:
==23030== Memcheck, a memory error detector
==23030== Copyright (C) 2002-2024, and GNU GPL'd, by Julian Seward et al.
==23030== Using Valgrind-3.27.0.GIT and LibVEX; rerun with -h for copyright info
==23030== Command: heif-dec clusterfuzz-testcase-minimized-kimgio_heif_fuzzer-5427590325403648 outut.png
==23030==
==23030== Invalid read of size 1
==23030== at 0x4961CF8: Op_YCbCr420_to_RRGGBBaa::convert_colorspace(std::shared_ptr<HeifPixelImage const> const&, ColorState const&, ColorState const&, heif_color_conversion_options const&, heif_color_conversion_options_ext const&, heif_security_limits const*) const (yuv2rgb.cc:674)
==23030== by 0x4950BCD: ColorConversionPipeline::convert_image(std::shared_ptr<HeifPixelImage> const&, heif_security_limits const*) (colorconversion.cc:447)
==23030== by 0x49521FF: convert_colorspace(std::shared_ptr<HeifPixelImage> const&, heif_colorspace, heif_chroma, nclx_profile const&, int, heif_color_conversion_options const&, heif_color_conversion_options_ext const*, heif_security_limits const*) (colorconversion.cc:623)
==23030== by 0x48E4777: HeifContext::convert_to_output_colorspace(std::shared_ptr<HeifPixelImage>, heif_colorspace, heif_chroma, heif_decoding_options const&) const (context.cc:1390)
==23030== by 0x48E64B5: HeifContext::decode_image(unsigned int, heif_colorspace, heif_chroma, heif_decoding_options const&, bool, unsigned int, unsigned int) const (context.cc:1300)
==23030== by 0x491F10F: heif_decode_image (heif_decoding.cc:240)
==23030== by 0x4005C3E: decode_single_image(heif_image_handle*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, heif_decoding_options*, std::unique_ptr<Encoder, std::default_delete<Encoder> >&) (heif_dec.cc:241)
==23030== by 0x400831B: main (heif_dec.cc:1026)
==23030== Address 0x6989a5f is 0 bytes after a block of size 15,887 alloc'd
==23030== at 0x485B308: operator new[](unsigned long, std::nothrow_t const&) (vg_replace_malloc.c:851)
==23030== by 0x48FC2F8: HeifPixelImage::ImagePlane::alloc(unsigned int, unsigned int, heif_channel_datatype, int, int, heif_security_limits const*, MemoryHandle&) (pixelimage.cc:438)
==23030== by 0x48FDD72: HeifPixelImage::add_plane(heif_channel, unsigned int, unsigned int, int, heif_security_limits const*) (pixelimage.cc:355)
==23030== by 0x4966CBA: Op_mono_to_YCbCr420::convert_colorspace(std::shared_ptr<HeifPixelImage const> const&, ColorState const&, ColorState const&, heif_color_conversion_options const&, heif_color_conversion_options_ext const&, heif_security_limits const*) const (monochrome.cc:83)
==23030== by 0x4950BCD: ColorConversionPipeline::convert_image(std::shared_ptr<HeifPixelImage> const&, heif_security_limits const*) (colorconversion.cc:447)
==23030== by 0x49521FF: convert_colorspace(std::shared_ptr<HeifPixelImage> const&, heif_colorspace, heif_chroma, nclx_profile const&, int, heif_color_conversion_options const&, heif_color_conversion_options_ext const*, heif_security_limits const*) (colorconversion.cc:623)
==23030== by 0x48E4777: HeifContext::convert_to_output_colorspace(std::shared_ptr<HeifPixelImage>, heif_colorspace, heif_chroma, heif_decoding_options const&) const (context.cc:1390)
==23030== by 0x48E64B5: HeifContext::decode_image(unsigned int, heif_colorspace, heif_chroma, heif_decoding_options const&, bool, unsigned int, unsigned int) const (context.cc:1300)
==23030== by 0x491F10F: heif_decode_image (heif_decoding.cc:240)
==23030== by 0x4005C3E: decode_single_image(heif_image_handle*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, heif_decoding_options*, std::unique_ptr<Encoder, std::default_delete<Encoder> >&) (heif_dec.cc:241)
==23030== by 0x400831B: main (heif_dec.cc:1026)
==23030==
==23030== Invalid read of size 2
==23030== at 0x4961D2D: Op_YCbCr420_to_RRGGBBaa::convert_colorspace(std::shared_ptr<HeifPixelImage const> const&, ColorState const&, ColorState const&, heif_color_conversion_options const&, heif_color_conversion_options_ext const&, heif_security_limits const*) const (yuv2rgb.cc:675)
==23030== by 0x4950BCD: ColorConversionPipeline::convert_image(std::shared_ptr<HeifPixelImage> const&, heif_security_limits const*) (colorconversion.cc:447)
==23030== by 0x49521FF: convert_colorspace(std::shared_ptr<HeifPixelImage> const&, heif_colorspace, heif_chroma, nclx_profile const&, int, heif_color_conversion_options const&, heif_color_conversion_options_ext const*, heif_security_limits const*) (colorconversion.cc:623)
==23030== by 0x48E4777: HeifContext::convert_to_output_colorspace(std::shared_ptr<HeifPixelImage>, heif_colorspace, heif_chroma, heif_decoding_options const&) const (context.cc:1390)
==23030== by 0x48E64B5: HeifContext::decode_image(unsigned int, heif_colorspace, heif_chroma, heif_decoding_options const&, bool, unsigned int, unsigned int) const (context.cc:1300)
==23030== by 0x491F10F: heif_decode_image (heif_decoding.cc:240)
==23030== by 0x4005C3E: decode_single_image(heif_image_handle*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, heif_decoding_options*, std::unique_ptr<Encoder, std::default_delete<Encoder> >&) (heif_dec.cc:241)
==23030== by 0x400831B: main (heif_dec.cc:1026)
==23030== Address 0x6989a5e is 15,886 bytes inside a block of size 15,887 alloc'd
==23030== at 0x485B308: operator new[](unsigned long, std::nothrow_t const&) (vg_replace_malloc.c:851)
==23030== by 0x48FC2F8: HeifPixelImage::ImagePlane::alloc(unsigned int, unsigned int, heif_channel_datatype, int, int, heif_security_limits const*, MemoryHandle&) (pixelimage.cc:438)
==23030== by 0x48FDD72: HeifPixelImage::add_plane(heif_channel, unsigned int, unsigned int, int, heif_security_limits const*) (pixelimage.cc:355)
==23030== by 0x4966CBA: Op_mono_to_YCbCr420::convert_colorspace(std::shared_ptr<HeifPixelImage const> const&, ColorState const&, ColorState const&, heif_color_conversion_options const&, heif_color_conversion_options_ext const&, heif_security_limits const*) const (monochrome.cc:83)
==23030== by 0x4950BCD: ColorConversionPipeline::convert_image(std::shared_ptr<HeifPixelImage> const&, heif_security_limits const*) (colorconversion.cc:447)
==23030== by 0x49521FF: convert_colorspace(std::shared_ptr<HeifPixelImage> const&, heif_colorspace, heif_chroma, nclx_profile const&, int, heif_color_conversion_options const&, heif_color_conversion_options_ext const*, heif_security_limits const*) (colorconversion.cc:623)
==23030== by 0x48E4777: HeifContext::convert_to_output_colorspace(std::shared_ptr<HeifPixelImage>, heif_colorspace, heif_chroma, heif_decoding_options const&) const (context.cc:1390)
==23030== by 0x48E64B5: HeifContext::decode_image(unsigned int, heif_colorspace, heif_chroma, heif_decoding_options const&, bool, unsigned int, unsigned int) const (context.cc:1300)
==23030== by 0x491F10F: heif_decode_image (heif_decoding.cc:240)
==23030== by 0x4005C3E: decode_single_image(heif_image_handle*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, heif_decoding_options*, std::unique_ptr<Encoder, std::default_delete<Encoder> >&) (heif_dec.cc:241)
==23030== by 0x400831B: main (heif_dec.cc:1026)
Please take a look when you have time.
Thank you. The image is 16 bit, but has an alpha plane with only 8 bits. The color-conversion expects both to be similar. I've added an error check for this case. Eventually, the color-conversion should convert the alpha bpp to match the main image. This is left for the future (if this case will ever happen in actual use).