High firefox Logic Error 🔧 Commit mapped

Overview

High
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Impacthigh
DescriptionUninitialized memory in the Networking component
ComponentNetworking
Bug ClassLogic Error
Tracker2082139
Fix commitd03c3288bf1a (firefox) +25/-7
CISA KEVNot listed
CreditedOpenAI Codex Security (kylebot)
Disclosed2026-10-27

Changed Functions

FunctionChangeNotes
for
netwerk/cache2/CacheFile.cpp
modified
if
netwerk/cache2/CacheFile.cpp
modified

Files Changed

  • netwerk/cache2/CacheFile.cpp
  • netwerk/cache2/CacheFileChunk.cpp
  • netwerk/cache2/CacheFileInputStream.h
diff --git a/netwerk/cache2/CacheFile.cpp b/netwerk/cache2/CacheFile.cpp
index 4c2a4476343..018017bf853 100644
--- a/netwerk/cache2/CacheFile.cpp
+++ b/netwerk/cache2/CacheFile.cpp
@@ -2191,16 +2191,12 @@ void CacheFile::RemoveOutput(CacheFileOutputStream* aOutput, nsresult aStatus) {
 
   mOutput = nullptr;  // XXX should this be after NotifyCloseListener?
 
-  // Cancel all queued chunk and update listeners that cannot be satisfied
-  NotifyListenersAboutOutputRemoval();
-
-  if (!mMemoryOnly) WriteMetadataIfNeededLocked();
+  bool failed = NS_FAILED(aStatus) && aStatus != NS_BASE_STREAM_CLOSED;
 
   // Make sure the CacheFile status is set to a failure when the output stream
   // is closed with a fatal error.  This way we propagate correctly and w/o any
   // windows the failure state of this entry to end consumers.
-  if (NS_SUCCEEDED(mStatus) && NS_FAILED(aStatus) &&
-      aStatus != NS_BASE_STREAM_CLOSED) {
+  if (NS_SUCCEEDED(mStatus) && failed) {
     if (aOutput->IsAlternativeData()) {
       MOZ_ASSERT(mAltDataOffset != -1);
       // If there is no alt-data input stream truncate only alt-data, otherwise
@@ -2233,6 +2229,25 @@ void CacheFile::RemoveOutput(CacheFileOutputStream* aOutput, nsresult aStatus) {
     }
   }
 
+  // Propagate the failure to alt-data readers.
+  if (failed && aOutput->IsAlternativeData() && NS_FAILED(mStatus)) {
+    for (CacheFileInputStream* input : mInputs) {
+      if (input->IsAlternativeData()) {
+        // Closing may drop the last outside reference to an input; keep it
+        // alive until the lock is released so RemoveInput() isn't reentered.
+        ReleaseOutsideLock(RefPtr<nsIInputStream>(input));
+        input->CloseWithStatusLocked(mStatus);
+      }
+    }
+  }
+
+  // Cancel all queued chunk and update listeners that cannot be satisfied
+  NotifyListenersAboutOutputRemoval();
+
+  if (!mMemoryOnly) {
+    WriteMetadataIfNeededLocked();
+  }
+
   // Notify close listener as the last action
   aOutput->NotifyCloseListener();
 
diff --git a/netwerk/cache2/CacheFileChunk.cpp b/netwerk/cache2/CacheFileChunk.cpp
index ff421e9b361..0ef21c4a8a7 100644
--- a/netwerk/cache2/CacheFileChunk.cpp
+++ b/netwerk/cache2/CacheFileChunk.cpp
@@ -498,7 +498,8 @@ void CacheFileChunk::CancelWait(CacheFileChunkListener* aCallback) {
 
   LOG(("CacheFileChunk::CancelWait() [this=%p, listener=%p]", this, aCallback));
 
-  MOZ_ASSERT(IsReady());
+  // The chunk may have failed while the listener was waiting.
+  MOZ_ASSERT(mState == READY || mState == WRITING);
 
   uint32_t i;
   for (i = 0; i < mUpdateListeners.Length(); i++) {
diff --git a/netwerk/cache2/CacheFileInputStream.h b/netwerk/cache2/CacheFileInputStream.h
index 36a56803b73..0d77f8eb55b 100644
--- a/netwerk/cache2/CacheFileInputStream.h
+++ b/netwerk/cache2/CacheFileInputStream.h
@@ -44,6 +44,8 @@ class CacheFileInputStream : public nsIAsyncInputStream,
   };
 
  private:
+  friend class CacheFile;
+
   virtual ~CacheFileInputStream();
 
   void CloseWithStatusLocked(nsresult aStatus);
Loading diff…