Low chrome Integer Overflow 🔧 Commit mapped

Overview

Low
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactInteger overflow in Chromium
DescriptionInteger overflow in Chromium
ComponentChromium
Bug ClassInteger Overflow
Tracker530816571
Fix commit36e509ddad66 (skia) +66/-6
CISA KEVNot listed
CreditedYoungjin Ju
Disclosed2026-08-25

Changed Functions

FunctionChangeNotes
DEF_TEST
modules/skottie/src/SkottieTest.cpp
modified
TestMarkerObserver
modules/skottie/src/SkottieTest.cpp
modified
TestResourceProvider
modules/skottie/src/SkottieTest.cpp
modified

Files Changed

  • modules/skottie/BUILD.gn
  • modules/skottie/src/SkottieTest.cpp
From 36e509ddad66569e1a604816c1e47845950eee77 Mon Sep 17 00:00:00 2001
From: Florin Malita <fmalita@google.com>
Date: Mon, 13 Jul 2026 12:15:44 -0400
Subject: [PATCH] [skottie] Fix gradient count overflow in 32 bit builds

Use SkSafeMath to detect size_t overflows.

Also relocate SkottieTest.cpp from src/ to tests/.

Bug: b/530816571
Change-Id: I861fe30b5223e2fb074c37217afa7d3bd48419ca
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/1292156
Commit-Queue: Florin Malita <fmalita@google.com>
Reviewed-by: Brandon Wilson <bwils@google.com>
---

diff --git a/modules/skottie/BUILD.gn b/modules/skottie/BUILD.gn
index 91aeb77..fc95703 100644
--- a/modules/skottie/BUILD.gn
+++ b/modules/skottie/BUILD.gn
@@ -60,13 +60,13 @@
 
         configs = [ "../..:skia_private" ]
         sources = [
-          "src/SkottieTest.cpp",
           "tests/AudioLayer.cpp",
           "tests/Expression.cpp",
           "tests/Image.cpp",
           "tests/Keyframe.cpp",
           "tests/PropertyObserver.cpp",
           "tests/Shaper.cpp",
+          "tests/SkottieTest.cpp",
           "tests/Text.cpp",
         ]
 
