diff --git a/lib/jpegli/decode.cc b/lib/jpegli/decode.cc index cd0feb9a..a0cb58b4 100644 --- a/lib/jpegli/decode.cc +++ b/lib/jpegli/decode.cc @@ -939,7 +939,8 @@ void jpegli_crop_scanline(j_decompress_ptr cinfo, JDIMENSION* xoffset, JPEGLI_ERROR("Output cropping is not supported in raw data mode"); } if (xoffset == nullptr || width == nullptr || *width == 0 || - *xoffset + *width > cinfo->output_width) { + *xoffset >= cinfo->output_width || + *width > cinfo->output_width - *xoffset) { JPEGLI_ERROR("jpegli_crop_scanline: Invalid arguments"); } // TODO(szabadka) Skip the IDCT for skipped over blocks. diff --git a/lib/jpegli/error_handling_test.cc b/lib/jpegli/error_handling_test.cc index fb39c939..bca8f68b 100644 --- a/lib/jpegli/error_handling_test.cc +++ b/lib/jpegli/error_handling_test.cc @@ -1140,6 +1140,25 @@ TEST(DecoderErrorHandlingTest, NoReadScanlines) { jpegli_destroy_decompress(&cinfo); } +TEST(DecoderErrorHandlingTest, CropScanlineArgumentOverflow) { + jpeg_decompress_struct cinfo = {}; + const auto try_catch_block = [&]() -> bool { + ERROR_HANDLER_SETUP(jpegli); + jpegli_create_decompress(&cinfo); + jpegli_mem_src(&cinfo, kCompressed0, kLen0); + jpegli_read_header(&cinfo, TRUE); + jpegli_start_decompress(&cinfo); + // xoffset + width wraps around JDIMENSION and lands below output_width, so + // an unguarded sum accepts this out-of-range crop window. + JDIMENSION xoffset = 0xffffffffu; + JDIMENSION width = 2; + jpegli_crop_scanline(&cinfo, &xoffset, &width); + return true; + }; + EXPECT_FALSE(try_catch_block()); + jpegli_destroy_decompress(&cinfo); +} + const size_t kMaxImageWidth = 0xffff; JSAMPLE kOutputBuffer[MAX_COMPONENTS * kMaxImageWidth];