
Eigenständiger Proof of Concept für CVE-2026-86547, eine NULL-Zeiger-Dereferenzierung in mrubyc op_enter() bis einschließlich 4.0.0.
OP_ENTER NULL-Zeiger-DereferenzierungEigenständiger Proof of Concept für CVE-2026-86547, eine NULL-Zeiger-Dereferenzierung im op_enter()-Handler von mrubyc bis einschließlich Release 4.0.0.
mrubyc ist eine leichtgewichtige Ruby-Implementierung für eingebettete Systeme. Seine Bytecode-VM hält den Zeiger auf den aktuellen Aufrufrahmen in mrbc_vm.callinfo_tail. Auf oberster Ebene initialisiert mrbc_vm_begin() diesen Zeiger auf NULL, da noch kein Methodenaufrufrahmen existiert.
In der verwundbaren op_enter()-Implementierung in release4.0.0 liest der Handler callinfo->reg_offset, ohne zuvor zu prüfen, ob vm->callinfo_tail NULL ist:
mrbc_callinfo *callinfo = vm->callinfo_tail;
int reg_offset = callinfo->reg_offset;
Ein manipuliertes .mrb-Bytecode-Programm kann OP_ENTER auf oberster Ebene platzieren, wodurch der Interpreter diesen Code mit einem NULL-callinfo_tail erreicht und durch eine NULL-Zeiger-Dereferenzierung abstürzt.
CVE: CVE-2026-86547
Typ: CWE-476 — NULL-Zeiger-Dereferenzierung
Auswirkung: Verfügbarkeit / Denial of Service
Betroffen: mrubyc bis einschließlich 4.0.0
Schweregrad: Mittel, CVSS 6.9 (laut Advisory)
Der PoC bildet die relevanten mrbc_callinfo- und mrbc_vm-Layouts nach und reproduziert den verwundbaren Speicherzugriff unabhängig von der vollständigen mrubyc-Laufzeitumgebung.
Er demonstriert zwei Pfade:
callinfo_tail ist NULL und callinfo->reg_offset wird ohne Schutzprüfung dereferenziert, was einen Segmentation Fault erzeugt.OP_ENTER auf oberster Ebene sicher zurück, gefolgt von einem Kontrolltest, der zeigt, dass ein gültiger Aufrufrahmen weiterhin funktioniert.Das Harness verwendet volatile für den verwundbaren Zeiger und __builtin_trap() in seiner Beschreibung, um den Reproduzierer für sanitizerbasierte Beobachtung geeignet zu machen. Der tatsächliche verwundbare Zugriff ist das Lesen von callinfo->reg_offset.
gcc -O0 -g -o poc poc.c
./poc
Das erwartete Ergebnis auf dem verwundbaren Pfad ist ein Segmentation Fault nach:
[VULNERABLE PATH] op_enter without NULL guard
vm->callinfo_tail = NULL (top-level frame)
About to dereference NULL...
gcc -O0 -g -fsanitize=address -fno-omit-frame-pointer -o poc-asan poc.c
./poc-asan
Der Sanitizer sollte einen SEGV auf einer Adresse melden, die dem reg_offset-Feld von einer NULL-mrbc_callinfo-Basis entspricht. Mit dem hier verwendeten Struktur-Layout ist offsetof(mrbc_callinfo, reg_offset) gleich 0x14.
./poc fixed
Die erwartete Ausgabe enthält:
[FIXED PATH] op_enter with NULL guard
[GUARD] top-level OP_ENTER — rejected safely
[control, valid frame] reg_offset = 5
Fixed path: no crash.
Der ursprüngliche verwundbare Handler befindet sich in src/vm.c in mrubyc release4.0.0, etwa in Zeile 1537. Die relevante Operation ist die direkte Dereferenzierung von callinfo->reg_offset, nachdem vm->callinfo_tail ohne NULL-Prüfung callinfo zugewiesen wurde.
Der in der Untersuchung referenzierte Quellcode nach der Behebung ist Commit 4261cf5e5ae5579e3110dab98a04b91c7d919429.
Das eigenständige Harness demonstriert den zugrunde liegenden Speicherfehler. In mrubyc selbst erfordert der Auslöser eine manipulierte .mrb-Bytecode-Datei, die eine OP_ENTER-Anweisung auf oberster Ebene außerhalb einer Methodendefinition enthält. Wenn eine Anwendung nicht vertrauenswürdige .mrb-Dateien lädt und ausführt, kann eine vom Angreifer kontrollierte Bytecode-Datei daher den Interpreterprozess zum Absturz bringen.
Dies ist eine Denial-of-Service-Bedingung. Die Untersuchung beansprucht keine Codeausführung, Informationsoffenlegung oder Speicherkorruption über die NULL-Dereferenzierung hinaus.
src/vm.csrc/vm.cOP_SUPER-NULL-Prüfungsproblem, das die Prüfung von op_enter() motivierteDie Entdeckungsgeschichte ist dokumentiert in: I Read Someone Else's Bug Report, Then Found The Same Missing Check In The Next Function Over.
Die zentrale Beobachtung der Untersuchung war, dass op_super() eine fehlende NULL-Prüfung rund um dieselbe vm->callinfo_tail-Invariante aufwies. Die Prüfung des benachbarten op_enter()-Handlers zeigte, dass dieselbe Annahme dort ohne die entsprechende Schutzprüfung vorhanden war.