
Preuve de concept autonome pour CVE-2026-86547, un déréférencement de pointeur NULL dans mrubyc op_enter() jusqu'à la version 4.0.0.
OP_ENTER de mrubycPreuve de concept autonome pour CVE-2026-86547, un déréférencement de pointeur NULL dans le gestionnaire op_enter() de mrubyc jusqu'à la version 4.0.0 incluse.
mrubyc est une implémentation légère de Ruby pour les systèmes embarqués. Sa VM de bytecode conserve le pointeur de la trame d'appel courante dans mrbc_vm.callinfo_tail. Au niveau supérieur, mrbc_vm_begin() initialise ce pointeur à NULL car aucune trame d'appel de méthode n'existe encore.
Dans l'implémentation vulnérable de op_enter() dans release4.0.0, le gestionnaire lit callinfo->reg_offset sans d'abord vérifier si vm->callinfo_tail est NULL :
mrbc_callinfo *callinfo = vm->callinfo_tail;
int reg_offset = callinfo->reg_offset;
Un programme bytecode .mrb conçu de manière malveillante peut placer OP_ENTER au niveau supérieur, amenant l'interpréteur à atteindre ce code avec un callinfo_tail NULL et à planter via un déréférencement de pointeur NULL.
CVE : CVE-2026-86547
Type : CWE-476 — Déréférencement de pointeur NULL
Impact : Disponibilité / déni de service
Affecté : mrubyc jusqu'à 4.0.0 inclus
Sévérité : Moyenne, CVSS 6.9 (selon l'avis)
La PoC reproduit les dispositions pertinentes de mrbc_callinfo et mrbc_vm et reproduit l'accès mémoire vulnérable indépendamment du runtime mrubyc complet.
Elle démontre deux chemins :
callinfo_tail est NULL et callinfo->reg_offset est déréférencé sans garde, produisant une erreur de segmentation.OP_ENTER de niveau supérieur, suivie d'un test de contrôle montrant qu'une trame d'appel valide fonctionne toujours.Le harnais utilise volatile sur le pointeur vulnérable et __builtin_trap() dans sa description pour rendre le reproducteur adapté à l'observation basée sur les sanitizers. L'accès vulnérable réel est la lecture de callinfo->reg_offset.
gcc -O0 -g -o poc poc.c
./poc
Le résultat attendu sur le chemin vulnérable est une erreur de segmentation après :
[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
Le sanitizer devrait signaler un SEGV sur une adresse correspondant au champ reg_offset à partir d'une base mrbc_callinfo NULL. Avec la disposition de structure utilisée ici, offsetof(mrbc_callinfo, reg_offset) vaut 0x14.
./poc fixed
La sortie attendue inclut :
[FIXED PATH] op_enter with NULL guard
[GUARD] top-level OP_ENTER — rejected safely
[control, valid frame] reg_offset = 5
Fixed path: no crash.
Le gestionnaire vulnérable d'origine se trouve dans src/vm.c dans mrubyc release4.0.0, vers la ligne 1537. L'opération concernée est le déréférencement direct de callinfo->reg_offset après avoir assigné vm->callinfo_tail à callinfo sans vérification de NULL.
Le code source post-correctif référencé dans la recherche est le commit 4261cf5e5ae5579e3110dab98a04b91c7d919429.
Le harnais autonome démontre l'erreur mémoire sous-jacente. Dans mrubyc lui-même, le déclencheur nécessite un fichier bytecode .mrb conçu de manière malveillante contenant une instruction OP_ENTER au niveau supérieur, en dehors d'une définition de méthode. Si une application charge et exécute des fichiers .mrb non fiables, un fichier bytecode contrôlé par un attaquant peut donc faire planter le processus de l'interpréteur.
Il s'agit d'une condition de déni de service. La recherche ne revendique pas d'exécution de code, de divulgation d'informations ou de corruption de mémoire au-delà du déréférencement de NULL.
src/vm.csrc/vm.c post-correctifOP_SUPER qui a motivé l'audit de op_enter()L'histoire de la découverte est documentée dans : I Read Someone Else's Bug Report, Then Found The Same Missing Check In The Next Function Over.
L'observation clé de la recherche était que op_super() avait une garde NULL manquante autour de la même invariant vm->callinfo_tail. La vérification du gestionnaire voisin op_enter() a montré que la même hypothèse y était présente sans la garde correspondante.