
बाइनरी इंस्ट्रुमेंटेशन और फ़ज़िंग के माध्यम से पाए गए कुछ बग
media-gen दो मीडिया-पार्सर टेस्ट केस बनाने के लिए एक छोटा, कम निर्भरता वाला Rust कमांड-लाइन टूल है। यह मौजूदा वैध मीडिया फ़ाइलों को इन-प्लेस संपादित करता है; यह FFmpeg को इनवोक नहीं करता, ब्राउज़र को पैच नहीं करता, किसी सर्वर से संपर्क नहीं करता, या कुछ भी अपलोड नहीं करता।
WebM केस में पुराने one-buffer-delayed Vorbis पथ और वर्तमान immediate-discard पथ दोनों के लिए एक ब्रिज लेआउट शामिल है। चेक-इन किए गए शॉर्ट सैंपल को Discord Desktop 1.0.9257 (Electron 42.11.1 / Chromium 148.0.7778.280) और Chrome 153.0.8010.48 के साथ मान्य किया गया था। M4A केस पिन किए गए Discord/FFmpeg बिल्ड के लिए विशिष्ट बना हुआ है। अन्य रिलीज़ इन फ़ाइलों को अस्वीकार कर सकती हैं, उन्हें सुरक्षित रूप से संभाल सकती हैं, या अलग तरीके से विफल हो सकती हैं।
| केस | इनपुट | प्रभावित बिल्ड में प्रभाव | ट्रिगर |
|---|
| WebM/Vorbis discard bridge | A_VORBIS ट्रैक वाला मौजूदा WebM | दोनों परीक्षण किए गए discard मोड पर Chromium के AudioDiscardHelper रिलीज़ चेक में रेंडरर 0x80000003 (STATUS_BREAKPOINT) के साथ समाप्त होता है | प्लेबैक/डिकोड; केवल मेटाडेटा लोडिंग पर्याप्त नहीं है |
M4A constant stsz count | मौजूदा fast-start AAC/M4A सीड | मेटाडेटा लोड करते समय रेंडरर अस्थायी रूप से लगभग 6.6 GB (6.16 GiB) निजी मेमोरी आवंटित करता है | ऑडियो एलिमेंट के preload="none" से मेटाडेटा में बदलने के बाद मेटाडेटा लोड |
ये denial-of-service/resource-consumption टेस्ट केस हैं, प्रदर्शित code-execution exploits नहीं। इन्हें केवल एक पृथक, सीमित टेस्ट वातावरण में चलाएँ।
media-gen प्रतिलिपि-निर्माण परत है, यह नहीं कि इन केसों की खोज कैसे हुई। कठिन हिस्सा एक बड़े नेटिव Discord executable और उसकी बंडल की गई मीडिया लाइब्रेरीज़ के भीतर व्यवहार को खोजना और सिद्ध करना था। blare2 ने सटीक रनटाइम की एक पृथक प्रति को फिर से लिखकर और संकीर्ण प्रोब्स को इंस्टॉल किए गए एप्लिकेशन को बदले बिना निष्पादन का निरीक्षण करने की अनुमति देकर इसे व्यावहारिक बनाया।
WebM केस के लिए, blare2 का सिमेंटिक प्रोब ठीक AudioDiscardHelper::ProcessBuffers चेक पर रुका और विफल स्थिति दर्ज की: discarded_frames = 129 और decoder_delay = 128। उस अवलोकन के बिना, STATUS_BREAKPOINT के साथ रेंडरर का बाहर निकलना केवल एक सामान्य रिलीज़ assertion की पहचान करता; यह स्थापित नहीं करता कि कौन सा मीडिया invariant विफल हुआ या क्या तैयार की गई पैडिंग वास्तव में उस तक पहुँची।
M4A केस के लिए, बड़े आवंटन अस्थायी होते हैं और सामान्य प्रोसेस सैंपल लिए जाने से पहले गायब हो सकते हैं। blare2 की सटीक-रनटाइम कवरेज और लक्षित इंस्ट्रुमेंटेशन, उच्च-आवृत्ति प्रोसेस सैंपलिंग और डिसअसेम्बली के साथ मिलकर, दिखाया कि छोटी फ़ाइल MOV sample-table builder तक पहुँची और घोषित count ने AVIndexEntry और timing-table आवंटन को स्केल किया। इसने इस मुद्दे को सामान्य AAC डिकोड विफलता या भ्रामक file-size/OOM सहसंबंध से अलग किया। केवल व्यापक function-entry कवरेज पर्याप्त नहीं था: low- और high-count फ़ाइलें समान फ़ंक्शन्स का पालन करती थीं, जबकि उनके आवंटन आकार बिल्कुल अलग थे।
blare2 ने कंटेनर विश्लेषण, स्रोत समीक्षा, या नियंत्रणों को प्रतिस्थापित नहीं किया, और इसने यह सिद्ध नहीं किया कि Discord का प्रोडक्शन upload/CDN पथ इन बाइट्स को संरक्षित करता है। इसका मूल्य रनटाइम एट्रिब्यूशन था: इसने संदिग्ध पार्सर व्यवहार को एक सटीक विफल स्थिति और एक तर्कसंगत आवंटन स्पष्टीकरण के साथ एक प्रतिलिपि-योग्य, संस्करण-पिन किए गए निष्कर्ष में बदल दिया। इस प्रकार के बाइनरी इंस्ट्रुमेंटेशन के बिना, इन दो केसों को खोजना काफी धीमा और मान्य करना बहुत कठिन होता।
रिपॉज़िटरी रूट से:
cargo build --release -p media-gen
बाइनरी target/release/media-gen है (Windows पर media-gen.exe)। जनरेटर को स्वयं केवल Rust और Cargo.toml में निर्भरताओं की आवश्यकता है।
cargo run --release -p media-gen -- --help
cargo run --release -p media-gen -- webm --help
cargo run --release -p media-gen -- m4a --help
Matroska negative DiscardPadding एक Vorbis front skip बन जाता है। Chromium का पुराना Vorbis पथ उस मेटाडेटा को एक एन्कोडेड पैकेट से विलंबित करता है; वर्तमान Chromium इसे वर्तमान डिकोडेड आउटपुट पर लागू करता है और पैकेट 0 का मेटाडेटा तब छोड़ देता है जब वह priming पैकेट कोई PCM उत्सर्जित नहीं करता। पैकेट 0 और 1 में एक बड़े skip को दोहराना दोनों व्यवहारों को जोड़ता है:
| ऑडियो पैकेट | डिकोडेड PCM | Front skip |
|---|---|---|
| 0 | कोई नहीं (Vorbis priming) | 577 फ़्रेम |
| 1 | 576 फ़्रेम | 577 फ़्रेम |
| 2 | 1,024 फ़्रेम | 1 फ़्रेम |
ट्रैक में 128-फ़्रेम CodecDelay है। पुराने delayed मोड में, पैकेट 0 का 577-फ़्रेम skip पैकेट 1 पर लागू होता है। वर्तमान मोड में, पैकेट 0 का skip छोड़ दिया जाता है और पैकेट 1 का समान skip सीधे लागू होता है। किसी भी तरह, decoder-delay ऑफ़सेट के बाद केवल 448 फ़्रेम हटाए जा सकते हैं, इसलिए 129 फ़्रेम पैकेट 2 में चले जाते हैं। इसका सकारात्मक front skip Chromium के रिलीज़ चेक तक पहुँचता है जब वे 129 फ़्रेम पहले ही हटाए जा चुके होते हैं। आवश्यक invariant discarded_frames <= decoder_delay है; 129 <= 128 विफल होता है और रेंडरर को समाप्त कर देता है।
जनरेटर Vorbis setup हेडर पार्स करता है, पैकेट 1 और 2 के डिकोडेड आकार की गणना करता है, और ब्रिज व्यवहार्य न होने पर fail closed करता है। फिर यह:
SimpleBlock एलिमेंट्स को BlockGroup एलिमेंट्स में परिवर्तित करता है;DiscardPadding और पैकेट 2 पर सकारात्मक one-frame ट्रिगर लिखता है;SeekHead, Cues, और प्रभावित cluster CRC एलिमेंट्स को बदल देता है ताकि फिर से लिखा गया कंटेनर पार्स करने योग्य बना रहे।मैनिफ़ेस्ट immediate और delayed पथों को अलग-अलग रिपोर्ट करता है। चेक-इन किए गए सैंपल के लिए, दोनों पथ पैकेट 2 को चेक पैकेट के रूप में नामित करते हैं और expected_carry_frames: 129 और expected_check_fails: true रिपोर्ट करते हैं।
रिपॉज़िटरी में एक 43 ms, 4,185-बाइट कंट्रोल WebM है:
cargo run --release -- webm \
--input samples/short-vorbis-dual-control.webm \
--output .build/short-vorbis-dual-crash.webm \
--manifest .build/short-vorbis-dual-crash.json \
--force
इनपुट में होना चाहिए:
A_VORBIS ट्रैक;CodecDelay (सामान्यतः ट्रैक से पढ़ा जाता है); औरउपयोगी विकल्प हैं --trigger-skip, --codec-delay, और --sample-rate। --second-skip नाम बदले गए --trigger-skip विकल्प के लिए एक उपनाम बना हुआ है। डिफ़ॉल्ट ज्ञात विफल स्थिति के लिए आवश्यक मान हैं। कमांड JSON रिपोर्ट को stdout पर प्रिंट करता है और जब वह विकल्प दिया जाता है तो वही रिपोर्ट --manifest पर लिखता है।
चेक-इन किया गया उम्मीदवार 43 ms और 4,206 बाइट है। इसका SHA-256 है:
a0ab9e146c629f037b86612addc1ab6fff9200711d45aa5f5edbb9576cc206ac
यदि इनपुट, पैकेट विंडो, या विकल्प बदलते हैं तो आउटपुट हैश बदलने की अपेक्षा है।
M4A केस एन्कोडेड AAC पेलोड के बजाय एक वैध MP4 sample-table आकार का दुरुपयोग करता है। जनरेटर एक सीड को इस प्रकार बदलता है:
stsz sample-size array को sample_size = 1 से बदल देता है।stsz, पहले stsc run, और पहले stts run में घोषित sample count को समान बड़े मान पर सेट करता है।stco offset की मरम्मत करता है ताकि one-byte AAC पेलोड अभी भी mdat के अंदर इंगित करे।पिन किया गया FFmpeg demuxer अपनी index और timing tables बनाते समय घोषित count को आधिकारिक मानता है। प्रासंगिक संरचनाएँ AVIndexEntry के लिए प्रति घोषित sample लगभग 24 बाइट और timing data के लिए प्रति sample 12 बाइट उपयोग करती हैं: कुल मिलाकर प्रति count entry 36 बाइट। परीक्षण किए गए बिल्ड में अधिकतम स्वीकृत count 178,956,969 (0x0AAAAAA9) है, जो अनुमानित है:
178,956,969 * 24 = 4,294,967,256 bytes
178,956,969 * 12 = 2,147,483,628 bytes
combined = 6,442,450,884 bytes
सटीक Discord रेंडरर मेटाडेटा लोड करते समय 6,614,761,472-बाइट निजी-मेमोरी शिखर तक पहुँचा। आसन्न count 178,956,970 पिन किए गए FFmpeg सीमा द्वारा अस्वीकार कर दिया जाता है और सामान्य मेमोरी के करीब रहा। यह अनियंत्रित संसाधन खपत (CWE-400) है, न कि देखा गया integer-wrap, negative-size allocation, या out-of-bounds write। वास्तविक AAC पेलोड को काटा जा सकता है; बड़े आवंटन तक पहुँचने के लिए सफल प्लेबैक आवश्यक नहीं है।
जनरेटर जानबूझकर AAC encoder एम्बेड करने के बजाय एक सीड स्वीकार करता है। एक fast-start AAC/M4A फ़ाइल का उपयोग करें जिसमें एक स्पष्ट stsz table, एक stsc run, एक या अधिक stts entries, और stco chunk offsets हों। यदि आवश्यक संरचना अनुपस्थित है तो यह fail closed करता है।
cargo run --release -p media-gen -- m4a \
--input path/to/base-faststart.m4a \
--output .build/media-gen/constant-stsz.m4a \
--manifest .build/media-gen/constant-stsz.json \
--force
डिफ़ॉल्ट --sample-count 178956969 है, जो पिन किए गए बिल्ड में अधिकतम स्वीकृत मान है। low-memory smoke test के लिए छोटा मान उपयोग करें, उदाहरण के लिए:
cargo run --release -p media-gen -- m4a \
--input path/to/base-faststart.m4a \
--output .build/media-gen/constant-stsz-32000000.m4a \
--sample-count 32000000 \
--force
--sample-count 178956970 एक उपयोगी आसन्न rejection control है, ट्रिगर करने वाला मान नहीं। वैकल्पिक --moov-at-end फ़्लैग moov को mdat के बाद ले जाता है और stco/co64 को अपडेट करता है; यह तब उपयोगी है जब ऐसी फ़ाइल का परीक्षण किया जा रहा हो जिसके भौतिक AAC बाइट्स उसके मेटाडेटा से पहले आते हैं, लेकिन यह आवंटन तंत्र के लिए आवश्यक नहीं है।
उस लेआउट को स्पष्ट रूप से बनाने के लिए:
cargo run --release -p media-gen -- m4a \
--input path/to/base-faststart.m4a \
--output .build/media-gen/constant-stsz-moov-end.m4a \
--moov-at-end \
--force
मेल खाते आर्टिफ़ैक्ट्स हैं
samples/short-vorbis-dual-control.webm,
samples/short-vorbis-dual-crash.webm,
और samples/short-vorbis-dual-crash.json।