From e202cf3ef8e18c0f47f1d7098fb96efbdc1953c1 Mon Sep 17 00:00:00 2001
From: Kaylee Lubick <kjlubick@google.com>
Date: Fri, 29 May 2026 15:16:50 -0400
Subject: [PATCH] Address potential MSAN issue in SkScalerContext

If malformed data was passed to SkStrikeClient, an unexpected
mask would pass through asserts in a release build and lead
to a mask being allocated that was 4x bigger than what
was written to.

To defend against this problem, we 1) reject masks that
aren't of the three formats SkScalerContext::GenerateImageFromPath
expects; 2) zero out the whole mask, regardless of how big
it is instead of relying on how big an A8 mask would be.

Additionally, I noticed that in the intermediateDst case
(e.g. for LCD text when we draw into an A8 and then later unpack
it to be LCD16) we weren't zeroing that intermediate buffer
which could be a problem if the glyph itself was small (but
the bounds were corrupted to be big). Thus, we zero that
intermediate A8 buffer too.

Change-Id: Ib7080fc45eb77ea19b3e733570da33cd339a51f8
Bug: https://issues.chromium.org/issues/513780208
Fixed: 513780208
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/1248536
Commit-Queue: Kaylee Lubick <kjlubick@google.com>
Auto-Submit: Kaylee Lubick <kjlubick@google.com>
Reviewed-by: Florin Malita <fmalita@google.com>
---
 src/core/SkGlyph.cpp             |  6 +++
 src/core/SkScalerContext.cpp     |  4 +-
 tests/SkRemoteGlyphCacheTest.cpp | 86 ++++++++++++++++++++++++++++++++
 3 files changed, 95 insertions(+), 1 deletion(-)

diff --git a/src/core/SkGlyph.cpp b/src/core/SkGlyph.cpp
index 26c8004256..7f440a4dfd 100644
--- a/src/core/SkGlyph.cpp
+++ b/src/core/SkGlyph.cpp
@@ -406,6 +406,12 @@ size_t SkGlyph::addPathFromBuffer(SkReadBuffer& buffer, SkArenaAlloc* alloc) {
         const bool pathIsHairline = buffer.readBool();
         const bool pathIsModified = buffer.readBool();
         if (auto path = buffer.readPath()) {
+            if (fMaskFormat != SkMask::kBW_Format &&
+                fMaskFormat != SkMask::kA8_Format &&
+                fMaskFormat != SkMask::kLCD16_Format) {
+                buffer.validate(false);
+                return 0;
+            }
             if (this->setPath(alloc, &path.value(), pathIsHairline, pathIsModified)) {
                 memoryIncrease += path->approximateBytesUsed();
             }
diff --git a/src/core/SkScalerContext.cpp b/src/core/SkScalerContext.cpp
index 85edc26a3f..2d68c145f0 100644
--- a/src/core/SkScalerContext.cpp
+++ b/src/core/SkScalerContext.cpp
@@ -572,10 +572,11 @@ void SkScalerContext::GenerateImageFromPath(
             sk_bzero(dstMask.image(), dstMask.computeImageSize());
             return;
         }
+        sk_bzero(dst.writable_addr(), dst.computeByteSize());
     } else {
         dst.reset(info, dstMask.image(), dstMask.fRowBytes);
     }
-    sk_bzero(dst.writable_addr(), dst.computeByteSize());
+    sk_bzero(dstMask.image(), dstMask.computeImageSize());
 
     skcpu::Draw draw;
     draw.fBlitterChooser = SkA8Blitter_Choose;
@@ -600,6 +601,7 @@ void SkScalerContext::GenerateImageFromPath(
             pack4xHToMask(dst, dstMask, maskPreBlend, doBGR, verticalLCD);
             break;
         default:
+            SkUNREACHABLE;
             break;
     }
 }
-- 
2.53.0

