CVE-2026-87497
Overview
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifthird_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.cc |
modified | |
forthird_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.cc |
modified | |
TESTthird_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder_test.cc |
modified |
Files Changed
third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.ccthird_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder_test.ccthird_party/blink/web_tests/flag-specific/skia-vulkan-swiftshader/images/12-55-expected.pngthird_party/blink/web_tests/flag-specific/skia-vulkan-swiftshader/images/23-55-expected.pngthird_party/blink/web_tests/platform/linux/images/12-55-expected.pngthird_party/blink/web_tests/platform/linux/images/182-expected.pngthird_party/blink/web_tests/platform/linux/images/23-55-expected.pngthird_party/blink/web_tests/platform/linux/virtual/exotic-color-space/images/12-55-expected.png
Patch
From 154727b1485f72b4a02bcb9b02c1ffd004170b2e Mon Sep 17 00:00:00 2001 From: Florin Malita <[email protected]> Date: Wed, 29 Jul 2026 08:41:42 -0700 Subject: [PATCH] Reland "Fix premature output of non-interleaved multi-scan JPEGs" This reverts commit a4ddaf23c2cbb85af1b09a8c0435265d68129c34. Reason for revert: reland with additional rebaselines Original change's description: > Revert "Fix premature output of non-interleaved multi-scan JPEGs" > > This reverts commit 191dfbeb4fd602cd0ee1dcbc9f401268675e3892. > > Reason for revert: Causing failures on Mac15 and Win11 bots. > > Failure Link: https://ci.chromium.org/ui/p/chromium/builders/ci/win11-arm64-rel-tests/8088/overview > https://ci.chromium.org/p/chromium/builders/ci/mac15-x64-rel-tests/b8675028340104321601 > > Original change's description: > > Fix premature output of non-interleaved multi-scan JPEGs > > > > In spite of its name, the kJpegDecompressProgressive code path handles > > both progressive and non-progressive multi-scan (non-interleaved > > sequential or lossless) JPEGs. Technically it corresponds to enabling > > buffered-image mode. > > > > Previously, all_components_seen() checked if info.coef_bits was > > non-null, which covers the progressive case. > > > > For non-progressive files, info.coef_bits is null. Because of this, > > all_components_seen() returned true on the very first scan before > > subsequent component scans were received. This triggered premature calls > > to jpeg_start_output() and output of uninitialized memory buffers for > > the unparsed components. > > > > Resolve this by checking jpeg_input_complete() for the non-progressive > > case. This safely postpones output generation until the entire input has > > been parsed and all component scans are complete. > > > > Add a unit test nonInterleavedSequentialBufferedDecompress to verify > > that sequential, non-interleaved JPEGs are not progressively decoded > > while input is incomplete. > > > > Rename kJpegDecompressProgressive -> kJpegDecompressBufferedImage to > > better reflect its semantics. > > > > Bug: 504670493 > > Test: blink_platform_unittests --gtest_filter=JPEGImageDecoderTest.* > > Change-Id: I32a44452c2b74d259a3957176eb64f95159287fe > > Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8141869 > > Commit-Queue: Florin Malita <[email protected]> > > Reviewed-by: Wan-Teh Chang <[email protected]> > > Cr-Commit-Position: refs/heads/main@{#1669371} > > Bug: 504670493, 539967091 > Bug: 504670493 > Change-Id: I5fa309dd6f2b827eb359db19dd9288a2be71418c > Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8161825 > Reviewed-by: Wan-Teh Chang <[email protected]> > Auto-Submit: Dibyajyoti Pal <[email protected]> > Reviewed-by: Florin Malita <[email protected]> > Commit-Queue: Florin Malita <[email protected]> > Bot-Commit: [email protected] <[email protected]> > Owners-Override: Dibyajyoti Pal <[email protected]> > Commit-Queue: Dibyajyoti Pal <[email protected]> > Cr-Commit-Position: refs/heads/main@{#1669683} Bug: 504670493, 539967091 Bug: 504670493 Change-Id: I1122e1404f84ef80d57d0a90c7dc011060405a2c Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8165123 Reviewed-by: Wan-Teh Chang <[email protected]> Commit-Queue: Florin Malita <[email protected]> Cr-Commit-Position: refs/heads/main@{#1670283} --- diff --git a/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.cc b/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.cc index 4d4b446a6..da1a69a4 100644 --- a/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.cc +++ b/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.cc @@ -168,8 +168,8 @@ enum jstate { kJpegHeader, // Reading JFIF headers kJpegStartDecompress, - kJpegDecompressProgressive, // Output progressive pixels - kJpegDecompressSequential, // Output sequential pixels + kJpegDecompressBufferedImage, // Output pixels in buffered-image mode. + kJpegDecompressSequential, // Output pixels in sequential mode. kJpegDone }; @@ -570,8 +570,8 @@ return false; // I/O suspension. } - // If this is a progressive JPEG ... - state_ = (info_.buffered_image) ? kJpegDecompressProgressive + // If this is a JPEG requiring buffered-image mode. + state_ = (info_.buffered_image) ? kJpegDecompressBufferedImage : kJpegDecompressSequential; [[fallthrough]]; @@ -587,9 +587,9 @@ } [[fallthrough]]; - case kJpegDecompressProgressive: - if (state_ == kJpegDecompressProgressive) { - auto all_components_seen = [](const jpeg_decompress_struct& info) { + case kJpegDecompressBufferedImage: + if (state_ == kJpegDecompressBufferedImage) { + auto all_components_seen = [](jpeg_decompress_struct& info) -> bool { if (info.coef_bits) { for (int c = 0; c < info.num_components; ++c) { if (UNSAFE_TODO(info.coef_bits[c])[0] == -1) { @@ -597,8 +597,12 @@ return false; } } + return true; } - return true; + // For non-progressive (e.g. non-interleaved sequential or lossless) + // images coef_bits is always null, and all components are only seen + // when the input is complete. + return jpeg_input_complete(&info); }; int status = 0; int first_scan_to_display = diff --git a/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder_test.cc b/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder_test.cc index a9966f7..adab7cfc 100644 --- a/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder_test.cc +++ b/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder_test.cc @@ -259,6 +259,35 @@ EXPECT_TRUE(test_decoder->Failed()); } +// This tests decoding a multi-scan non-interleaved sequential JPEG. +// Decoding should fail with incomplete data. +TEST(JPEGImageDecoderTest, nonInterleavedSequentialBufferedDecompress) { + Vector<char> test_data = + ReadFile("/images/jpeg-suite/baseline/32x32x8_ycbcr.jpg"); + ASSERT_FALSE(test_data.empty()); + + const size_t partial_size = test_data.size() / 2; + scoped_refptr<SharedBuffer> partial_buffer = SharedBuffer::Create(); + partial_buffer->Append(base::span<const char>(test_data).first(partial_size)); + + std::unique_ptr<ImageDecoder> test_decoder = CreateJPEGDecoder(); + test_decoder->SetData(partial_buffer, false); + + ImageFrame* frame = test_decoder->DecodeFrameBufferAtIndex(0); + ASSERT_TRUE(frame); + EXPECT_NE(frame->GetStatus(), ImageFrame::kFramePartial); + EXPECT_NE(frame->GetStatus(), ImageFrame::kFrameComplete); + EXPECT_FALSE(test_decoder->Failed()); + + scoped_refptr<SharedBuffer> full_buffer = SharedBuffer::Create(); + full_buffer->Append(base::span<const char>(test_data)); + test_decoder->SetData(full_buffer, true); + + frame = test_decoder->DecodeFrameBufferAtIndex(0); + ASSERT_TRUE(frame); + EXPECT_EQ(frame->GetStatus(), ImageFrame::kFrameComplete); +} + // Decode a JPEG with EXIF data that defines a density corrected size. The EXIF // data has the initial IFD at the end of the data blob, and out-of-line data // defined just after the header. diff --git a/third_party/blink/web_tests/flag-specific/skia-vulkan-swiftshader/images/12-55-expected.png b/third_party/blink/web_tests/flag-specific/skia-vulkan-swiftshader/images/12-55-expected.png index 253052e5..1b02678a 100644 --- a/third_party/blink/web_tests/flag-specific/skia-vulkan-swiftshader/images/12-55-expected.png +++ b/third_party/blink/web_tests/flag-specific/skia-vulkan-swiftshader/images/12-55-expected.png Binary files differ diff --git a/third_party/blink/web_tests/flag-specific/skia-vulkan-swiftshader/images/23-55-expected.png b/third_party/blink/web_tests/flag-specific/skia-vulkan-swiftshader/images/23-55-expected.png index 335d4394..1b02678a 100644 --- a/third_party/blink/web_tests/flag-specific/skia-vulkan-swiftshader/images/23-55-expected.png +++ b/third_party/blink/web_tests/flag-specific/skia-vulkan-swiftshader/images/23-55-expected.png Binary files differ diff --git a/third_party/blink/web_tests/platform/linux/images/12-55-expected.png b/third_party/blink/web_tests/platform/linux/images/12-55-expected.png index dbefbc5..5671bec 100644 --- a/third_party/blink/web_tests/platform/linux/images/12-55-expected.png +++ b/third_party/blink/web_tests/platform/linux/images/12-55-expected.png Binary files differ diff --git a/third_party/blink/web_tests/platform/linux/images/182-expected.png b/third_party/blink/web_tests/platform/linux/images/182-expected.png index 9341f9a60..5671bec 100644 --- a/third_party/blink/web_tests/platform/linux/images/182-expected.png +++ b/third_party/blink/web_tests/platform/linux/images/182-expected.png Binary files differ diff --git a/third_party/blink/web_tests/platform/linux/images/23-55-expected.png b/third_party/blink/web_tests/platform/linux/images/23-55-expected.png index 941256dc..5671bec 100644 --- a/third_party/blink/web_tests/platform/linux/images/23-55-expected.png +++ b/third_party/blink/web_tests/platform/linux/images/23-55-expected.png Binary files differ diff --git a/third_party/blink/web_tests/platform/linux/virtual/exotic-color-space/images/12-55-expected.png b/third_party/blink/web_tests/platform/linux/virtual/exotic-color-space/images/12-55-expected.png index 3a6bc1e..0be40aa 100644 --- a/third_party/blink/web_tests/platform/linux/virtual/exotic-color-space/images/12-55-expected.png +++ b/third_party/blink/web_tests/platform/linux/virtual/exotic-color-space/images/12-55-expected.png Binary files differ
Regression Test / PoC
diff --git a/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder_test.cc b/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder_test.cc
index a9966f7..adab7cfc 100644
--- a/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder_test.cc
+++ b/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder_test.cc
@@ -259,6 +259,35 @@
EXPECT_TRUE(test_decoder->Failed());
}
+// This tests decoding a multi-scan non-interleaved sequential JPEG.
+// Decoding should fail with incomplete data.
+TEST(JPEGImageDecoderTest, nonInterleavedSequentialBufferedDecompress) {
+ Vector<char> test_data =
+ ReadFile("/images/jpeg-suite/baseline/32x32x8_ycbcr.jpg");
+ ASSERT_FALSE(test_data.empty());
+
+ const size_t partial_size = test_data.size() / 2;
+ scoped_refptr<SharedBuffer> partial_buffer = SharedBuffer::Create();
+ partial_buffer->Append(base::span<const char>(test_data).first(partial_size));
+
+ std::unique_ptr<ImageDecoder> test_decoder = CreateJPEGDecoder();
+ test_decoder->SetData(partial_buffer, false);
+
+ ImageFrame* frame = test_decoder->DecodeFrameBufferAtIndex(0);
+ ASSERT_TRUE(frame);
+ EXPECT_NE(frame->GetStatus(), ImageFrame::kFramePartial);
+ EXPECT_NE(frame->GetStatus(), ImageFrame::kFrameComplete);
+ EXPECT_FALSE(test_decoder->Failed());
+
+ scoped_refptr<SharedBuffer> full_buffer = SharedBuffer::Create();
+ full_buffer->Append(base::span<const char>(test_data));
+ test_decoder->SetData(full_buffer, true);
+
+ frame = test_decoder->DecodeFrameBufferAtIndex(0);
+ ASSERT_TRUE(frame);
+ EXPECT_EQ(frame->GetStatus(), ImageFrame::kFrameComplete);
+}
+
// Decode a JPEG with EXIF data that defines a density corrected size. The EXIF
// data has the initial IFD at the end of the data blob, and out-of-line data
// defined just after the header.
diff --git a/third_party/blink/web_tests/flag-specific/skia-vulkan-swiftshader/images/12-55-expected.png b/third_party/blink/web_tests/flag-specific/skia-vulkan-swiftshader/images/12-55-expected.png
index 253052e5..1b02678a 100644
--- a/third_party/blink/web_tests/flag-specific/skia-vulkan-swiftshader/images/12-55-expected.png
+++ b/third_party/blink/web_tests/flag-specific/skia-vulkan-swiftshader/images/12-55-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/skia-vulkan-swiftshader/images/23-55-expected.png b/third_party/blink/web_tests/flag-specific/skia-vulkan-swiftshader/images/23-55-expected.png
index 335d4394..1b02678a 100644
--- a/third_party/blink/web_tests/flag-specific/skia-vulkan-swiftshader/images/23-55-expected.png
+++ b/third_party/blink/web_tests/flag-specific/skia-vulkan-swiftshader/images/23-55-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/images/12-55-expected.png b/third_party/blink/web_tests/platform/linux/images/12-55-expected.png
index dbefbc5..5671bec 100644
--- a/third_party/blink/web_tests/platform/linux/images/12-55-expected.png
+++ b/third_party/blink/web_tests/platform/linux/images/12-55-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/images/182-expected.png b/third_party/blink/web_tests/platform/linux/images/182-expected.png
index 9341f9a60..5671bec 100644
--- a/third_party/blink/web_tests/platform/linux/images/182-expected.png
+++ b/third_party/blink/web_tests/platform/linux/images/182-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/images/23-55-expected.png b/third_party/blink/web_tests/platform/linux/images/23-55-expected.png
index 941256dc..5671bec 100644
--- a/third_party/blink/web_tests/platform/linux/images/23-55-expected.png
+++ b/third_party/blink/web_tests/platform/linux/images/23-55-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/exotic-color-space/images/12-55-expected.png b/third_party/blink/web_tests/platform/linux/virtual/exotic-color-space/images/12-55-expected.png
index 3a6bc1e..0be40aa 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/exotic-color-space/images/12-55-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/exotic-color-space/images/12-55-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/exotic-color-space/images/182-expected.png b/third_party/blink/web_tests/platform/linux/virtual/exotic-color-space/images/182-expected.png
index cc6a061..0be40aa 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/exotic-color-space/images/182-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/exotic-color-space/images/182-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/exotic-color-space/images/23-55-expected.png b/third_party/blink/web_tests/platform/linux/virtual/exotic-color-space/images/23-55-expected.png
index b54ebe5..0be40aa 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/exotic-color-space/images/23-55-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/exotic-color-space/images/23-55-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/23-55-expected.png b/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/23-55-expected.png
index 335d4394..1b02678a 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/23-55-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/23-55-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac13-arm64/virtual/exotic-color-space/images/12-55-expected.png b/third_party/blink/web_tests/platform/mac-mac13-arm64/virtual/exotic-color-space/images/12-55-expected.png
deleted file mode 100644
index 2e05869c..0000000
--- a/third_party/blink/web_tests/platform/mac-mac13-arm64/virtual/exotic-color-space/images/12-55-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac13-arm64/virtual/exotic-color-space/images/182-expected.png b/third_party/blink/web_tests/platform/mac-mac13-arm64/virtual/exotic-color-space/images/182-expected.png
deleted file mode 100644
index 82ab4ee5..0000000
--- a/third_party/blink/web_tests/platform/mac-mac13-arm64/virtual/exotic-color-space/images/182-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac13-arm64/virtual/exotic-color-space/images/23-55-expected.png b/third_party/blink/web_tests/platform/mac-mac13-arm64/virtual/exotic-color-space/images/23-55-expected.png
deleted file mode 100644
index 91d3852..0000000
--- a/third_party/blink/web_tests/platform/mac-mac13-arm64/virtual/exotic-color-space/images/23-55-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac26-arm64/virtual/exotic-color-space/images/12-55-expected.png b/third_party/blink/web_tests/platform/mac-mac26-arm64/virtual/exotic-color-space/images/12-55-expected.png
index bbb54c3..9738f19 100644
--- a/third_party/blink/web_tests/platform/mac-mac26-arm64/virtual/exotic-color-space/images/12-55-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac26-arm64/virtual/exotic-color-space/images/12-55-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac26-arm64/virtual/exotic-color-space/images/182-expected.png b/third_party/blink/web_tests/platform/mac-mac26-arm64/virtual/exotic-color-space/images/182-expected.png
index 8aa0b49..9738f19 100644
--- a/third_party/blink/web_tests/platform/mac-mac26-arm64/virtual/exotic-color-space/images/182-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac26-arm64/virtual/exotic-color-space/images/182-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac26-arm64/virtual/exotic-color-space/images/23-55-expected.png b/third_party/blink/web_tests/platform/mac-mac26-arm64/virtual/exotic-color-space/images/23-55-expected.png
index 8cdcd02..9738f19 100644
--- a/third_party/blink/web_tests/platform/mac-mac26-arm64/virtual/exotic-color-space/images/23-55-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac26-arm64/virtual/exotic-color-space/images/23-55-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/images/12-55-expected.png b/third_party/blink/web_tests/platform/mac/images/12-55-expected.png
index ec38fe3f..7ed9d78bc 100644
--- a/third_party/blink/web_tests/platform/mac/images/12-55-expected.png
+++ b/third_party/blink/web_tests/platform/mac/images/12-55-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/images/182-expected.png b/third_party/blink/web_tests/platform/mac/images/182-expected.png
index 3609f33..7ed9d78bc 100644
--- a/third_party/blink/web_tests/platform/mac/images/182-expected.png
+++ b/third_party/blink/web_tests/platform/mac/images/182-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/images/23-55-expected.png b/third_party/blink/web_tests/platform/mac/images/23-55-expected.png
index f687a17..7ed9d78bc 100644
--- a/third_party/blink/web_tests/platform/mac/images/23-55-expected.png
+++ b/third_party/blink/web_tests/platform/mac/images/23-55-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/exotic-color-space/images/12-55-expected.png b/third_party/blink/web_tests/platform/mac/virtual/exotic-color-space/images/12-55-expected.png
index b3527d2..2d590a86 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/exotic-color-space/images/12-55-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/exotic-color-space/images/12-55-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/exotic-color-space/images/182-expected.png b/third_party/blink/web_tests/platform/mac/virtual/exotic-color-space/images/182-expected.png
index 95ab680..2d590a86 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/exotic-color-space/images/182-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/exotic-color-space/images/182-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/exotic-color-space/images/23-55-expected.png b/third_party/blink/web_tests/platform/mac/virtual/exotic-color-space/images/23-55-expected.png
index 8113274..2d590a86 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/exotic-color-space/images/23-55-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/exotic-color-space/images/23-55-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/images/12-55-expected.png b/third_party/blink/web_tests/platform/win/images/12-55-expected.png
index 3261260..3588010e 100644
--- a/third_party/blink/web_tests/platform/win/images/12-55-expected.png
+++ b/third_party/blink/web_tests/platform/win/images/12-55-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/images/182-expected.png b/third_party/blink/web_tests/platform/win/images/182-expected.png
index eca92b1..3588010e 100644
--- a/third_party/blink/web_tests/platform/win/images/182-expected.png
+++ b/third_party/blink/web_tests/platform/win/images/182-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/images/23-55-expected.png b/third_party/blink/web_tests/platform/win/images/23-55-expected.png
index 32fc3fc..3588010e 100644
--- a/third_party/blink/web_tests/platform/win/images/23-55-expected.png
+++ b/third_party/blink/web_tests/platform/win/images/23-55-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/exotic-color-space/images/12-55-expected.png b/third_party/blink/web_tests/platform/win/virtual/exotic-color-space/images/12-55-expected.png
index 4c599f97..b035de6 100644
--- a/third_party/blink/web_tests/platform/win/virtual/exotic-color-space/images/12-55-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/exotic-color-space/images/12-55-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/exotic-color-space/images/182-expected.png b/third_party/blink/web_tests/platform/win/virtual/exotic-color-space/images/182-expected.png
index 3ab08e4..b035de6 100644
--- a/third_party/blink/web_tests/platform/win/virtual/exotic-color-space/images/182-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/exotic-color-space/images/182-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/exotic-color-space/images/23-55-expected.png b/third_party/blink/web_tests/platform/win/virtual/exotic-color-space/images/23-55-expected.png
index 2f970193..b035de6 100644
--- a/third_party/blink/web_tests/platform/win/virtual/exotic-color-space/images/23-55-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/exotic-color-space/images/23-55-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/182-expected.png b/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/182-expected.png
index b504399..389fb49 100644
--- a/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/182-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/182-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/23-55-expected.png b/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/23-55-expected.png
index 329d9f12..389fb49 100644
--- a/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/23-55-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/23-55-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win11-arm64/virtual/exotic-color-space/images/12-55-expected.png b/third_party/blink/web_tests/platform/win11-arm64/virtual/exotic-color-space/images/12-55-expected.png
index 6e3fed2..53edfcd 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/virtual/exotic-color-space/images/12-55-expected.png
+++ b/third_party/blink/web_tests/platform/win11-arm64/virtual/exotic-color-space/images/12-55-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win11-arm64/virtual/exotic-color-space/images/182-expected.png b/third_party/blink/web_tests/platform/win11-arm64/virtual/exotic-color-space/images/182-expected.png
index 4bb6cc7..53edfcd 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/virtual/exotic-color-space/images/182-expected.png
+++ b/third_party/blink/web_tests/platform/win11-arm64/virtual/exotic-color-space/images/182-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win11-arm64/virtual/exotic-color-space/images/23-55-expected.png b/third_party/blink/web_tests/platform/win11-arm64/virtual/exotic-color-space/images/23-55-expected.png
index ec7653d..53edfcd 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/virtual/exotic-color-space/images/23-55-expected.png
+++ b/third_party/blink/web_tests/platform/win11-arm64/virtual/exotic-color-space/images/23-55-expected.png
Binary files differ
Original Bug Report
Uninitialized heap disclosure in libjpeg-turbo via progressive display
Project Fortify, an experimental security project, has identified the following potential security issue. If you’re a feature owner CC-ed on this bug, please do your best to review these reports without the Chrome Security team. Please see https://chromium.googlesource.com/chromium/src/+/main/docs/security/ai-generated-security-bugs-faq.md for more information.
Overview: A potential uninitialized heap disclosure exists in libjpeg-turbo’s lossless decoder when combined with Blink’s progressive image decoding. A premature watermark advancement in libjpeg-turbo’s memory manager, coupled with a flaw in Blink’s JPEGImageDecoder::all_components_seen(), allows an attacker to leak uninitialized PartitionAlloc heap memory to a canvas. This can be used as an ASLR-defeat primitive.
Affected files:
third_party/libjpeg_turbo/src/jddiffct.cthird_party/libjpeg_turbo/src/jmemmgr.cthird_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.ccthird_party/libjpeg_turbo/src/jdlhuff.cthird_party/libjpeg_turbo/src/jdcolor.c
Estimated timestamp from git blame: 2025-08-07
Summary
A potential uninitialized heap disclosure vulnerability exists in the libjpeg-turbo lossless decoder (used for SOF3 JPEGs) when combined with Blink’s progressive image decoding. A Time-of-Check Time-of-Use (TOCTOU) flaw in libjpeg-turbo’s memory management, combined with incomplete state tracking in Blink’s JPEGImageDecoder, allows an attacker to read renderer process PartitionAlloc heap memory via a <canvas> element.
Technical Details
The vulnerability arises from the interaction between libjpeg-turbo’s virtual array management and Blink’s progressive display logic:
- Premature Watermark Advancement: In
jddiffct.c, the lossless difference controller allocates virtual sample arrays withpre_zero=FALSE. When processing a scan,consume_data()callsaccess_virt_sarraywithwritable=TRUE. Insidejmemmgr.c:987, the memory manager immediately advances thefirst_undef_rowwatermark before any data is written to the buffer. - Suspension: If the input stream is truncated or stalls mid-row,
decompress_data()returnsJPEG_SUSPENDED. The current row is left completely unwritten, but is incorrectly marked as ‘defined’ by the memory manager because the watermark was already advanced. - Progressive Display Bypass: Back in Blink,
JPEGImageDecoder::Decodechecks if the partial image can be displayed progressively using theall_components_seenlambda (jpeg_image_decoder.cc:592). This lambda checksinfo.coef_bits. Because lossless JPEGs do not use DCT,coef_bitsis NULL. The lambda immediately returnstrue, causing Blink to bypass the check and force output of the incomplete scan viajpeg_start_output. - Uninitialized Read: During output generation,
output_data()(jddiffct.c:315) callsaccess_virt_sarraywithwritable=FALSEto read the stalled row. Because thefirst_undef_rowwatermark was advanced in Step 1, the memory manager does not throw aJERR_BAD_VIRTUAL_ACCESSerror. - Leak to Canvas:
output_datacopies the uninitialized PartitionAlloc heap memory into the output buffer. Blink’sOutputScanlinesthen writes this data into theImageFrame. An attacker can subsequently draw the partially decoded image to a canvas and usegetImageData()to read the leaked heap data.
Potential Attacker Steps to Trigger
Note: These are suggested steps based on code analysis; a working Proof of Concept has not been run.
- Serve a crafted, multi-scan 3-component SOF3 (lossless) JPEG.
- Provide full entropy for the first two scans.
- For the third scan, provide valid entropy for the first
Rrows, then artificially stall the TCP connection mid-way through rowR+1. - In the victim’s browser, load the image and draw it to a
<canvas>usingctx.drawImage(). - Call
ctx.getImageData()and inspect the color channels corresponding to the stalled scan of rowR+1. The resulting bytes will contain uninitialized heap memory.
Suggested Fix
- Blink: Fix the logic in
all_components_seen(jpeg_image_decoder.cc:592) so that it accurately tracks component availability for lossless JPEGs, rather than defaulting totruewheninfo.coef_bitsis NULL. - libjpeg-turbo: Either initialize the virtual arrays by setting
pre_zero=TRUEwhen allocating them injddiffct.c:392, or delay advancingfirst_undef_rowinjmemmgr.cuntil the caller signals that the write has actually completed.
Evaluated with Chrome root at commit: 7353d249d9cacf9c7218e1d7b8a39cf39c72d646
Results so far have been promising, but there can be wrong deductions. If this proves to be a false positive, please close as WAI; data from false positives will be used to improve accuracy over time. And please feel free to reach out to me directly if you have concerns or feedback on the project.