High firefox Logic Error 🔧 Commit mapped

Overview

High
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Impacthigh
DescriptionRace condition, use-after-free in the Graphics: CanvasWebGL component
ComponentDOM
Bug ClassLogic Error
Tracker2073969
Fix commit91b817d70c38 (firefox) +26/-5
CISA KEVNot listed
CreditedShu Takahashi of Velcore Consulting Inc.
Disclosed2026-10-13

Changed Functions

FunctionChangeNotes
if
dom/canvas/OffscreenCanvas.cpp
modified
if
dom/canvas/OffscreenCanvasDisplayHelper.cpp
modified
HTMLCanvasElement
dom/canvas/OffscreenCanvasDisplayHelper.h
modified
OffscreenCanvas
dom/canvas/OffscreenCanvasDisplayHelper.h
modified
ThreadSafeWorkerRef
dom/canvas/OffscreenCanvasDisplayHelper.h
modified
WorkerPrivate
dom/canvas/OffscreenCanvasDisplayHelper.h
modified

Files Changed

  • dom/canvas/OffscreenCanvas.cpp
  • dom/canvas/OffscreenCanvasDisplayHelper.cpp
  • dom/canvas/OffscreenCanvasDisplayHelper.h
diff --git a/dom/canvas/OffscreenCanvas.cpp b/dom/canvas/OffscreenCanvas.cpp
index 34d57935a4b..8250ac8f6d4 100644
--- a/dom/canvas/OffscreenCanvas.cpp
+++ b/dom/canvas/OffscreenCanvas.cpp
@@ -213,7 +213,12 @@ void OffscreenCanvas::GetContext(
   // if we need to flush our contents to its ImageContainer for display.
   RefPtr<ThreadSafeWorkerRef> workerRef;
   if (mDisplay) {
-    if (WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate()) {
+    WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
+    if (!mDisplay->MayUpdateContext(workerPrivate, aRv)) {
+      aResult.SetNull();
+      return;
+    }
+    if (workerPrivate) {
       RefPtr<StrongWorkerRef> strongRef = StrongWorkerRef::Create(
           workerPrivate, "OffscreenCanvas::GetContext",
           [display = mDisplay]() { display->DestroyCanvas(); });
@@ -233,10 +238,6 @@ void OffscreenCanvas::GetContext(
       aCx, contextType, aContextOptions, aRv);
   if (!result) {
     aResult.SetNull();
-    if (mDisplay) {
-      mDisplay->UpdateContext(this, nullptr, CanvasContextType::NoContext,
-                              Nothing());
-    }
     return;
   }
 
diff --git a/dom/canvas/OffscreenCanvasDisplayHelper.cpp b/dom/canvas/OffscreenCanvasDisplayHelper.cpp
index 209d4980bc4..cc55e6899b6 100644
--- a/dom/canvas/OffscreenCanvasDisplayHelper.cpp
+++ b/dom/canvas/OffscreenCanvasDisplayHelper.cpp
@@ -117,6 +117,24 @@ RefPtr<layers::ImageContainer> OffscreenCanvasDisplayHelper::GetImageContainer()
   return mImageContainer;
 }
 
+bool OffscreenCanvasDisplayHelper::MayUpdateContext(WorkerPrivate* aWorker,
+                                                    ErrorResult& aRv) {
+  MutexAutoLock lock(mMutex);
+  if (!mOffscreenCanvas) {
+    return true;
+  }
+  if (aWorker) {
+    if (mWorkerRef && mWorkerRef->Private() == aWorker) {
+      return true;
+    }
+  } else if (!mWorkerRef) {
+    return true;
+  }
+  aRv.ThrowInvalidStateError(
+      "Cannot update created context to different thread");
+  return false;
+}
+
 void OffscreenCanvasDisplayHelper::UpdateContext(
     OffscreenCanvas* aOffscreenCanvas, RefPtr<ThreadSafeWorkerRef>&& aWorkerRef,
     CanvasContextType aType, const Maybe<mozilla::ipc::ActorId>& aChildId) {
diff --git a/dom/canvas/OffscreenCanvasDisplayHelper.h b/dom/canvas/OffscreenCanvasDisplayHelper.h
index b2bb00667a8..082c96346b1 100644
--- a/dom/canvas/OffscreenCanvasDisplayHelper.h
+++ b/dom/canvas/OffscreenCanvasDisplayHelper.h
@@ -22,6 +22,7 @@ namespace mozilla::dom {
 class HTMLCanvasElement;
 class OffscreenCanvas;
 class ThreadSafeWorkerRef;
+class WorkerPrivate;
 
 struct OffscreenCanvasDisplayData final {
   mozilla::gfx::IntSize mSize = {0, 0};
@@ -42,6 +43,7 @@ class OffscreenCanvasDisplayHelper final {
 
   RefPtr<layers::ImageContainer> GetImageContainer() const;
 
+  bool MayUpdateContext(WorkerPrivate* aWorker, ErrorResult& aRv);
   void UpdateContext(OffscreenCanvas* aOffscreenCanvas,
                      RefPtr<ThreadSafeWorkerRef>&& aWorkerRef,
                      CanvasContextType aType,
Loading diff…