
CVE-2026-74943, Firefox RasterImage में यूज़ आफ्टर फ्री (sec-high)
यह डायरेक्टरी mozilla::image::RasterImage::OnSurfaceDiscarded में एक क्रॉस-थ्रेड यूज़-आफ्टर-फ्री के लिए एक ईमानदार पुनरुत्पादन स्कैफ़ोल्ड रखती है। इसे केवल सिंथेटिक इमेज डेटा का उपयोग करके स्थानीय रूप से डाउनलोड किए गए कमज़ोर Firefox बिल्ड के विरुद्ध चलाने के लिए बनाया गया है। यह कभी भी किसी लाइव या तृतीय-पक्ष सिस्टम को स्पर्श नहीं करता है।
मिलता-जुलता PoC रिपॉज़िटरी: https://github.com/defineid/Revenant
राइटअप: इस पोर्टफ़ोलियो में writeup-rasterimage-uaf.html।
इनकी पुष्टि मूल शोध के दौरान कमज़ोर बिल्ड (libxul.so, Firefox 140.9.0esr) को डिसअसेम्बल करके की गई थी; कमिट की गई स्क्रीनशॉट assets/writeup-uaf-disasm.png वही विश्लेषण है। फ़ंक्शन नाम उस सटीक बिल्ड के लिए आधिकारिक Mozilla Breakpad सिंबल फ़ाइल से आते हैं; शिप किया गया libxul.so स्ट्रिप्ड है। इस PoC पैकेज को इकट्ठा करने वाले वातावरण में इन्हें दोबारा डिसअसेम्बल नहीं किया गया (सत्यापन स्थिति देखें)।
| तथ्य | प्रमाण | स्रोत |
|---|---|---|
कमज़ोर फ़ंक्शन RasterImage::OnSurfaceDiscarded(SurfaceKey const&) है | FUNC 3eba200 16c 0 mozilla::image::RasterImage::OnSurfaceDiscarded(...) | Mozilla सिंबल सर्वर .sym |
this+0xC0 पर प्रारंभिक बाइट रीड (राइटअप: mIsBeingDestroyed) | 3eba20a: cmp BYTE PTR [rdi+0xc0],0x0 जहाँ rdi = this | objdump -d libxul.so |
this+0x40 पर RasterImage रेफ़काउंट पर AddRef | 3eba25a: lock inc QWORD PTR [rbx+0x40] (दो बार जारी), rbx = this | objdump -d libxul.so |
एक 0x20-बाइट रननेबल आवंटित होता है और this को कैप्चर करता है | 3eba264: mov edi,0x20 → call moz_xmalloc@plt; 3eba280: mov QWORD PTR [rax+0x10],rbx | objdump -d libxul.so |
रननेबल को डिस्पैच किया जाता है, फिर this को Release किया जाता है | 3eba298: call QWORD PTR [rcx+0x28] (वर्चुअल डिस्पैच); 3eba29b: lock dec QWORD PTR [rbx+0x40] | objdump -d libxul.so |
रेफ़काउंट 0 पर पहुँचने पर ~RasterImage फिर free चलता है | je 3eba345 → call 3ebbe90 <~RasterImage> → call free@plt | objdump + .sym |
डिस्पैच किया गया रननेबल OnSurfaceDiscarded::$_0 लैम्ब्डा को कैप्चर करता है | FUNC 5279d90 ... RunnableFunction<...OnSurfaceDiscarded(...)::$_0>::Run() | Mozilla सिंबल सर्वर .sym |
| फ़ील्ड | मान |
|---|---|
| CVE | CVE-2026-74943 |
| घटक | Core / Graphics: ImageLib |
| वर्ग | Use-After-Free (CWE-416) |
| गंभीरता | sec-high (वेब-पहुँचनीय मेमोरी सुरक्षा) |
| इसमें ठीक किया गया | Firefox 154 · ESR 140.14 |
| बग | bugzilla.mozilla.org/show_bug.cgi?id=2057308 (सुरक्षा प्रतिबंधित) |
SurfaceCacheImpl::Remove स्वामी इमेज को सूचित करता है कि एक डिकोड किया गया सरफेस डिस्कार्ड कर दिया गया है, और यह OnSurfaceDiscarded को एक कच्चे, गैर-स्वामित्व वाले ImageKey पॉइंटर के माध्यम से कॉल करके करता है, एक डिकोडर / ImageIO थ्रेड पर, सरफेस कैश म्यूटेक्स रखते हुए। कमज़ोर बिल्ड में वह हैंडलर:
this+0xC0 पर एक एकल बाइट फ़्लैग पढ़ता है (cmp BYTE PTR [rdi+0xc0],0x0)।
राइटअप इसे mIsBeingDestroyed के रूप में पहचानता है, जो एक पूर्व शमन उपाय है।this+0x40 पर RasterImage रेफ़काउंट बढ़ाकर this का एक मज़बूत संदर्भ लेता है
(lock inc QWORD PTR [rbx+0x40])। यह एक सादा
add-ref है, न कि परमाणु add-ref-if-nonzero।moz_xmalloc(0x20)-आवंटित करता है एक RunnableFunction जो this को कैप्चर करता है
(mov QWORD PTR [rax+0x10],rbx), इसे एक वैश्विक इवेंट टारगेट पर डिस्पैच करता है
(call QWORD PTR [rcx+0x28]), फिर स्थानीय संदर्भ को रिलीज़ करता है
(lock dec QWORD PTR [rbx+0x40])।चूँकि फ़्लैग पढ़ना और काउंट बढ़ाना एक लॉक-फ़्री रेफ़काउंट के विरुद्ध दो अलग-अलग
ऑपरेशन हैं, वे उस क्षण को पार कर सकते हैं जब मुख्य
थ्रेड अंतिम संदर्भ छोड़ता है। डिकोडर थ्रेड तब शून्य से AddRef करता है,
ऐसी वस्तु को पुनर्जीवित करते हुए जिसका डिस्ट्रक्टर पहले ही प्रतिबद्ध हो चुका है। जब
डिस्ट्रक्टर समाप्त होता है और RasterImage को free करता है, तो कतार में रखा गया रननेबल बाद में मुख्य थ्रेड पर चलता है
और मुक्त स्टोरेज पढ़ता है।
यह फ़िक्स इमेज को सीधे संदर्भित करना बंद कर देता है: OnSurfaceDiscarded अलग से refcounted ProgressTracker के लिए एक
मज़बूत संदर्भ कैप्चर करता है और ट्रैकर के weak back-reference के माध्यम से मुख्य थ्रेड पर इमेज को पुनर्प्राप्त करता है, इसे
atomic add-ref-if-live के साथ प्रमोट करता है; mIsBeingDestroyed फ़्लैग हटा दिया गया है।
कंटेंट प्रोसेस में एक सामान्य वेब पेज surface-cache दबाव पैदा करता है (कई discardable decoded surfaces) जबकि इमेज अनुरोधों का स्वामित्व रखने वाले फ़्रेम को रिलीज़ करता है। किसी क्लिक, अनुमति, एक्सटेंशन या pref परिवर्तन की आवश्यकता नहीं है। रेस डिकोडर थ्रेड की discard सूचना और उसी इमेज के मुख्य थ्रेड के अंतिम रिलीज़ के बीच है।
https://ftp.mozilla.org/pub/firefox/releases/140.9.0esr/।
एक ASAN बिल्ड (Nightly asan या स्थानीय --enable-address-sanitizer
बिल्ड) use-after-free को कभी-कभार होने वाले साइलेंट क्रैश के बजाय एक स्पष्ट रिपोर्ट के रूप में देखने योग्य बनाता है।<canvas> के साथ अपनी स्वयं की इमेज उत्पन्न करता है; यह नेटवर्क से कुछ भी लोड नहीं करता।vulnerable build में trigger.html खोलें, आदर्श रूप से file:// पथ या आपके नियंत्रण वाले
स्थानीय स्टैटिक सर्वर से:
/path/to/firefox --new-instance --profile ./poc-profile ./trigger.html
डिफ़ॉल्ट रूप से ड्राइवर अधिकतम डिकोड/रिलीज़ ओवरलैप के लिए एक सघन माइक्रोटास्क लूप चलाता है। URL में ?tick=N जोड़ने पर यह एक यील्डिंग setTimeout(N) लूप पर स्विच हो जाता है जो उतनी ही तीव्रता से चलता है लेकिन इवेंट लूप को साँस लेने देता है, जिसके कारण एक स्वचालित ड्राइवर पेज के चलते समय उसे स्टेप और स्क्रीनशॉट कर सकता है। कमिट किया गया trigger-running.png ठीक इसी तरह कैप्चर किया गया था, जिसमें स्थानीय 140.11.0esr बिल्ड को Marionette के माध्यम से ?tick=4 के साथ चलाया गया था: यह हार्नेस को लाइव दिखाता है (साइकल और टियरडाउन बढ़ते हुए)। वह बिल्ड पैच किया गया है, इसलिए कोई क्रैश नहीं होता; छवि केवल यह सिद्ध करती है कि ड्राइवर चलता है। हेडलेस पर ऑफ-स्क्रीन छवियाँ पेंट नहीं होतीं, इसलिए वहाँ "images decoded" काउंटर 0 पर रहता है; एक हेडेड कमज़ोर बिल्ड उन्हें डिकोड करता है और वहीं रेस का परीक्षण होता है।
पेज को चलने दें। यह बार-बार कई भिन्न बड़ी छवियों को डिकोड करता है (सरफेस कैश भरने और एविक्शन को बाध्य करने के लिए) जबकि उन्हें रखने वाले DOM सबट्री को टियर डाउन करता है (स्वामी छवि के अंतिम रिलीज़ को चलाने के लिए)। यह डिकोडर थ्रेड पर "surface discarded" और मुख्य थ्रेड पर "last release" के ओवरलैप को अधिकतम करता है। रेस प्रायिकतात्मक होती हैं; इसे चलता रहने दें।
heap-use-after-free देखेंगे जिसका READ फ्रेम
RasterImage::OnSurfaceDiscardedInternal / डिस्पैच किए गए रननेबल के अंदर है, और
freed फ्रेम RasterImage::Release टियरडाउन में है। ASAN के बिना यह
रुक-रुक कर होने वाले कंटेंट-प्रोसेस क्रैश के रूप में सामने आ सकता है।ProgressTracker के कमज़ोर बैक-रेफ़रेंस से होकर जाता है और जब विनाश पहले ही
कमिट हो चुका हो तो नोटिफ़िकेशन को छोड़ देता है।