cargo-fuzz - Fuzzing Rust con libFuzzer
cargo-fuzz es la forma estándar de hacer fuzzing a código Rust. Cableatea libFuzzer con un workflow nativo a Cargo: escribe un objetivo de fuzz como una función Rust ordinaria tomando bytes arbitrarios, ejecuta cargo fuzz run, y fuzzing guiado por cobertura caza panics, overflows aritméticos, y — en código unsafe — errores de memoria genuinos. Rust seguro previene corrupción de memoria, pero no previene panics, loops infinitos o bugs de lógica, y cualquier bloque unsafe o dependencia C reintroduce la clase completa de problemas de memoria.
Instalación
| Paso | Comando |
|---|
| Instalar | cargo install cargo-fuzz |
| Nightly requerido | rustup install nightly (libFuzzer necesita nightly) |
| Inicializar | cargo fuzz init (en tu crate) |
| Verificar | cargo fuzz --version |
Creando un objetivo de fuzz
cargo fuzz init # crea directorio fuzz/
cargo fuzz add parse_input # crea un nuevo objetivo
// fuzz/fuzz_targets/parse_input.rs
#![no_main]
use libfuzzer_sys::fuzz_target;
fuzz_target!(|data: &[u8]| {
if let Ok(s) = std::str::from_utf8(data) {
let _ = my_crate::parse(s); // los panics aquí se convierten en hallazgos
}
});
Ejecutando
| Comando | Descripción |
|---|
cargo fuzz run parse_input | Hacer fuzzing al objetivo |
cargo fuzz run parse_input -- -max_total_time=300 | Ejecutar por 5 minutos |
cargo fuzz run parse_input -j 8 | 8 trabajos paralelos |
cargo fuzz list | Listar objetivos |
cargo fuzz build | Compilar sin ejecutar |
Entrada estructurada con Arbitrary
Los bytes raw desperdician tiempo en entradas que tu parser rechaza inmediatamente. El crate arbitrary construye valores tipados en su lugar:
use arbitrary::Arbitrary;
#[derive(Arbitrary, Debug)]
struct Config { name: String, retries: u8, enabled: bool }
fuzz_target!(|cfg: Config| {
let _ = my_crate::apply_config(cfg);
});
| Beneficio | Por qué |
|---|
| Entradas válidas-formadas | Alcanza lógica más profunda |
| Objetivos tipados | Hacer fuzzing a APIs, no solo parsers |
Salida Debug | Reproductores legibles |
Sanitizers
| Sanitizer | Flag |
|---|
| AddressSanitizer (por defecto) | -s address |
| LeakSanitizer | incluido con ASan |
| MemorySanitizer | -s memory |
| ThreadSanitizer | -s thread |
| Ninguno (más rápido) | -s none |
# Hacer fuzzing a código FFI unsafe con ASan
cargo fuzz run ffi_target -s address
Corpus y cobertura
| Comando | Propósito |
|---|
fuzz/corpus/<target>/ | Dónde se acumulan entradas interesantes |
cargo fuzz cmin <target> | Minimizar el corpus |
cargo fuzz tmin <target> <input> | Minimizar una entrada que crashea |
cargo fuzz coverage <target> | Generar datos de cobertura |
| Corpus semilla | Añadir ejemplos válidos para bootstrap |
Semillar el corpus con entradas reales válidas es la forma más efectiva de hacer que el fuzzing sea productivo rápidamente.
Reproduciendo crashes
# Los crashes aterrizan en fuzz/artifacts/<target>/
cargo fuzz run parse_input fuzz/artifacts/parse_input/crash-abc123
# Encogerlo a un caso mínimal
cargo fuzz tmin parse_input fuzz/artifacts/parse_input/crash-abc123
Convierte la entrada minimizada en un #[test] regular para que el bug permanezca arreglado.
Qué hacer fuzzing en Rust
| Buen objetivo | Por qué |
|---|
| Parsers / deserializers | Entrada no confiable, estado complejo |
Bloques unsafe | Seguridad de memoria realmente en riesgo |
| Límites FFI | Código C detrás de la interfaz |
| Máquinas de estado/protocolos | Bugs de orden |
| Compresión / encoding | Territorio de bugs clásico |
| Menos útil | Por qué |
|---|
| Aritmética segura pura | Los panics usualmente son obvios |
| Wrappers finos | Poca lógica a explorar |
cargo-fuzz vs otros fuzzers
| Aspecto | cargo-fuzz | AFL++ (afl.rs) | LibAFL | honggfuzz-rs |
|---|
| Motor | libFuzzer | AFL++ | Personalizado | honggfuzz |
| Setup | El más fácil para Rust | Moderado | Construye el tuyo | Fácil |
| Entrada estructurada | arbitrary | arbitrary | Tipos personalizados | arbitrary |
| Mejor para | Fuzzing Rust estándar | Modos persistente/binario | Objetivos inusuales | Feedback por hardware |
Para objetivos non-Rust ve AFL++ o honggfuzz; para fuzzers personalizados ve LibAFL.
Recursos