diff --git a/modules/skottie/src/SkottieTest.cpp b/modules/skottie/src/SkottieTest.cpp
deleted file mode 100644
index 76bd5c3..0000000
--- a/modules/skottie/src/SkottieTest.cpp
+++ /dev/null
@@ -1,271 +0,0 @@
-/*
- * Copyright 2018 Google LLC
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "include/core/SkStream.h"
-#include "include/core/SkSurface.h"
-#include "modules/skottie/include/Skottie.h"
-#include "tests/Test.h"
-
-#include <cmath>
-#include <string>
-#include <tuple>
-#include <vector>
-
-using namespace skottie;
-
-DEF_TEST(Skottie_OssFuzz8956, reporter) {
-    static constexpr char json[] =
-        "{\"v\":\" \",\"fr\":3,\"w\":4,\"h\":3,\"layers\":[{\"ty\": 1, \"sw\": 10, \"sh\": 10,"
-            " \"sc\":\"#ffffff\", \"ks\":{\"o\":{\"a\": true, \"k\":"
-            " [{\"t\": 0, \"s\": 0, \"e\": 1, \"i\": {\"x\":[]}}]}}}]}";
-
-    SkMemoryStream stream(json, strlen(json));
-
-    // Passes if parsing doesn't crash.
-    auto animation = Animation::Make(&stream);
-}
-
-DEF_TEST(Skottie_Annotations, reporter) {
-    static constexpr char json[] = R"({
-                                     "v": "5.2.1",
-                                     "w": 100,
-                                     "h": 100,
-                                     "fr": 10,
-                                     "ip": 0,
-                                     "op": 100,
-                                     "layers": [
-                                       {
-                                         "ty": 1,
-                                         "ind": 0,
-                                         "ip": 0,
-                                         "op": 1,
-                                         "ks": {
-                                           "o": { "a": 0, "k": 50 }
-                                         },
-                                         "sw": 100,
-                                         "sh": 100,
-                                         "sc": "#ffffff"
-                                       }
-                                     ],
-                                     "markers": [
-                                       {
-                                           "cm": "marker_1",
-                                           "dr": 25,
-                                           "tm": 25
-                                       },
-                                       {
-                                           "cm": "marker_2",
-                                           "dr": 0,
-                                           "tm": 75
-                                       }
-                                     ]
-                                   })";
-
-    class TestMarkerObserver final : public MarkerObserver {
-    public:
-        void onMarker(const char name[], float t0, float t1) override {
-            fMarkers.push_back(std::make_tuple(name, t0, t1));
-        }
-
-        std::vector<std::tuple<std::string, float, float>> fMarkers;
-    };
-
-    SkMemoryStream stream(json, strlen(json));
-    auto observer = sk_make_sp<TestMarkerObserver>();
-
-    auto animation = skottie::Animation::Builder()
-            .setMarkerObserver(observer)
-            .make(&stream);
-
-    REPORTER_ASSERT(reporter, animation);
-    REPORTER_ASSERT(reporter, animation->duration() == 10);
-    REPORTER_ASSERT(reporter, animation->inPoint()  == 0.0);
-    REPORTER_ASSERT(reporter, animation->outPoint() == 100.0);
-
-    REPORTER_ASSERT(reporter, observer->fMarkers.size() == 2ul);
-    REPORTER_ASSERT(reporter, std::get<0>(observer->fMarkers[0]) == "marker_1");
-    REPORTER_ASSERT(reporter, std::get<1>(observer->fMarkers[0]) == 0.25f);
-    REPORTER_ASSERT(reporter, std::get<2>(observer->fMarkers[0]) == 0.50f);
-    REPORTER_ASSERT(reporter, std::get<0>(observer->fMarkers[1]) == "marker_2");
-    REPORTER_ASSERT(reporter, std::get<1>(observer->fMarkers[1]) == 0.75f);
-    REPORTER_ASSERT(reporter, std::get<2>(observer->fMarkers[1]) == 0.75f);
-}
-
-DEF_TEST(Skottie_Image_Loading, reporter) {
-    class TestResourceProvider final : public skresources::ResourceProvider {
-    public:
-        TestResourceProvider(sk_sp<skresources::ImageAsset> single_asset,
-                             sk_sp<skresources::ImageAsset>  multi_asset)
-            : fSingleFrameAsset(std::move(single_asset))
-            , fMultiFrameAsset (std::move( multi_asset)) {}
-
-    private:
-        sk_sp<ImageAsset> loadImageAsset(const char path[],
-                                         const char name[],
-                                         const char id[]) const override {
-            return strcmp(id, "single_frame")
-                    ? fMultiFrameAsset
-                    : fSingleFrameAsset;
-        }
-
-        const sk_sp<skresources::ImageAsset> fSingleFrameAsset,
-                                             fMultiFrameAsset;
-    };
-
-    auto make_animation = [&reporter] (sk_sp<skresources::ImageAsset> single_asset,
-                                       sk_sp<skresources::ImageAsset>  multi_asset,
-                                       bool deferred_image_loading) {
-        static constexpr char json[] = R"({
-                                         "v": "5.2.1",
-                                         "w": 100,
-                                         "h": 100,
-                                         "fr": 10,
-                                         "ip": 0,
-                                         "op": 100,
-                                         "assets": [
-                                           {
-                                             "id": "single_frame",
-                                             "p" : "single_frame.png",
-                                             "u" : "images/",
-                                             "w" : 500,
-                                             "h" : 500
-                                           },
-                                           {
-                                             "id": "multi_frame",
-                                             "p" : "multi_frame.png",
-                                             "u" : "images/",
-                                             "w" : 500,
-                                             "h" : 500
-                                           }
-                                         ],
-                                         "layers": [
-                                           {
-                                             "ty": 2,
-                                             "refId": "single_frame",
-                                             "ind": 0,
-                                             "ip": 0,
-                                             "op": 100,
-                                             "ks": {}
-                                           },
-                                           {
-                                             "ty": 2,
-                                             "refId": "multi_frame",
-                                             "ind": 1,
-                                             "ip": 0,
-                                             "op": 100,
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/modules/skottie/tests/SkottieTest.cpp b/modules/skottie/tests/SkottieTest.cpp
new file mode 100644
index 0000000..472c2bd
--- /dev/null
+++ b/modules/skottie/tests/SkottieTest.cpp
@@ -0,0 +1,322 @@
+/*
+ * Copyright 2018 Google LLC
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "include/core/SkStream.h"
+#include "include/core/SkSurface.h"
+#include "modules/skottie/include/Skottie.h"
+#include "tests/Test.h"
+
+#include <string>
+#include <tuple>
+#include <vector>
+
+using namespace skottie;
+
+DEF_TEST(Skottie_OssFuzz8956, reporter) {
+    static constexpr char json[] =
+        "{\"v\":\" \",\"fr\":3,\"w\":4,\"h\":3,\"layers\":[{\"ty\": 1, \"sw\": 10, \"sh\": 10,"
+            " \"sc\":\"#ffffff\", \"ks\":{\"o\":{\"a\": true, \"k\":"
+            " [{\"t\": 0, \"s\": 0, \"e\": 1, \"i\": {\"x\":[]}}]}}}]}";
+
+    SkMemoryStream stream(json, strlen(json));
+
+    // Passes if parsing doesn't crash.
+    auto animation = Animation::Make(&stream);
+}
+
+DEF_TEST(Skottie_Annotations, reporter) {
+    static constexpr char json[] = R"({
+                                     "v": "5.2.1",
+                                     "w": 100,
+                                     "h": 100,
+                                     "fr": 10,
+                                     "ip": 0,
+                                     "op": 100,
+                                     "layers": [
+                                       {
+                                         "ty": 1,
+                                         "ind": 0,
+                                         "ip": 0,
+                                         "op": 1,
+                                         "ks": {
+                                           "o": { "a": 0, "k": 50 }
+                                         },
+                                         "sw": 100,
+                                         "sh": 100,
+                                         "sc": "#ffffff"
+                                       }
+                                     ],
+                                     "markers": [
+                                       {
+                                           "cm": "marker_1",
+                                           "dr": 25,
+                                           "tm": 25
+                                       },
+                                       {
+                                           "cm": "marker_2",
+                                           "dr": 0,
+                                           "tm": 75
+                                       }
+                                     ]
+                                   })";
+
+    class TestMarkerObserver final : public MarkerObserver {
+    public:
+        void onMarker(const char name[], float t0, float t1) override {
+            fMarkers.push_back(std::make_tuple(name, t0, t1));
+        }
+
+        std::vector<std::tuple<std::string, float, float>> fMarkers;
+    };
+
+    SkMemoryStream stream(json, strlen(json));
+    auto observer = sk_make_sp<TestMarkerObserver>();
+
+    auto animation = skottie::Animation::Builder()
+            .setMarkerObserver(observer)
+            .make(&stream);
+
+    REPORTER_ASSERT(reporter, animation);
+    REPORTER_ASSERT(reporter, animation->duration() == 10);
+    REPORTER_ASSERT(reporter, animation->inPoint()  == 0.0);
+    REPORTER_ASSERT(reporter, animation->outPoint() == 100.0);
+
+    REPORTER_ASSERT(reporter, observer->fMarkers.size() == 2ul);
+    REPORTER_ASSERT(reporter, std::get<0>(observer->fMarkers[0]) == "marker_1");
+    REPORTER_ASSERT(reporter, std::get<1>(observer->fMarkers[0]) == 0.25f);
+    REPORTER_ASSERT(reporter, std::get<2>(observer->fMarkers[0]) == 0.50f);
+    REPORTER_ASSERT(reporter, std::get<0>(observer->fMarkers[1]) == "marker_2");
+    REPORTER_ASSERT(reporter, std::get<1>(observer->fMarkers[1]) == 0.75f);
+    REPORTER_ASSERT(reporter, std::get<2>(observer->fMarkers[1]) == 0.75f);
+}
+
+DEF_TEST(Skottie_Image_Loading, reporter) {
+    class TestResourceProvider final : public skresources::ResourceProvider {
+    public:
+        TestResourceProvider(sk_sp<skresources::ImageAsset> single_asset,
+                             sk_sp<skresources::ImageAsset>  multi_asset)
+            : fSingleFrameAsset(std::move(single_asset))
+            , fMultiFrameAsset (std::move( multi_asset)) {}
+
+    private:
+        sk_sp<ImageAsset> loadImageAsset(const char path[],
+                                         const char name[],
+                                         const char id[]) const override {
+            return strcmp(id, "single_frame")
+                    ? fMultiFrameAsset
+                    : fSingleFrameAsset;
+        }
+
+        const sk_sp<skresources::ImageAsset> fSingleFrameAsset,
+                                             fMultiFrameAsset;
+    };
+
+    auto make_animation = [&reporter] (sk_sp<skresources::ImageAsset> single_asset,
+                                       sk_sp<skresources::ImageAsset>  multi_asset,
+                                       bool deferred_image_loading) {
+        static constexpr char json[] = R"({
+                                         "v": "5.2.1",
+                                         "w": 100,
+                                         "h": 100,
+                                         "fr": 10,
+                                         "ip": 0,
+                                         "op": 100,
+                                         "assets": [
+                                           {
+                                             "id": "single_frame",
+                                             "p" : "single_frame.png",
+                                             "u" : "images/",
+                                             "w" : 500,
+                                             "h" : 500
+                                           },
+                                           {
+                                             "id": "multi_frame",
+                                             "p" : "multi_frame.png",
+                                             "u" : "images/",
+                                             "w" : 500,
+                                             "h" : 500
+                                           }
+                                         ],
+                                         "layers": [
+                                           {
+                                             "ty": 2,
+                                             "refId": "single_frame",
+                                             "ind": 0,
+                                             "ip": 0,
+                                             "op": 100,
+                                             "ks": {}
+                                           },
+                                           {
+                                             "ty": 2,
+                                             "refId": "multi_frame",
+                                             "ind": 1,
+                                             "ip": 0,
+                                             "op": 100,
+                                             "ks": {}
+                                           }
+                                         ]
+                                       })";
+
+        SkMemoryStream stream(json, strlen(json));
+
+        const auto flags = deferred_image_loading
+            ? static_cast<uint32_t>(skottie::Animation::Builder::kDeferImageLoading)
+            : 0;
+        auto animation =
+            skottie::Animation::Builder(flags)
+                .setResourceProvider(sk_make_sp<TestResourceProvider>(std::move(single_asset),
+                                                                      std::move( multi_asset)))
+                .make(&stream);
+
+        REPORTER_ASSERT(reporter, animation);
+
+        return  animation;
+    };
+
+    class TestAsset final : public skresources::ImageAsset {
+    public:
+        explicit TestAsset(bool multi_frame) : fMultiFrame(multi_frame) {}
+
+        const std::vector<float>& requestedFrames() const { return fRequestedFrames; }
+
+    private:
+        bool isMultiFrame() override { return fMultiFrame; }
+
+        sk_sp<SkImage> getFrame(float t) override {
+            fRequestedFrames.push_back(t);
+
+            return SkSurfaces::Raster(SkImageInfo::MakeN32Premul(10, 10))->makeImageSnapshot();
+        }
+
+        const bool fMultiFrame;
+
+        std::vector<float> fRequestedFrames;
+    };
+
+    {
+        auto single_asset = sk_make_sp<TestAsset>(false),
+              multi_asset = sk_make_sp<TestAsset>(true);
+
+        // Default image loading: single-frame images are loaded upfront, multi-frame images are
+        // loaded on-demand.
+        auto animation = make_animation(single_asset, multi_asset, false);
+
+        REPORTER_ASSERT(reporter, single_asset->requestedFrames().size() == 1);
+        REPORTER_ASSERT(reporter,  multi_asset->requestedFrames().size() == 0);
+        REPORTER_ASSERT(reporter, SkScalarNearlyZero(single_asset->requestedFrames()[0]));
+
+        animation->seekFrameTime(1);
+        REPORTER_ASSERT(reporter, single_asset->requestedFrames().size() == 1);
+        REPORTER_ASSERT(reporter,  multi_asset->requestedFrames().size() == 1);
+        REPORTER_ASSERT(reporter, SkScalarNearlyEqual(multi_asset->requestedFrames()[0], 1));
+
+        animation->seekFrameTime(2);
+        REPORTER_ASSERT(reporter, single_asset->requestedFrames().size() == 1);
+        REPORTER_ASSERT(reporter,  multi_asset->requestedFrames().size() == 2);
+        REPORTER_ASSERT(reporter, SkScalarNearlyEqual(multi_asset->requestedFrames()[1], 2));
+    }
+
+    {
+        auto single_asset = sk_make_sp<TestAsset>(false),
+              multi_asset = sk_make_sp<TestAsset>(true);
+
+        // Deferred image loading: both single-frame and multi-frame images are loaded on-demand.
+        auto animation = make_animation(single_asset, multi_asset, true);
+
+        REPORTER_ASSERT(reporter, single_asset->requestedFrames().size() == 0);
+        REPORTER_ASSERT(reporter,  multi_asset->requestedFrames().size() == 0);
+
+        animation->seekFrameTime(1);
+        REPORTER_ASSERT(reporter, single_asset->requestedFrames().size() == 1);
+        REPORTER_ASSERT(reporter,  multi_asset->requestedFrames().size() == 1);
+        REPORTER_ASSERT(reporter, SkScalarNearlyEqual(single_asset->requestedFrames()[0], 1));
+        REPORTER_ASSERT(reporter, SkScalarNearlyEqual (multi_asset->requestedFrames()[0], 1));
+
+        animation->seekFrameTime(2);
+        REPORTER_ASSERT(reporter, single_asset->requestedFrames().size() == 1);
+        REPORTER_ASSERT(reporter,  multi_asset->requestedFrames().size() == 2);
+        REPORTER_ASSERT(reporter, SkScalarNearlyEqual(multi_asset->requestedFrames()[1], 2));
+    }
+}
+
+DEF_TEST(Skottie_Layer_NoType, r) {
+    static constexpr char json[] =
+        R"({
+             "v": "5.2.1",
+             "w": 100,
+             "h": 100,
+             "fr": 10,
+             "ip": 0,
+             "op": 100,
+             "layers": [
+               {
+                 "ind": 0,
+                 "ip": 0,
+                 "op": 100,
+                 "ks": {}
+               }
+             ]
+           })";
+
+    SkMemoryStream stream(json, strlen(json));
+    auto anim = Animation::Make(&stream);
+
+    // passes if we don't crash
+    REPORTER_ASSERT(r, anim);
+}
+
+DEF_TEST(Skottie_Gradient_InvalidCount, r) {
+    static constexpr char json[] = R"({
+      "v": "5.12.0",
+      "fr": 60,
+      "ip": 0,
+      "op": 1,
+      "w": 64,
+      "h": 64,
+      "layers": [
+        {
+          "ind": 1,
+          "ty": 4,
+          "sr": 1,
+          "ks": {},
+          "shapes": [
+            {
+              "ty": "rc",
+              "d": 1,
+              "p": { "a": 0, "k": [0, 0] },
+              "s": { "a": 0, "k": [32, 32] },
+              "r": { "a": 0, "k": 0 }
+            },
+            {
... (truncated)
Loading diff…

Original Bug Report

The reporter's bug is still restricted on the tracker. Chrome de-restricts security bugs ~30–90 days after the fix ships; a later run will backfill it here.