From 4320748aa7d3dc82b7064b23625a78d621f21963 Mon Sep 17 00:00:00 2001
From: Kaylee Lubick <kjlubick@google.com>
Date: Mon, 30 Mar 2026 08:44:58 -0700
Subject: [PATCH] Validate sizes in mskp reading and SkTableMaskFilter

The max dimension for mskps is approximately the sqrt of INT32_MAX
which felt "big enough"

Bug: https://issues.chromium.org/issues/496526419
Change-Id: I6850c28e18f7427d85ea0ea724c5d056a4682970
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/1198616
Commit-Queue: Kaylee Lubick <kjlubick@google.com>
Reviewed-by: Jorge Betancourt <jmbetancourt@google.com>
---
 src/effects/SkTableMaskFilter.cpp    | 12 ++++++++++--
 src/utils/SkMultiPictureDocument.cpp | 18 +++++++++++++-----
 2 files changed, 23 insertions(+), 7 deletions(-)

diff --git a/src/effects/SkTableMaskFilter.cpp b/src/effects/SkTableMaskFilter.cpp
index d422ce02d4..ad423727cf 100644
--- a/src/effects/SkTableMaskFilter.cpp
+++ b/src/effects/SkTableMaskFilter.cpp
@@ -78,14 +78,22 @@ bool SkTableMaskFilterImpl::filterMask(SkMaskBuilder* dst, const SkMask& src,
     if (src.fFormat != SkMask::kA8_Format) {
         return false;
     }
-
+    // SkAlign4 overflows when too close to INT32_MAX, so reject when too big.
+    constexpr int32_t kMaxWidth = 1 << 30;
+    if (src.fBounds.width() > kMaxWidth) {
+        return false;
+    }
     dst->bounds() = src.fBounds;
     dst->rowBytes() = SkAlign4(dst->fBounds.width());
     dst->format() = SkMask::kA8_Format;
     dst->image() = nullptr;
 
     if (src.fImage) {
-        dst->image() = SkMaskBuilder::AllocImage(dst->computeImageSize());
+        auto imgSize = dst->computeImageSize();
+        if (imgSize == 0) {
+            return false;
+        }
+        dst->image() = SkMaskBuilder::AllocImage(imgSize);
 
         const uint8_t* srcP = src.fImage;
         uint8_t* dstP = dst->image();
diff --git a/src/utils/SkMultiPictureDocument.cpp b/src/utils/SkMultiPictureDocument.cpp
index 5f327e6f70..72377d0eb6 100644
--- a/src/utils/SkMultiPictureDocument.cpp
+++ b/src/utils/SkMultiPictureDocument.cpp
@@ -50,7 +50,9 @@ static constexpr char kMagic[] = "Skia Multi-Picture Doc\n\n";
 
 static constexpr char kEndPage[] = "SkMultiPictureEndPage";
 
-const uint32_t kVersion = 2;
+static constexpr uint32_t kVersion = 2;
+
+static constexpr uint32_t kMaxDimension = 1 << 16;
 
 static SkSize join(const TArray<SkSize>& sizes) {
     SkSize joined = {0, 0};
@@ -169,28 +171,34 @@ int ReadPageCount(SkStreamSeekable* src) {
         return 0;
     }
     uint32_t pageCount;
-    if (!src->readU32(&pageCount) || pageCount > INT_MAX) {
+    if (!src->readU32(&pageCount) || pageCount > (INT_MAX / sizeof(SkSize))) {
         return 0;
     }
     // leave stream position right here.
     return SkTo<int>(pageCount);
 }
 
-bool ReadPageSizes(SkStreamSeekable* stream,
+bool ReadPageSizes(SkStreamSeekable* src,
                    SkDocumentPage* dstArray,
                    int dstArrayCount) {
     if (!dstArray || dstArrayCount < 1) {
         return false;
     }
-    int pageCount = ReadPageCount(stream);
+    int pageCount = ReadPageCount(src);
     if (pageCount < 1 || pageCount != dstArrayCount) {
         return false;
     }
+    if (src->hasLength() && src->getLength() < (static_cast<size_t>(pageCount) * sizeof(SkSize))) {
+        return false;  // not enough memory to read all the sizes
+    }
     for (int i = 0; i < pageCount; ++i) {
         SkSize& s = dstArray[i].fSize;
-        if (sizeof(s) != stream->read(&s, sizeof(s))) {
+        if (sizeof(s) != src->read(&s, sizeof(s))) {
             return false;
         }
+        if (s.isEmpty() || s.width() >= kMaxDimension || s.height() >= kMaxDimension) {
+            return false;  // invalid sizes
+        }
     }
     // leave stream position right here.
     return true;
-- 
2.53.0

