From 0cc01b753ac6750e8decbcb92e4e33de1b147e20 Mon Sep 17 00:00:00 2001 From: Florin Malita Date: Thu, 10 May 2018 18:40:35 -0400 Subject: [skottie] Guard against asset cycles Track assets being attached, and break cycles. Bug: oss-fuzz:8220 Change-Id: I146cf35eba8cfea487c00544fe82f89c3a859803 Reviewed-on: https://skia-review.googlesource.com/127381 Reviewed-by: Kevin Lubick Commit-Queue: Florin Malita --- experimental/skottie/Skottie.cpp | 77 ++++++++++++++++++++++------------------ 1 file changed, 42 insertions(+), 35 deletions(-) (limited to 'experimental') diff --git a/experimental/skottie/Skottie.cpp b/experimental/skottie/Skottie.cpp index 18c8c193c0..8396b5ba90 100644 --- a/experimental/skottie/Skottie.cpp +++ b/experimental/skottie/Skottie.cpp @@ -52,7 +52,12 @@ namespace skottie { namespace { -using AssetMap = SkTHashMap; +struct AssetInfo { + json::ValueRef fAsset; + mutable bool fIsAttaching; // Used for cycle detection +}; + +using AssetMap = SkTHashMap; struct AttachContext { const ResourceProvider& fResources; @@ -756,16 +761,41 @@ sk_sp AttachNestedAnimation(const char* path, AttachContext* c return sk_make_sp(std::move(animation)); } -sk_sp AttachCompLayer(const json::ValueRef& jlayer, AttachContext* ctx, - float* time_bias, float* time_scale) { - SkASSERT(jlayer.isObject()); +sk_sp AttachAssetRef(const json::ValueRef& jlayer, AttachContext* ctx, + sk_sp(*attach_proc)(const json::ValueRef& comp, AttachContext* ctx)) { - SkString refId; - if (!jlayer["refId"].to(&refId) || refId.isEmpty()) { - LOG("!! Comp layer missing refId\n"); + const auto refId = jlayer["refId"].toDefault(SkString()); + if (refId.isEmpty()) { + LOG("!! Layer missing refId\n"); return nullptr; } + if (refId.startsWith("$")) { + return AttachNestedAnimation(refId.c_str() + 1, ctx); + } + + const auto* asset_info = ctx->fAssets.find(refId); + if (!asset_info) { + LOG("!! Asset not found: '%s'\n", refId.c_str()); + return nullptr; + } + + if (asset_info->fIsAttaching) { + LOG("!! Asset cycle detected for: '%s'\n", refId.c_str()); + return nullptr; + } + + asset_info->fIsAttaching = true; + auto asset = attach_proc(asset_info->fAsset, ctx); + asset_info->fIsAttaching = false; + + return asset; +} + +sk_sp AttachCompLayer(const json::ValueRef& jlayer, AttachContext* ctx, + float* time_bias, float* time_scale) { + SkASSERT(jlayer.isObject()); + const auto start_time = jlayer["st"].toDefault(0.0f), stretch_time = jlayer["sr"].toDefault(1.0f); @@ -775,18 +805,7 @@ sk_sp AttachCompLayer(const json::ValueRef& jlayer, AttachCont *time_scale = 1; } - if (refId.startsWith("$")) { - return AttachNestedAnimation(refId.c_str() + 1, ctx); - } - - const auto* comp = ctx->fAssets.find(refId); - if (!comp) { - LOG("!! Pre-comp not found: '%s'\n", refId.c_str()); - return nullptr; - } - - // TODO: cycle detection - return AttachComposition(*comp, ctx); + return AttachAssetRef(jlayer, ctx, AttachComposition); } sk_sp AttachSolidLayer(const json::ValueRef& jlayer, AttachContext*, @@ -831,23 +850,11 @@ sk_sp AttachImageAsset(const json::ValueRef& jimage, AttachCon SkImage::MakeFromEncoded(SkData::MakeFromStream(resStream.get(), resStream->getLength()))); } -sk_sp AttachImageLayer(const json::ValueRef& layer, AttachContext* ctx, +sk_sp AttachImageLayer(const json::ValueRef& jlayer, AttachContext* ctx, float*, float*) { - SkASSERT(layer.isObject()); - - SkString refId; - if (!layer["refId"].to(&refId) || refId.isEmpty()) { - LOG("!! Image layer missing refId\n"); - return nullptr; - } - - const auto* jimage = ctx->fAssets.find(refId); - if (!jimage) { - LOG("!! Image asset not found: '%s'\n", refId.c_str()); - return nullptr; - } + SkASSERT(jlayer.isObject()); - return AttachImageAsset(*jimage, ctx); + return AttachAssetRef(jlayer, ctx, AttachImageAsset); } sk_sp AttachNullLayer(const json::ValueRef& layer, AttachContext*, float*, float*) { @@ -1268,7 +1275,7 @@ Animation::Animation(const ResourceProvider& resources, AssetMap assets; for (const json::ValueRef asset : json["assets"]) { if (asset.isObject()) { - assets.set(asset["id"].toDefault(SkString()), asset); + assets.set(asset["id"].toDefault(SkString()), { asset, false }); } } -- cgit v1.2.3