
CVE-2026-74943 · Firefox RasterImage에서 해제 후 사용 (sec-high)
심각도: 높음(sec high). CWE 416. Firefox 154 및 ESR 140.14에서 수정됨. Bugzilla 2057308. 일반 웹 페이지에서 사용자 상호작용 없이 도달 가능.
Firefox는 디코딩된 이미지 서피스를 SurfaceCache에 보관합니다. 캐시는 소유 이미지에 대한 원시 비소유 포인터를 보관합니다. 서피스가 축출되면 캐시는 디코더 스레드에서 해당 이미지에 알림을 보냅니다. 알림은 mIsBeingDestroyed 원자적 플래그를 읽은 후에만 RefPtr<RasterImage> image = this를 획득했습니다. 플래그를 읽는 것과 참조를 획득하는 것은 별개의 두 작업입니다. 메인 스레드는 그 사이에 마지막 참조를 해제할 수 있습니다. 소멸 중인 객체가 부활한 다음 해제된 이후에 읽힙니다.
Decoder thread (holds the SurfaceCache lock) Main thread
OnSurfaceDiscarded reads mIsBeingDestroyed = false
Release drops the refcount to zero and commits delete
~RasterImage sets the flag then blocks on the cache lock
RefPtr image = this (AddRef from zero to one)
queues the runnable and releases the lock
the destructor finishes and frees the 248 byte object
the runnable runs and reads freed mProgressTracker ==> use after free
이전 수정에서 추가된 플래그는 경쟁 구간을 좁힐 뿐입니다. 완전히 없애지는 못합니다. 플래그가 false로 관측된다고 해서 참조 카운트가 여전히 0보다 크다는 것을 증명하지 못합니다. 플래그는 소멸자 내부에서 카운트가 이미 0에 도달한 이후에 설정되기 때문입니다.
이 버그를 유발하는 두 명령어는 컴파일된 함수에 그대로 드러납니다. 플래그 검사와 this에 대한 참조 카운트 증가는 분리되어 있습니다.

영향을 받는 버전의 ASAN 빌드를 사용하세요. prefs.js의 환경 설정을 적용하여 서피스 캐시를 아주 작게 유지하고 디코더 스레드가 서피스를 계속 축출하게 하세요. uaf-reduced.html을 로드하고 반복 실행되도록 두세요. 이는 스레드 간 타이밍 경합이므로 간헐적으로 재현됩니다.
AddressSanitizer: heap-use-after-free
READ of size 8, 8 bytes into a freed 248-byte RasterImage
use : RasterImage::OnSurfaceDiscardedInternal (main thread)
freed : RasterImage::Release() via imgRequest teardown
alloc : ImageFactory::CreateRasterImage() on the ImageIO thread
콘텐츠 프로세스에서 힙 use after free가 발생합니다. 웹 페이지에서 도달할 수 있으며 클릭이나 권한이 필요 없습니다. 테스트한 빌드에서는 제어된 실행이 입증되지 않았습니다. 객체는 부활한 후 나중에 두 번째로 해제됩니다.
OnSurfaceDiscarded는 더 이상 이미지를 참조하지 않습니다. 별도로 참조 카운트되는 ProgressTracker에 강한 참조를 캡처하고, 트래커의 약한 역참조(weak back reference)를 통해 메인 스레드에서 이미지를 복구합니다. 복구는 객체가 살아 있으면 원자적 add를 사용합니다. 더 이상 사용되지 않는 플래그는 제거되었습니다.
Abdulaziz Alasaiqah · https://azoz.my/writeups.html