Fuzzing di programmi Rust

Il fuzzing è una tecnica di testing dinamica che consiste nel fornire input casuali o non validi a un programma al fine di individuare bug, crash o vulnerabilità di sicurezza. In Rust, possiamo sfruttare lo strumento cargo-fuzz per eseguire il fuzzing dei nostri programmi in modo efficace e automatizzato.

Configurazione di cargo-fuzz

Per utilizzare cargo-fuzz, è necessario aggiungere cargo-fuzz come dipendenza nel file Cargo.toml del progetto:

[dependencies]
fuzz_targets = "0.2"

[dev-dependencies]
cargo-fuzz = "0.11"

Creiamo quindi una cartella fuzz nella radice del progetto e all'interno un file fuzz/Cargo.toml:

[package]
name = "fuzz"
version = "0.1.0"
edition = "2021"

[dependencies]
fuzz_targets = "0.2"

Definizione di un target di fuzzing

Successivamente, definiamo un target di fuzzing nel file fuzz/fuzz_targets/parse.rs, in questo esempio stiamo cercando di capire se il parsing di un i32 da una stringa può dare problemi.

#![allow(unused)]
#![no_main]
fn main() {
use libfuzzer_sys::fuzz_target;

// Questa funzione è il nostro target di fuzzing
fuzz_target!(|data: &[u8]| {
    // Convertiamo l'input in una stringa UTF-8
    if let Ok(s) = std::str::from_utf8(data) {
        // Eseguiamo il parsing della stringa
        let _ = s.parse::<i32>();
    }
});
}

Esecuzione del Fuzzing

Per eseguire il fuzzing, possiamo utilizzare il comando cargo fuzz run parse:

$ cargo fuzz run parse

Durante l'esecuzione, cargo-fuzz genera automaticamente input casuali per testare la funzione di parsing. Ogni volta che viene trovato un input che provoca un fallimento, cargo-fuzz conserva quel caso di test per ulteriori analisi. cargo-fuzz produce inoltre report dettagliati che mostrano gli input che hanno causato crash o errori nel programma sotto test. Questi report sono essenziali per comprendere e risolvere le vulnerabilità o i bug identificati durante il fuzzing.

Tramite il fuzzing in Rust è possibile:

  • Identificare precocemente di Bug: il fuzzing permette di individuare bug e vulnerabilità di sicurezza che potrebbero non essere stati previsti durante lo sviluppo.
  • Automatizzare il Testing: cargo-fuzz automatizza il processo di generazione e test di input casuali, riducendo l'onere manuale sullo sviluppatore.
  • Migliorare la Sicurezza: migliorando la copertura dei test, il fuzzing contribuisce a garantire che il software sia robusto e sicuro anche in presenza di input non previsti.