Browse Source

LibGfx: Catch integer overflows in PNG decoder and fail the decode

Found by oss-fuzz: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=28134&sort=reported&q=serenity
Andreas Kling 4 years ago
parent
commit
0fc8561029
1 changed files with 24 additions and 4 deletions
  1. 24 4
      Libraries/LibGfx/PNGLoader.cpp

+ 24 - 4
Libraries/LibGfx/PNGLoader.cpp

@@ -130,6 +130,20 @@ struct PNGLoadingContext {
     Vector<u8> compressed_data;
     Vector<PaletteEntry> palette_data;
     Vector<u8> palette_transparency_data;
+
+    Checked<int> compute_row_size_for_width(int width)
+    {
+        Checked<int> row_size = width;
+        row_size *= channels;
+        row_size *= bit_depth;
+        row_size += 7;
+        row_size /= 8;
+        if (row_size.has_overflow()) {
+            dbgln("PNG too large, integer overflow while computing row size");
+            state = State::Error;
+        }
+        return row_size;
+    }
 };
 
 class Streamer {
@@ -607,8 +621,11 @@ static bool decode_png_bitmap_simple(PNGLoadingContext& context)
 
         context.scanlines.append({ filter });
         auto& scanline_buffer = context.scanlines.last().data;
-        auto row_size = ((context.width * context.channels * context.bit_depth) + 7) / 8;
-        if (!streamer.wrap_bytes(scanline_buffer, row_size)) {
+        auto row_size = context.compute_row_size_for_width(context.width);
+        if (row_size.has_overflow())
+            return false;
+
+        if (!streamer.wrap_bytes(scanline_buffer, row_size.value())) {
             context.state = PNGLoadingContext::State::Error;
             return false;
         }
@@ -710,8 +727,11 @@ static bool decode_adam7_pass(PNGLoadingContext& context, Streamer& streamer, in
 
         subimage_context.scanlines.append({ filter });
         auto& scanline_buffer = subimage_context.scanlines.last().data;
-        auto row_size = ((subimage_context.width * context.channels * context.bit_depth) + 7) / 8;
-        if (!streamer.wrap_bytes(scanline_buffer, row_size)) {
+
+        auto row_size = context.compute_row_size_for_width(subimage_context.width);
+        if (row_size.has_overflow())
+            return false;
+        if (!streamer.wrap_bytes(scanline_buffer, row_size.value())) {
             context.state = PNGLoadingContext::State::Error;
             return false;
         }