From 335d947c100e2543b84ab2f1385e8b2ee5458b9a Mon Sep 17 00:00:00 2001 From: Raymond Hill Date: Mon, 11 Nov 2024 15:08:10 -0500 Subject: [PATCH] Fix potential infinite async loop Related issue: https://bugzilla.mozilla.org/show_bug.cgi?id=1929326 As identified by @Rob--W: https://bugzilla.mozilla.org/show_bug.cgi?id=1929326#c9 Truncated or otherwise corrupted asset content in extension storage could lead to infinite async loop causing high CPU usage in uBO and its workers. Likely related to the issue of the asset content returned as `undefined`: https://github.com/gorhill/uBlock/blob/652f1787878ba434c3a65287afcd84082c409397/src/js/cachestorage.js#L98 --- src/js/assets.js | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/js/assets.js b/src/js/assets.js index e1bc4e616..4f02700f8 100644 --- a/src/js/assets.js +++ b/src/js/assets.js @@ -19,18 +19,15 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; +import * as sfp from './static-filtering-parser.js'; -/******************************************************************************/ - -import µb from './background.js'; import { broadcast } from './broadcast.js'; import cacheStorage from './cachestorage.js'; -import { ubolog } from './console.js'; import { i18n$ } from './i18n.js'; import logger from './logger.js'; -import * as sfp from './static-filtering-parser.js'; -import { orphanizeString, } from './text-utils.js'; +import { orphanizeString } from './text-utils.js'; +import { ubolog } from './console.js'; +import µb from './background.js'; /******************************************************************************/ @@ -50,6 +47,9 @@ let remoteServerFriendly = false; /******************************************************************************/ +const hasOwnProperty = (o, p) => + Object.prototype.hasOwnProperty.call(o, p); + const stringIsNotEmpty = s => typeof s === 'string' && s !== ''; const parseExpires = s => { @@ -107,8 +107,8 @@ const resourceTimeFromXhr = xhr => { const resourceTimeFromParts = (parts, time) => { const goodParts = parts.filter(part => typeof part === 'object'); - return goodParts.reduce((acc, part) => - ((part.resourceTime || 0) > acc ? part.resourceTime : acc), + return goodParts.reduce( + (acc, part) => ((part.resourceTime || 0) > acc ? part.resourceTime : acc), time ); }; @@ -246,6 +246,7 @@ const fireNotification = function(topic, details) { assets.fetch = function(url, options = {}) { return new Promise((resolve, reject) => { // Start of executor + /* eslint-disable indent */ const timeoutAfter = µb.hiddenSettings.assetFetchTimeout || 30; const xhr = new XMLHttpRequest(); @@ -322,6 +323,7 @@ assets.fetch = function(url, options = {}) { onErrorEvent.call(xhr); } + /* eslint-enable indent */ // End of executor }); }; @@ -733,7 +735,7 @@ async function assetCacheRead(assetKey, updateReadTime = false) { } if ( bin instanceof Object === false ) { return reportBack(''); } - if ( bin.hasOwnProperty(internalKey) === false ) { return reportBack(''); } + if ( hasOwnProperty(bin, internalKey) === false ) { return reportBack(''); } const entry = assetCacheRegistry[assetKey]; if ( entry === undefined ) { return reportBack(''); } @@ -1277,7 +1279,9 @@ async function diffUpdater() { if ( data.status === 'needtext' ) { ubolog('Diff updater: need text for', data.assetKey); assetCacheRead(data.assetKey).then(result => { - data.text = result.content; + // https://bugzilla.mozilla.org/show_bug.cgi?id=1929326#c9 + // Must never be set to undefined! + data.text = result.content || ''; data.status = undefined; checkAndCorrectDiffPath(data); bc.postMessage(data);