
Un fuzzer orienté GPU guidé par la couverture pour applications CUDA en espace utilisateur
Ce dépôt contient les artefacts de cuFuzz, un fuzzer guidé par la couverture orienté GPU pour les applications CUDA en espace utilisateur. cuFuzz combine la collecte de couverture côté hôte et côté device avec la sanitisation pour détecter efficacement les bugs dans les programmes CUDA.

cufuzz-artifacts/
├── src/ # Core cuFuzz components
│ ├── cufuzz_cov_nvbit/ # NVBit-based device-side coverage collection tool
│ └── cufuzz_sand/ # Sanitizer wrappers for SAND integration
├── targets/ # Example fuzzing targets
│ └── sampleApp/ # Simple CUDA app with intentional bug for testing
├── scripts/ # Evaluation and analysis scripts
├── Tools/ # External dependencies
│ ├── AFLplusplus/ # AFL++ fuzzer (git submodule)
│ └── AFLplusplus.patch # cuFuzz patches for AFL++
├── third-party-licenses/ # Third-party license files
│ ├── LICENSE_from_aflplusplus # AFL++ Apache 2.0 license
│ └── LICENSE_from_nvbit # NVBit NVIDIA EULA
├── images/ # Documentation images
├── build.sh # Automated build script
├── verify_build.sh # Quick verification test
├── Dockerfile # Docker container definition
├── LICENSE # Apache License 2.0
└── CONTRIBUTING.md # Contribution guidelines and DCO
cuFuzz a été testé avec la configuration matérielle suivante :
| Composant | Spécification |
|---|---|
| GPU | NVIDIA A40 (48 Go de VRAM, Compute Capability 8.6) |
| CPU |
Autres GPU : cuFuzz devrait fonctionner sur d'autres GPU NVIDIA avec une Compute Capability ≥ 7.0. Ajustez la variable d'environnement GPU_ARCH en conséquence (voir Configuration de l'architecture GPU).
Le moyen le plus rapide d'essayer cuFuzz est d'utiliser un conteneur Docker. Notre Dockerfile utilise l'image de développement officielle NVIDIA CUDA 12.9.
tar -xzvf cufuzz-artifacts.tar.gz
cd cufuzz-artifacts
# Clone AFL++ (required dependency)
git clone https://github.com/AFLplusplus/AFLplusplus.git Tools/AFLplusplus
cd Tools/AFLplusplus
git checkout 9cac7ced05eb9f36c1d0b02ad594b3b09cd3938b
cd ../..
Construisez l'image Docker en spécifiant votre architecture GPU :
sudo docker build --build-arg GPU_ARCH=<your_arch> -t cufuzz .
Référence des architectures GPU :
Pour une liste complète, voir : https://developer.nvidia.com/cuda-gpus
Exemple pour A40/RTX 3090 :
sudo docker build --build-arg GPU_ARCH=sm_86 -t cufuzz .
Remarque : Cette étape peut prendre plusieurs minutes selon votre machine et votre connexion réseau.
sudo docker run --rm --gpus all -it -v /:/my_workspace cufuzz bash
Une fois que le conteneur Docker est en cours d'exécution, vérifiez la compilation :
root@container:~/cufuzz# ./verify_build.sh
Installez les dépendances requises sur Ubuntu 22.04 :
apt-get update && apt-get install -y build-essential python3-dev automake cmake git flex \
bison libglib2.0-dev libpixman-1-dev python3-setuptools cargo libgtk-3-dev lld llvm llvm-dev \
clang ninja-build cpio libcapstone-dev wget curl python3-pip vim less libxxhash-dev bc zlib1g-dev
Définissez la variable d'environnement GPU_ARCH pour votre GPU (voir le tableau des architectures ci-dessus) :
export GPU_ARCH=sm_86 # Change to match your GPU
cd Tools/AFLplusplus
patch -N -p1 < ../AFLplusplus.patch
export CXX=/usr/bin/clang++-14
export CC=/usr/bin/clang-14
make -j8 &> build.log
Téléchargez NVBit version 1.7.5 :
mkdir -p Tools/NVBit
wget https://github.com/NVlabs/NVBit/releases/download/v1.7.5/nvbit-Linux-x86_64-1.7.5.tar.bz2
tar -xvf nvbit-Linux-x86_64-1.7.5.tar.bz2
mv nvbit_release_x86_64/* Tools/NVBit/
rm -rf nvbit_release_x86_64 nvbit-Linux-x86_64-1.7.5.tar.bz2
Compilez notre outil de couverture NVBit :
cd src/cufuzz_cov_nvbit/
export GPU_ARCH=sm_86 # Adjust for your GPU
ARCH=$GPU_ARCH make
cd src/cufuzz_sand
AFL_SAN_NO_INST=1 ../../Tools/AFLplusplus/afl-clang-fast -O2 wrapper_san.c -o wrapper_memcheck.out
AFL_SAN_NO_INST=1 ../../Tools/AFLplusplus/afl-clang-fast -DSAN_MODE_INIT -O2 wrapper_san.c -o wrapper_initcheck.out
AFL_SAN_NO_INST=1 ../../Tools/AFLplusplus/afl-clang-fast -DSAN_MODE_RACE -O2 wrapper_san.c -o wrapper_racecheck.out
AFL_SAN_NO_INST=1 ../../Tools/AFLplusplus/afl-clang-fast -DSAN_MODE_ASAN -O2 wrapper_san.c -o wrapper_asan.out
Après avoir compilé cuFuzz, lancez le fuzzing avec la commande suivante :
CUFUZZ_MAP_SIZE=65536 AFL_SKIP_CPUFREQ=1 AFL_PRELOAD=/PATH/TO/cufuzz_cov.so \
./Tools/AFLplusplus/afl-fuzz -x sample.dict -i input_samples/ -o output_dir/ \
-t 1000000 ./cuda_app.out @@
| Variable | Description | Exemple |
|---|---|---|
AFL_SKIP_CPUFREQ | Ignorer la vérification de la politique de scaling CPU | AFL_SKIP_CPUFREQ=1 |
AFL_PRELOAD | Chemin vers l'outil de couverture NVBit | AFL_PRELOAD=/path/to/cufuzz_cov.so |
La variable AFL_SAN_ABSTRACTION contrôle quelles entrées sont transmises aux sanitizers :
Recommandé : AFL_SAN_ABSTRACTION=simplify_trace (par défaut)
Dans ce mode, cuFuzz utilise la couverture côté device et exécute compute sanitizer sur un sous-ensemble d'entrées (les entrées avec des traces uniques). Ce mode exploite la fonctionnalité SAND d'AFL++ pour découpler la collecte de couverture de la sanitisation.
cd src/cufuzz_sand
# Build sanitizer wrappers
AFL_SAN_NO_INST=1 ../../Tools/AFLplusplus/afl-clang-fast -O2 wrapper_san.c -o wrapper_memcheck.out
AFL_SAN_NO_INST=1 ../../Tools/AFLplusplus/afl-clang-fast -DSAN_MODE_INIT -O2 wrapper_san.c -o wrapper_initcheck.out
AFL_SAN_NO_INST=1 ../../Tools/AFLplusplus/afl-clang-fast -DSAN_MODE_RACE -O2 wrapper_san.c -o wrapper_racecheck.out
AFL_SAN_NO_INST=1 ../../Tools/AFLplusplus/afl-clang-fast -DSAN_MODE_ASAN -O2 wrapper_san.c -o wrapper_asan.out
cd ../../targets/sampleApp/
export PATH=/usr/local/cuda/bin/:$PATH
export GPU_ARCH=sm_86 # Adjust for your GPU
# Build vanilla version (for sanitizer)
nvcc sampleApp.cu -I/usr/local/cuda/include/ -O2 --ptxas-options "-v" \
--gpu-architecture=$GPU_ARCH -o sampleApp-vanilla.out
# Build instrumented version (for fuzzing)
nvcc sampleApp.cu -I/usr/local/cuda/include/ -O2 --ptxas-options "-v" \
--gpu-architecture=$GPU_ARCH --compiler-bindir ../../Tools/AFLplusplus/afl-clang-fast++ \
-o sampleApp.out
# Run cuFuzz
ORIGINAL_APP=./sampleApp-vanilla.out \
SANITIZER_PATH=/usr/local/cuda/bin/compute-sanitizer \
SANITIZER_ARG="--tool=memcheck --report-api-errors=no --error-exitcode 99" \
SANITIZER_ARG_RACE="--tool=racecheck --report-api-errors=no --error-exitcode 99" \
SANITIZER_ARG_INIT="--tool=initcheck --report-api-errors=no --error-exitcode 99" \
CUFUZZ_MAP_SIZE=65536 \
AFL_SKIP_CPUFREQ=1 \
AFL_PRELOAD=../../src/cufuzz_cov_nvbit/cufuzz_cov.so \
../../Tools/AFLplusplus/afl-fuzz -x sample.dict -i in/ -o out/ \
-w ../../src/cufuzz_sand/wrapper_memcheck.out \
-w ../../src/cufuzz_sand/wrapper_racecheck.out \
-w ../../src/cufuzz_sand/wrapper_initcheck.out \
-t 1000000 ./sampleApp.out @@

Exécution sans sanitizers (non recommandée) : Supprimez les arguments -w et les variables SANITIZER_*.
Exécution sans couverture côté device (optionnel) : Supprimez AFL_PRELOAD=...cufuzz_cov.so.
Dans ce mode, cuFuzz exploite le mode persistant d'AFL++, où plusieurs entrées sont testées au sein d'un même processus. Cela améliore considérablement le débit en amortissant le surcoût d'initialisation de CUDA.
Le mode persistant nécessite des modifications du code source du harnais de fuzzing. Voir la documentation du mode persistant AFL++ pour plus de détails.
cd targets/sampleApp/
export PATH=/usr/local/cuda/bin/:$PATH
export GPU_ARCH=sm_86 # Adjust for your GPU
# Build persistent mode binary
nvcc sampleApp_persistent.cu -I/usr/local/cuda/include/ -O2 --ptxas-options "-v" \
--gpu-architecture=$GPU_ARCH --compiler-bindir ../../Tools/AFLplusplus/afl-clang-fast++ \
-o sampleApp_persistent.out
# Run cuFuzz in persistent mode
COV_PERSISTENT=1 \
CUFUZZ_MAP_SIZE=65536 \
AFL_SKIP_CPUFREQ=1 \
AFL_PRELOAD=../../src/cufuzz_cov_nvbit/cufuzz_cov.so \
./../../Tools/AFLplusplus/afl-fuzz -x sample.dict -i in/ -o out/ \
-t 1000000 ./sampleApp_persistent.out @@

Le mode persistant prend également en charge les options de sanitizer via : src/cufuzz_sand/wrapper_persistent_san.c
nvidia-smi fonctionneGPU_ARCH en fonction de la compute capability de votre GPUNous accueillons volontiers les contributions ! Veuillez consulter CONTRIBUTING.md pour les directives sur la façon de contribuer, notamment :
Si vous utilisez cuFuzz dans vos recherches, veuillez citer notre article OOPSLA 2026 :
@article{cufuzz2026,
title={Hunting CUDA Bugs at Scale with cuFuzz},
author={Mohamed Tarek Ibn Ziad and Christos Kozyrakis},
journal={Proceedings of the ACM on Programming Languages},
volume={10},
number={OOPSLA1},
article={123},
month={4},
year={2026},
doi={10.1145/3798231}
}
Ce projet est sous licence Apache License 2.0 - voir le fichier LICENSE pour plus de détails.
Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Ce projet utilise les composants tiers suivants :
| Composant | Licence | Fichier de licence |
|---|---|---|
| AFL++ | Apache License 2.0 | third-party-licenses/LICENSE_from_aflplusplus |
| NVBit | NVIDIA EULA | third-party-licenses/LICENSE_from_nvbit |
| Intel Xeon Platinum 8362 (64 cœurs, 2 threads/cœur) |
| Mémoire | 120 Go+ de RAM recommandés |
| Stockage | 50 Go+ d'espace libre pour l'image Docker et les sorties de fuzzing |
| Composant | Version |
|---|
| Ubuntu | 22.04 LTS |
| Pilote NVIDIA | 570.144 ou compatible |
| CUDA Toolkit | 12.9 |
| Docker | 20.10+ (recommandé) |
| nvidia-container-toolkit | Requis pour la prise en charge de l'option --gpus |
| clang | 14 |
| Famille de GPU | Architecture | Exemples |
|---|
| Ampere (Data Center) | sm_80 | A100 |
| Ampere (Consumer/Pro) | sm_86 | A40, RTX 3090, RTX 3060 |
| Hopper | sm_90 | H100 |
| Ada Lovelace | sm_89 | RTX 4090, L40 |
| Turing | sm_75 | RTX 2080, T4 |
| Variable | Description | Exemple |
|---|
CUFUZZ_MAP_SIZE | Taille de la carte de couverture en octets | CUFUZZ_MAP_SIZE=65536 |
COV_PERSISTENT | Activer la prise en charge du mode persistant AFL++ (0=non, 1=oui) | COV_PERSISTENT=1 |
GPU_ARCH | Architecture GPU cible pour les compilations | GPU_ARCH=sm_86 |
| Variable | Description | Exemple |
|---|
ORIGINAL_APP | Chemin vers l'application vanilla (non instrumentée) | ORIGINAL_APP=./cuda_app |
SANITIZER_PATH | Chemin vers le binaire compute-sanitizer | SANITIZER_PATH=/usr/local/cuda/bin/compute-sanitizer |
SANITIZER_ARG | Arguments pour le sanitizer memcheck | SANITIZER_ARG="--tool=memcheck --error-exitcode 99" |
SANITIZER_ARG_RACE | Arguments pour le sanitizer racecheck | SANITIZER_ARG_RACE="--tool=racecheck --error-exitcode 99" |
SANITIZER_ARG_INIT | Arguments pour le sanitizer initcheck | SANITIZER_ARG_INIT="--tool=initcheck --error-exitcode 99" |
| Valeur | Description | Sensibilité | Performance |
|---|
all_trace | Transmettre toutes les entrées aux sanitizers | La plus élevée | La plus lente |
simplify_trace | Transmettre les entrées ayant des chemins d'exécution uniques | Élevée | Équilibrée |
unique_trace | Transmettre les entrées ayant des signatures de couverture uniques | Moyenne | Plus rapide |
coverage_increase | Transmettre uniquement les entrées provoquant une augmentation de la couverture | La plus faible | La plus rapide |