High firefox Logic Error 🔧 Commit mapped

Overview

High
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Impacthigh
DescriptionOther issue, use-after-free in the Storage: IndexedDB component
ComponentDOM
Bug ClassLogic Error
Tracker2075431
Fix commit712cafdf4ca2 (firefox) +63/-69
CISA KEVNot listed
CreditedAmy Burnett of OpenAI
Disclosed2026-10-27

Changed Functions

FunctionChangeNotes
VersionChangeOp
dom/indexedDB/ActorsParent.cpp
modified
if
dom/indexedDB/ActorsParent.cpp
modified

Files Changed

  • dom/indexedDB/ActorsParent.cpp
diff --git a/dom/indexedDB/ActorsParent.cpp b/dom/indexedDB/ActorsParent.cpp
index 05f7d8a0b0c..08d64cf16b6 100644
--- a/dom/indexedDB/ActorsParent.cpp
+++ b/dom/indexedDB/ActorsParent.cpp
@@ -3068,6 +3068,7 @@ class FactoryOp : public DatabaseOperationBase,
   Maybe<nsString> mDatabaseName;
   Maybe<nsCString> mDatabaseId;
   Maybe<nsString> mDatabaseFilePath;
+  Maybe<nsString> mDatabaseFilenameBase;
   int64_t mDirectoryLockId;
   const PersistenceType mPersistenceType;
   State mState;
@@ -3180,6 +3181,9 @@ class FactoryOp : public DatabaseOperationBase,
   virtual void SendBlockedNotification() = 0;
 
  private:
+  static nsAutoString GetDatabaseFilenameBase(const nsAString& aDatabaseName,
+                                              bool aIsPrivate);
+
   // Test whether this FactoryOp needs to wait for the given op.
   bool MustWaitFor(const FactoryOp& aExistingOp);
 
@@ -3336,7 +3340,6 @@ class DeleteDatabaseOp final : public FactoryRequestOp {
   class VersionChangeOp;
 
   nsString mDatabaseDirectoryPath;
-  nsString mDatabaseFilenameBase;
   uint64_t mPreviousVersion;
 
  public:
@@ -6198,54 +6201,6 @@ uint32_t TelemetryIdForFile(nsIFile* aFile) {
   });
 }
 
