
Reproduit le débordement d'entier CVE-2026-70638 dans llama.cpp Android JNI avec une démonstration arithmétique sûre, un générateur GGUF malveillant et un hook Frida pour la recherche en sécurité autorisée.
PoC compagnon pour l'article de Hunt-Benito « Une multiplication de trop : CVE-2026-70638 — Dépassement d'entier dans l'allocation de tas JNI Android de llama.cpp » → https://www.hunt-benito.com/blog/one-multiply-too-many-cve-2026-70638-llama-cpp-android-jni-integer-overflow/
Java_android_llama_cpp_LLamaAndroid_new_1batch() dans
examples/llama.android/llama/src/main/cpp/llama-android.cpp (builds llama.cpp
b1886–b7445) est une copie manuelle de llama_batch_init() qui effectue plusieurs
calculs malloc(sizeof(T) * count) non vérifiés. Avec un multiplicateur
contrôlé par l'attaquant (n_seq_max, n_tokens ou embd), la taille déborde, le bloc
de tas est sous-dimensionné et les écritures ultérieures de l'appelant débordent de ce bloc
(CWE-190 → CWE-122). NVD CVSS 3.1 7.8 High
(AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H).
Le cœur vulnérable de la fonction :
batch->seq_id[i] = (llama_seq_id *) malloc(sizeof(llama_seq_id) * n_seq_max);
# 1. Arithmetic demonstrator (the core of the article's PoC)
cc -O2 -o overflow_demo overflow_demo.c
./overflow_demo
# 2. Malicious model file
python3 craft_gguf.py 0x40000001 malicious.gguf # -> 416-byte GGUF
xxd malicious.gguf | head # verify magic 'GGUF' + key
# 3. Live hook (rooted/emulator device with frida-server, authorized target only)
frida -U -l hook_new_batch.js -f <package> --no-pause
[2] Malicious: n_seq_max = 0x40000000 (2^30). 4 * 2^30 = 2^32 -> wraps:
n_seq_max (attacker) = 1073741824 (0x40000000)
malloc size, arm64 = 4294967296 bytes (4.00 GiB)
malloc size, armeabi-v7a = 0 bytes
caller believes it got = 4294967296 bytes
>>> 32-bit WRAP: 4294967296-byte write into 0-byte heap block (CWE-122)
armeabi-v7a, toujours distribuées). Sur 64 bits (arm64-v8a), la même expression non vérifiée demande à la place un bloc de plusieurs Gio que malloc ne peut pas allouer (NULL → crash ultérieur / DoS) ; la corruption du tas nécessite le chemin 32 bits.overflow_demo.c n'effectue aucune écriture hors limites — il prouve uniquement que l'arithmétique déborde. craft_gguf.py produit un modèle non exécutable (aucun tenseur) et ne peut donc pas être utilisé comme arme tel quel ; il démontre que le multiplicateur contrôlé par l'attaquant provient de métadonnées non fiables.Mettez à jour llama.cpp vers b7446 ou une version ultérieure (le chemin JNI new_1batch a été supprimé par la réécriture de la liaison Android). Si vous devez rester sur une build affectée ou un fork en aval, appliquez le patch de validation de Cyera depuis
https://github.com/Vladimir-tokarev-cyera/llama-cpp-security-patches
(la protection batch-init CVE-2026-43627 est le correctif canonique pour cette classe de bug).
RÉSERVÉ À LA RECHERCHE EN SÉCURITÉ AUTORISÉE ET À L'USAGE ÉDUCATIF UNIQUEMENT.
| Fichier | Objectif |
|---|
overflow_demo.c | Reproducteur autonome de l'arithmétique de dépassement de la taille en 32 bits (armeabi-v7a) vs 64 bits (arm64-v8a) size_t. Aucune écriture corrompue — sûr à exécuter n'importe où. |
craft_gguf.py | Construit un GGUF minimal et structurellement valide avec llama.embedding_length défini sur une valeur contrôlée par l'attaquant, montrant le vecteur de livraison par fichier de modèle (embd est lu directement depuis des métadonnées non fiables). |
hook_new_batch.js | Hook Frida qui journalise/remplace les trois multiplicandes à la frontière JNI en direct sur un appareil de recherche. |