mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-12-25 20:22:18 +03:00
LibGfx/WebPLossless: Fix out-of-bounds write in color indexing transform
If a lossless webp has 3 or 4 colors, it uses 2 bits per pixel to store an offset into a "color index" (which the spec explicitly does not call palette since it says the 'color cache' is more like that). This way, it can pack 4 pixels into a single pixel. If the width of the output image wasn't evenly divisble by 4, we used to write out-of-bounds in the last few columns of each row, since we used to always write all 4 pixels. Found by clusterfuzz. Probably fixes https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=66082 While here, spruce up the comments very slightly.
This commit is contained in:
parent
c8b219914e
commit
7cb12e057f
Notes:
sideshowbarker
2024-07-17 00:53:02 +09:00
Author: https://github.com/nico Commit: https://github.com/SerenityOS/serenity/commit/7cb12e057f Pull-request: https://github.com/SerenityOS/serenity/pull/23645 Reviewed-by: https://github.com/trflynn89 ✅
@ -838,11 +838,11 @@ public:
|
||||
// This returns how many output pixels one input pixel can encode after the color indexing transform.
|
||||
//
|
||||
// The spec isn't very explicit about this, but this affects all images after the color indexing transform:
|
||||
// If a webp file contains a 32x32 image and it contains a color indexing transform with a 4-color palette, then the in-memory size of all images
|
||||
// after the color indexing transform assume a bitmap size of (32/4)x32 = 8x32.
|
||||
// If a webp file contains a 29x32 image and it contains a color indexing transform with a 4-color palette, then the in-memory size of all images
|
||||
// after the color indexing transform assume a bitmap size of ceil_div(29, 4)x32 = 8x32.
|
||||
// That is, the sizes of transforms after the color indexing transform are computed relative to the size 8x32,
|
||||
// the main image's meta prefix image's size (if present) is comptued relative to the size 8x32,
|
||||
// the main image is 8x32, and only applying the color indexing transform resizes the image back to 32x32.
|
||||
// the main image's meta prefix image's size (if present) is computed relative to the size 8x32,
|
||||
// the main image is 8x32, and only applying the color indexing transform resizes the image back to 29x32.
|
||||
int pixels_per_pixel() const { return m_pixels_per_pixel; }
|
||||
|
||||
private:
|
||||
@ -868,7 +868,7 @@ ErrorOr<NonnullOwnPtr<ColorIndexingTransform>> ColorIndexingTransform::read(Litt
|
||||
IntSize palette_image_size { color_table_size, 1 };
|
||||
auto palette_bitmap = TRY(decode_webp_chunk_VP8L_image(ImageKind::EntropyCoded, BitmapFormat::BGRA8888, palette_image_size, bit_stream));
|
||||
|
||||
// "When the color table is small (equal to or less than 16 colors), several pixels are bundled into a single pixel...."
|
||||
// "When the color table is small (equal to or less than 16 colors), several pixels are bundled into a single pixel..."
|
||||
int pixels_per_pixel = 1;
|
||||
if (color_table_size <= 2)
|
||||
pixels_per_pixel = 8;
|
||||
@ -913,7 +913,7 @@ ErrorOr<NonnullRefPtr<Bitmap>> ColorIndexingTransform::transform(NonnullRefPtr<B
|
||||
for (int x = 0, new_x = 0; x < bitmap->width(); ++x, new_x += pixels_per_pixel()) {
|
||||
u8 indexes = Color::from_argb(bitmap_scanline[x]).green();
|
||||
|
||||
for (int i = 0; i < pixels_per_pixel(); ++i) {
|
||||
for (int i = 0; i < pixels_per_pixel() && new_x + i < new_bitmap->width(); ++i) {
|
||||
u8 index = indexes & pixel_mask;
|
||||
new_bitmap_scanline[new_x + i] = index < m_palette_bitmap->width() ? m_palette_bitmap->scanline(0)[index] : 0;
|
||||
indexes >>= bits_per_pixel;
|
||||
|
Loading…
Reference in New Issue
Block a user