-nsAutoString GetDatabaseFilenameBase(const nsAString& aDatabaseName,
-                                     bool aIsPrivate) {
-  nsAutoString databaseFilenameBase;
-
-  if (aIsPrivate) {
-    MOZ_DIAGNOSTIC_ASSERT(gStorageDatabaseNameMutex);
-
-    MutexAutoLock lock(*gStorageDatabaseNameMutex);
-
-    if (!gStorageDatabaseNameHashtable) {
-      gStorageDatabaseNameHashtable = new StorageDatabaseNameHashtable();
-    }
-
-    databaseFilenameBase.Append(
-        gStorageDatabaseNameHashtable->LookupOrInsertWith(aDatabaseName, []() {
-          return NSID_TrimBracketsUTF16(nsID::GenerateUUID());
-        }));
-
-    return databaseFilenameBase;
-  }
-
-  // WARNING: do not change this hash function. See the comment in HashName()
-  // for details.
-  databaseFilenameBase.AppendInt(HashName(aDatabaseName));
-
-  nsAutoCString escapedName;
-  if (!NS_Escape(NS_ConvertUTF16toUTF8(aDatabaseName), escapedName,
-                 url_XPAlphas)) {
-    MOZ_CRASH("Can't escape database name!");
-  }
-
-  const char* forwardIter = escapedName.BeginReading();
-  const char* backwardIter = escapedName.EndReading() - 1;
-
-  nsAutoCString substring;
-  while (forwardIter <= backwardIter && substring.Length() < 21) {
-    if (substring.Length() % 2) {
-      substring.Append(*backwardIter--);
-    } else {
-      substring.Append(*forwardIter++);
-    }
-  }
-
-  databaseFilenameBase.AppendASCII(substring.get(), substring.Length());
-
-  return databaseFilenameBase;
-}
-
 const CommonIndexOpenCursorParams& GetCommonIndexOpenCursorParams(
     const OpenCursorParams& aParams) {
   switch (aParams.type()) {
@@ -15159,14 +15114,15 @@ nsresult FactoryOp::Open() {
   }
 
   if (mDatabaseName.isSome()) {
+    mDatabaseFilenameBase = Some(GetDatabaseFilenameBase(
+        mDatabaseName.ref(), mOriginMetadata.mIsPrivate));
     nsCString databaseId;
 
     QuotaManager::GetStorageId(mPersistenceType, mOriginMetadata.mOrigin,
                                Client::IDB, databaseId);
 
     databaseId.Append('*');
-    databaseId.Append(NS_ConvertUTF16toUTF8(GetDatabaseFilenameBase(
-        mDatabaseName.ref(), mOriginMetadata.mIsPrivate)));
+    databaseId.Append(NS_ConvertUTF16toUTF8(*mDatabaseFilenameBase));
 
     mDatabaseId = Some(std::move(databaseId));
 
@@ -15181,10 +15137,8 @@ nsresult FactoryOp::Open() {
           QM_TRY(MOZ_TO_RESULT(dbFile->Append(
               NS_LITERAL_STRING_FROM_CSTRING(IDB_DIRECTORY_NAME))));
 
-          QM_TRY(MOZ_TO_RESULT(dbFile->Append(
-              GetDatabaseFilenameBase(mDatabaseName.ref(),
-                                      mOriginMetadata.mIsPrivate) +
-              kSQLiteSuffix)));
+          QM_TRY(MOZ_TO_RESULT(
+              dbFile->Append(*mDatabaseFilenameBase + kSQLiteSuffix)));
 
           QM_TRY_RETURN(
               MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(nsString, dbFile, GetPath));
@@ -15410,6 +15364,54 @@ nsresult FactoryOp::SendVersionChangeMessages(
   return NS_OK;
 }  // namespace indexedDB
 
+nsAutoString FactoryOp::GetDatabaseFilenameBase(const nsAString& aDatabaseName,
+                                                bool aIsPrivate) {
+  nsAutoString databaseFilenameBase;
+
+  if (aIsPrivate) {
+    MOZ_DIAGNOSTIC_ASSERT(gStorageDatabaseNameMutex);
+
+    MutexAutoLock lock(*gStorageDatabaseNameMutex);
+
+    if (!gStorageDatabaseNameHashtable) {
+      gStorageDatabaseNameHashtable = new StorageDatabaseNameHashtable();
+    }
+
+    databaseFilenameBase.Append(
+        gStorageDatabaseNameHashtable->LookupOrInsertWith(aDatabaseName, []() {
+          return NSID_TrimBracketsUTF16(nsID::GenerateUUID());
+        }));
+
+    return databaseFilenameBase;
+  }
+
+  // WARNING: do not change this hash function. See the comment in HashName()
+  // for details.
+  databaseFilenameBase.AppendInt(HashName(aDatabaseName));
+
+  nsAutoCString escapedName;
+  if (!NS_Escape(NS_ConvertUTF16toUTF8(aDatabaseName), escapedName,
+                 url_XPAlphas)) {
+    MOZ_CRASH("Can't escape database name!");
+  }
+
+  const char* forwardIter = escapedName.BeginReading();
+  const char* backwardIter = escapedName.EndReading() - 1;
+
+  nsAutoCString substring;
+  while (forwardIter <= backwardIter && substring.Length() < 21) {
+    if (substring.Length() % 2) {
+      substring.Append(*backwardIter--);
+    } else {
+      substring.Append(*forwardIter++);
+    }
+  }
+
+  databaseFilenameBase.AppendASCII(substring.get(), substring.Length());
+
+  return databaseFilenameBase;
+}
+
 bool FactoryOp::MustWaitFor(const FactoryOp& aExistingOp) {
   AssertIsOnOwningThread();
 
@@ -15641,12 +15643,9 @@ nsresult OpenDatabaseOp::DoDatabaseWork() {
 #endif
   }
 
-  const auto databaseFilenameBase =
-      GetDatabaseFilenameBase(databaseName, mOriginMetadata.mIsPrivate);
-
   QM_TRY_INSPECT(const auto& markerFile,
                  CloneFileAndAppend(*dbDirectory, kIdbDeletionMarkerFilePrefix +
-                                                      databaseFilenameBase));
+                                                      *mDatabaseFilenameBase));
 
   QM_TRY_INSPECT(const bool& exists,
                  MOZ_TO_RESULT_INVOKE_MEMBER(markerFile, Exists));
@@ -15656,14 +15655,14 @@ nsresult OpenDatabaseOp::DoDatabaseWork() {
     // previous operation.
     // Note: only update usage to the QuotaManager when mEnforcingQuota == true
     QM_TRY(MOZ_TO_RESULT(RemoveDatabaseFilesAndDirectory(
-        *dbDirectory, databaseFilenameBase,
+        *dbDirectory, *mDatabaseFilenameBase,
         mEnforcingQuota ? quotaManager : nullptr, persistenceType,
         mOriginMetadata, databaseName)));
   }
 
   QM_TRY_INSPECT(
       const auto& dbFile,
-      CloneFileAndAppend(*dbDirectory, databaseFilenameBase + kSQLiteSuffix));
+      CloneFileAndAppend(*dbDirectory, *mDatabaseFilenameBase + kSQLiteSuffix));
 
   mTelemetryId = TelemetryIdForFile(dbFile);
 
@@ -15679,7 +15678,7 @@ nsresult OpenDatabaseOp::DoDatabaseWork() {
 
   QM_TRY_INSPECT(
       const auto& fmDirectory,
-      CloneFileAndAppend(*dbDirectory, databaseFilenameBase +
+      CloneFileAndAppend(*dbDirectory, *mDatabaseFilenameBase +
                                            kFileManagerDirectoryNameSuffix));
 
   IndexedDatabaseManager* const idm = IndexedDatabaseManager::Get();
@@ -16832,8 +16831,6 @@ nsresult DeleteDatabaseOp::DoDatabaseWork() {
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
-  const nsAString& databaseName = mCommonParams.metadata().name();
-
   QuotaManager* const quotaManager = QuotaManager::Get();
   MOZ_ASSERT(quotaManager);
 
@@ -16846,12 +16843,9 @@ nsresult DeleteDatabaseOp::DoDatabaseWork() {
   QM_TRY_UNWRAP(mDatabaseDirectoryPath, MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(
                                             nsString, directory, GetPath));
 
-  mDatabaseFilenameBase =
-      GetDatabaseFilenameBase(databaseName, mOriginMetadata.mIsPrivate);
-
   QM_TRY_INSPECT(
       const auto& dbFile,
-      CloneFileAndAppend(*directory, mDatabaseFilenameBase + kSQLiteSuffix));
+      CloneFileAndAppend(*directory, *mDatabaseFilenameBase + kSQLiteSuffix));
 
 #ifdef DEBUG
   {
@@ -17025,7 +17019,7 @@ nsresult DeleteDatabaseOp::VersionChangeOp::RunOnIOThread() {
   }
 
   nsresult rv = RemoveDatabaseFilesAndDirectory(
-      *directory, mDeleteDatabaseOp->mDatabaseFilenameBase, quotaManager,
+      *directory, *mDeleteDatabaseOp->mDatabaseFilenameBase, quotaManager,
       persistenceType, mDeleteDatabaseOp->mOriginMetadata,
       mDeleteDatabaseOp->mCommonParams.metadata().name());
   if (NS_WARN_IF(NS_FAILED(rv))) {
Loading diff…