LibGfx: Make all image decoders reject image sizes above 16384 pixels

Let's just say no to shenanigans by capping images at 16384 pixels both
wide and tall. If a day comes in the future where we need to handle
images larger than this, we can deal with it then.
This commit is contained in:
Andreas Kling 2020-12-25 00:19:06 +01:00
parent a5f4cb78cf
commit edf01803cd
Notes: sideshowbarker 2024-07-19 00:37:24 +09:00
7 changed files with 38 additions and 10 deletions

View file

@ -518,6 +518,11 @@ static bool decode_bmp_core_dib(BMPLoadingContext& context, Streamer& streamer)
return false; return false;
} }
if (static_cast<size_t>(core.width) > maximum_width_for_decoded_images || static_cast<size_t>(abs(core.height)) > maximum_height_for_decoded_images) {
dbgln("This BMP is too large for comfort: {}x{}", core.width, abs(core.height));
return false;
}
auto color_planes = streamer.read_u16(); auto color_planes = streamer.read_u16();
if (color_planes != 1) { if (color_planes != 1) {
IF_BMP_DEBUG(dbg() << "BMP has an invalid number of color planes: " << color_planes); IF_BMP_DEBUG(dbg() << "BMP has an invalid number of color planes: " << color_planes);

View file

@ -424,6 +424,11 @@ static bool load_gif_frame_descriptors(GIFLoadingContext& context)
if (stream.handle_any_error()) if (stream.handle_any_error())
return false; return false;
if (context.logical_screen.width > maximum_width_for_decoded_images || context.logical_screen.height > maximum_height_for_decoded_images) {
dbgln("This GIF is too large for comfort: {}x{}", context.logical_screen.width, context.logical_screen.height);
return false;
}
u8 gcm_info = 0; u8 gcm_info = 0;
stream >> gcm_info; stream >> gcm_info;

View file

@ -36,6 +36,9 @@ namespace Gfx {
class Bitmap; class Bitmap;
static constexpr size_t maximum_width_for_decoded_images = 16384;
static constexpr size_t maximum_height_for_decoded_images = 16384;
struct ImageFrameDescriptor { struct ImageFrameDescriptor {
RefPtr<Bitmap> image; RefPtr<Bitmap> image;
int duration { 0 }; int duration { 0 };

View file

@ -776,6 +776,12 @@ static bool read_start_of_frame(InputMemoryStream& stream, JPGLoadingContext& co
#endif #endif
return false; return false;
} }
if (context.frame.width > maximum_width_for_decoded_images || context.frame.height > maximum_height_for_decoded_images) {
dbgln("This JPEG is too large for comfort: {}x{}", context.frame.width, context.frame.height);
return false;
}
set_macroblock_metadata(context); set_macroblock_metadata(context);
stream >> context.component_count; stream >> context.component_count;

View file

@ -60,8 +60,8 @@ struct PBMLoadingContext {
State state { State::NotDecoded }; State state { State::NotDecoded };
const u8* data { nullptr }; const u8* data { nullptr };
size_t data_size { 0 }; size_t data_size { 0 };
int width { -1 }; size_t width { 0 };
int height { -1 }; size_t height { 0 };
RefPtr<Gfx::Bitmap> bitmap; RefPtr<Gfx::Bitmap> bitmap;
}; };

View file

@ -853,8 +853,8 @@ static bool process_IHDR(ReadonlyBytes data, PNGLoadingContext& context)
return false; return false;
auto& ihdr = *(const PNG_IHDR*)data.data(); auto& ihdr = *(const PNG_IHDR*)data.data();
if (ihdr.width > NumericLimits<i32>::max() || ihdr.height > NumericLimits<i32>::max()) { if (ihdr.width > maximum_width_for_decoded_images || ihdr.height > maximum_height_for_decoded_images) {
dbgln("PNG has invalid geometry {}x{}", (u32)ihdr.width, (u32)ihdr.height); dbgln("This PNG is too large for comfort: {}x{}", (u32)ihdr.width, (u32)ihdr.height);
return false; return false;
} }

View file

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2020, the SerenityOS developers, Hüseyin ASLITÜRK <asliturk@hotmail.com> * Copyright (c) 2020, Hüseyin Aslıtürk <asliturk@hotmail.com>
* Copyright (c) 2020, the SerenityOS developers
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -26,7 +27,6 @@
#pragma once #pragma once
#include "Streamer.h"
#include <AK/Array.h> #include <AK/Array.h>
#include <AK/Endian.h> #include <AK/Endian.h>
#include <AK/LexicalPath.h> #include <AK/LexicalPath.h>
@ -36,6 +36,10 @@
#include <AK/StringBuilder.h> #include <AK/StringBuilder.h>
#include <AK/Types.h> #include <AK/Types.h>
#include <AK/Vector.h> #include <AK/Vector.h>
#include <LibGfx/Bitmap.h>
#include <LibGfx/Color.h>
#include <LibGfx/ImageDecoder.h>
#include <LibGfx/Streamer.h>
//#define PORTABLE_IMAGE_LOADER_DEBUG //#define PORTABLE_IMAGE_LOADER_DEBUG
@ -216,8 +220,8 @@ template<typename TContext>
static void set_adjusted_pixels(TContext& context, const AK::Vector<Gfx::Color>& color_data) static void set_adjusted_pixels(TContext& context, const AK::Vector<Gfx::Color>& color_data)
{ {
size_t index = 0; size_t index = 0;
for (int y = 0; y < context.height; ++y) { for (size_t y = 0; y < context.height; ++y) {
for (int x = 0; x < context.width; ++x) { for (size_t x = 0; x < context.width; ++x) {
Color color = color_data.at(index); Color color = color_data.at(index);
if (context.max_val < 255) { if (context.max_val < 255) {
color = adjust_color(context.max_val, color); color = adjust_color(context.max_val, color);
@ -232,8 +236,8 @@ template<typename TContext>
static void set_pixels(TContext& context, const AK::Vector<Gfx::Color>& color_data) static void set_pixels(TContext& context, const AK::Vector<Gfx::Color>& color_data)
{ {
size_t index = 0; size_t index = 0;
for (int y = 0; y < context.height; ++y) { for (size_t y = 0; y < context.height; ++y) {
for (int x = 0; x < context.width; ++x) { for (size_t x = 0; x < context.width; ++x) {
context.bitmap->set_pixel(x, y, color_data.at(index)); context.bitmap->set_pixel(x, y, color_data.at(index));
index++; index++;
} }
@ -267,6 +271,11 @@ static bool decode(TContext& context)
if (!read_height(context, streamer)) if (!read_height(context, streamer))
return false; return false;
if (context.width > maximum_width_for_decoded_images || context.height > maximum_height_for_decoded_images) {
dbgln("This portable network image is too large for comfort: {}x{}", context.width, context.height);
return false;
}
if (!read_white_space(context, streamer)) if (!read_white_space(context, streamer))
return false; return false;