
Einige Fehler, die durch binäre Instrumentierung und Fuzzing gefunden wurden
media-gen ist ein kleines, abhängigkeitsarmes Rust-Kommandozeilenwerkzeug zum Erstellen zweier Media-Parser-Testfälle. Es bearbeitet vorhandene gültige Mediendateien direkt; es ruft kein FFmpeg auf, patcht keinen Browser, kontaktiert keinen Server und lädt nichts hoch.
Der WebM-Fall enthält ein Bridge-Layout sowohl für den älteren, um einen Puffer verzögerten Vorbis-Pfad als auch für den aktuellen Immediate-Discard-Pfad. Das eingecheckte kurze Beispiel wurde mit Discord Desktop 1.0.9257 (Electron 42.11.1 / Chromium 148.0.7778.280) und Chrome 153.0.8010.48 validiert. Der M4A-Fall bleibt spezifisch für den gepinnten Discord/FFmpeg-Build. Andere Releases können diese Dateien ablehnen, sicher behandeln oder anders fehlschlagen.
| Fall | Eingabe | Wirkung im betroffenen Build | Auslöser |
|---|
| WebM/Vorbis Discard-Bridge | Vorhandenes WebM mit einem A_VORBIS-Track | Renderer beendet sich mit 0x80000003 (STATUS_BREAKPOINT) in Chromiums AudioDiscardHelper-Release-Check bei beiden getesteten Discard-Modi | Wiedergabe/Dekodierung; alleiniges Laden von Metadaten ist nicht ausreichend |
M4A konstanter stsz-Zähler | Vorhandener Fast-Start-AAC/M4A-Seed | Renderer allokiert vorübergehend etwa 6,6 GB (6,16 GiB) privaten Speicher beim Laden der Metadaten | Metadaten-Laden, nachdem das Audio-Element von preload="none" auf Metadaten wechselt |
Dies sind Denial-of-Service-/Ressourcenverbrauchs-Testfälle, keine nachgewiesenen Code-Execution-Exploits. Führen Sie sie nur in einer isolierten, begrenzten Testumgebung aus.
media-gen ist die Reproduzierbarkeitsschicht, nicht der Weg, auf dem diese Fälle entdeckt wurden. Der schwierige Teil bestand darin, das Verhalten in einer großen nativen Discord-Executable und ihren gebündelten Medienbibliotheken zu finden und zu beweisen. blare2 machte dies praktikabel, indem es eine isolierte Kopie der exakten Laufzeitumgebung umschrieb und enge Sonden ermöglichte, die Ausführung zu beobachten, ohne die installierte Anwendung zu verändern.
Für den WebM-Fall stoppte blare2s semantische Sonde exakt am AudioDiscardHelper::ProcessBuffers-Check und zeichnete den fehlerhaften Zustand auf: discarded_frames = 129 und decoder_delay = 128. Ohne diese Beobachtung würde ein Renderer-Exit mit STATUS_BREAKPOINT nur eine generische Release-Assertion identifizieren; es würde nicht feststellen, welche Medieninvariante verletzt wurde oder ob das präparierte Padding sie tatsächlich erreicht hat.
Für den M4A-Fall sind die großen Allokationen vorübergehend und können verschwinden, bevor eine normale Prozess-Stichprobe genommen wird. blare2s Exact-Runtime-Coverage und gezielte Instrumentierung, kombiniert mit hochfrequentem Prozess-Sampling und Disassembly, zeigten, dass die winzige Datei den MOV-Sample-Table-Builder erreichte und dass der deklarierte Zähler AVIndexEntry- und Timing-Table-Allokationen skalierte. Dies trennte das Problem von einem gewöhnlichen AAC-Dekodierungsfehler oder einer irreführenden Dateigrößen-/OOM-Korrelation. Breite Function-Entry-Coverage allein war nicht ausreichend: Die Dateien mit niedrigem und hohem Zähler durchliefen dieselben Funktionen, während ihre Allokationsgrößen radikal unterschiedlich waren.
blare2 ersetzte weder Container-Analyse noch Quellcode-Review oder Kontrollen, und es bewies nicht, dass Discords Produktions-Upload-/CDN-Pfad diese Bytes bewahrt. Sein Wert lag in der Laufzeit-Attribution: Es verwandelte verdächtiges Parser-Verhalten in einen reproduzierbaren, versionsgepinnten Befund mit einem exakten Fehlerzustand und einer belastbaren Allokationserklärung. Ohne Binärinstrumentierung dieser Art wäre das Finden dieser beiden Fälle erheblich langsamer und viel schwieriger zu validieren gewesen.
Vom Repository-Stammverzeichnis aus:
cargo build --release -p media-gen
Die Binärdatei ist target/release/media-gen (media-gen.exe unter Windows). Der Generator selbst benötigt nur Rust und die Abhängigkeiten in 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-negatives DiscardPadding wird zu einem Vorbis-Front-Skip. Chromiums älterer Vorbis-Pfad verzögert diese Metadaten um ein kodiertes Paket; aktuelles Chromium wendet sie auf die aktuelle dekodierte Ausgabe an und verwirft die Metadaten von Paket 0, wenn dieses Priming-Paket kein PCM ausgibt. Das Wiederholen eines großen Skips über die Pakete 0 und 1 hinweg überbrückt die beiden Verhaltensweisen:
| Audio-Paket | Dekodiertes PCM | Front-Skip |
|---|---|---|
| 0 | keines (Vorbis-Priming) | 577 Frames |
| 1 | 576 Frames | 577 Frames |
| 2 | 1.024 Frames | 1 Frame |
Der Track hat eine CodecDelay von 128 Frames. Im älteren verzögerten Modus wird der 577-Frame-Skip von Paket 0 auf Paket 1 angewendet. Im aktuellen Modus wird der Skip von Paket 0 verworfen und der identische Skip von Paket 1 direkt angewendet. In beiden Fällen können nach dem Decoder-Delay-Offset nur 448 Frames entfernt werden, sodass 129 Frames in Paket 2 übertragen werden. Sein positiver Front-Skip erreicht Chromiums Release-Check, nachdem diese 129 Frames bereits entfernt wurden. Die erforderliche Invariante ist discarded_frames <= decoder_delay; 129 <= 128 schlägt fehl und beendet den Renderer.
Der Generator parst die Vorbis-Setup-Header, berechnet die dekodierten Größen der Pakete 1 und 2 und schlägt fehl (fail closed), es sei denn, die Bridge ist tragfähig. Er führt dann Folgendes aus:
SimpleBlock-Elemente in BlockGroup-Elemente;DiscardPadding auf die Pakete 0 und 1 und einen positiven Ein-Frame-Trigger auf Paket 2;SeekHead-, Cues- und betroffene Cluster-CRC-Elemente, damit der umgeschriebene Container parsebar bleibt.Das Manifest meldet den Immediate- und den Delayed-Pfad getrennt. Für das eingecheckte Beispiel benennen beide Pfade Paket 2 als Check-Paket und melden expected_carry_frames: 129 und expected_check_fails: true.
Das Repository enthält ein 43 ms, 4.185 Byte großes Kontroll-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
Die Eingabe muss enthalten:
A_VORBIS-Track;CodecDelay (normalerweise aus dem Track gelesen); undNützliche Optionen sind --trigger-skip, --codec-delay und --sample-rate. --second-skip bleibt ein Alias für die umbenannte Option --trigger-skip. Die Standardwerte sind die für den bekannten Fehlerzustand erforderlichen Werte. Der Befehl gibt den JSON-Bericht auf stdout aus und schreibt denselben Bericht nach --manifest, wenn diese Option angegeben wird.
Der eingecheckte Kandidat ist 43 ms und 4.206 Byte groß. Sein SHA-256 ist:
a0ab9e146c629f037b86612addc1ab6fff9200711d45aa5f5edbb9576cc206ac
Es wird erwartet, dass sich der Ausgabe-Hash ändert, wenn sich die Eingabe, das Paketfenster oder die Optionen ändern.
Der M4A-Fall missbraucht eine gültige MP4-Sample-Table-Form statt der kodierten AAC-Payload. Der Generator ändert einen Seed wie folgt:
stsz-Sample-Size-Array durch sample_size = 1.stsz, den ersten stsc-Run und den ersten stts-Run auf denselben großen Wert.stco-Offset, sodass die Ein-Byte-AAC-Payload weiterhin in mdat zeigt.Der gepinnte FFmpeg-Demuxer behandelt den deklarierten Zähler als maßgeblich, während er seine Index- und Timing-Tabellen aufbaut. Die relevanten Strukturen verwenden ungefähr 24 Byte pro deklariertem Sample für AVIndexEntry und 12 Byte pro Sample für Timing-Daten: insgesamt 36 Byte pro Zähler-Eintrag. Der maximal akzeptierte Zähler im getesteten Build ist 178.956.969 (0x0AAAAAA9), was Folgendes projiziert:
178,956,969 * 24 = 4,294,967,256 bytes
178,956,969 * 12 = 2,147,483,628 bytes
combined = 6,442,450,884 bytes
Der exakte Discord-Renderer erreichte einen privaten Speicher-Peak von 6.614.761.472 Byte beim Laden der Metadaten. Der benachbarte Zähler 178.956.970 wird von der gepinnten FFmpeg-Grenze abgelehnt und blieb nahe am normalen Speicher. Dies ist unkontrollierter Ressourcenverbrauch (CWE-400), kein beobachteter Integer-Wrap, keine Negative-Size-Allokation und kein Out-of-Bounds-Write. Die tatsächliche AAC-Payload kann abgeschnitten werden; erfolgreiche Wiedergabe ist nicht erforderlich, um die große Allokation zu erreichen.
Der Generator akzeptiert absichtlich einen Seed, anstatt einen AAC-Encoder einzubetten. Verwenden Sie eine Fast-Start-AAC/M4A-Datei mit einer expliziten stsz-Tabelle, einem stsc-Run, einem oder mehreren stts-Einträgen und stco-Chunk-Offsets. Er schlägt fehl (fail closed), wenn die erforderliche Struktur fehlt.
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
Der Standardwert für --sample-count ist 178956969, der maximal akzeptierte Wert im gepinnten Build. Verwenden Sie einen kleineren Wert für einen Low-Memory-Smoke-Test, zum Beispiel:
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 ist eine nützliche benachbarte Rejection-Kontrolle, nicht der auslösende Wert. Das optionale Flag --moov-at-end verschiebt moov hinter mdat und aktualisiert stco/co64; es ist nützlich beim Testen einer Datei, deren physische AAC-Bytes vor ihren Metadaten auftreten, aber es ist nicht erforderlich für den Allokationsmechanismus.
Um dieses Layout explizit zu erzeugen:
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
Die passenden Artefakte sind
samples/short-vorbis-dual-control.webm,
samples/short-vorbis-dual-crash.webm,
und samples/short-vorbis-dual-crash.json.