מודולים של Fuzz

תמיכה ב-Rust fuzzing ניתנת באמצעות ה-crate‏ libfuzzer-sys, שמספק קישורים למנוע ה-fuzzing libFuzzer של LLVM. מידע נוסף זמין במאגר libfuzzer-sys וגם בדף הפרויקט LLVM libFuzzer.

המודול rust_fuzz יוצר קובץ בינארי של fuzzer שמתחיל לבצע fuzzing כשמריצים אותו (בדומה למודול cc_fuzz). מאחר שה-fuzzer משתמש במנוע ה-fuzzing libFuzzer, יכול להיות שיידרש מספר ארגומנטים כדי לשלוט ב-fuzzing. הם מפורטים במסמכי התיעוד של libFuzzer.

מודולים מסוג rust_fuzz הם תוסף למודולים מסוג rust_binary, ולכן יש להם את אותן תכונות וההנחות. בנוסף, הן מטמיעות הרבה מהתכונות והפונקציונליות של המודולים cc_fuzz.

כשמפתחים מודולים של rust_fuzz, הדגל --cfg fuzzing מופעל. אפשר להשתמש בדגל הזה כדי לתמוך בתכנות מותנית של קוד הספרייה, כדי לשפר את בדיקת ה-fuzzing.

כתיבה של fuzzer בסיסי ב-Rust

אפשר להגדיר מודול fuzz בקובץ build ‏Android.bp באמצעות הקוד הזה:

rust_fuzz {
    name: "example_rust_fuzzer",
    srcs: ["fuzzer.rs"],

    // Config for running the target on fuzzing infrastructure can be set under
    // fuzz_config. This shares the same properties as cc_fuzz's fuzz_config.
    fuzz_config: {
        fuzz_on_haiku_device: true,
        fuzz_on_haiku_host: false,
    },

    // Path to a corpus of sample inputs, optional. See https://llvm.org/docs/LibFuzzer.html#corpus
    corpus: ["testdata/*"],

    // Path to a dictionary of sample byte sequences, optional. See https://llvm.org/docs/LibFuzzer.html#dictionaries
    dictionary: "example_rust_fuzzer.dict",
}

הקובץ fuzzer.rs מכיל כלי fuzzing פשוט:

fn heap_oob() {
    let xs = vec![0, 1, 2, 3];
    let val = unsafe { *xs.as_ptr().offset(4) };
    println!("Out-of-bounds heap value: {}", val);
}

fuzz_target!(|data: &[u8]| {
    let magic_number = 327;
    if data.len() == magic_number {
        heap_oob();
    }
});

כאן, fuzz_target!(|data: &[u8]| { /* fuzz using data here */ }); מגדיר את נקודת הכניסה של יעד ה-fuzz שנקראת על ידי מנוע libFuzzer. הארגומנט data הוא רצף של בייטים שסופקו על ידי המנוע libFuzzer, והוא משמש לצורך מניפולציה כקלט כדי לבצע בדיקת fuzz לפונקציה המטורגטת.

בדוגמה הזו של ה-fuzzer, רק אורך הנתונים נבדק כדי לקבוע אם להפעיל את הפונקציה heap_oob, שהפעלה שלה גורמת לקריאה מחוץ למגבלות. libFuzzer הוא כלי fuzzing מבוסס-כיסוי, ולכן הוא מתקרב במהירות לאורך הבעיה, מאחר שהוא קובע שה-326 B הראשונים של הנתונים לא יוצרים נתיבים חדשים לביצוע.

הדוגמה הזו נמצאת ב-tree, בכתובת tools/security/fuzzing/example_rust_fuzzer/. דוגמה מורכבת יותר של fuzzer אחר (שמפעיל fuzzing על יחסי תלות של rustlib) בתוך העץ מופיעה ב-legacy_blob_fuzzer.

איך כותבים כלי fuzzing מבוססי-מבנה ב-Rust? תוכלו למצוא הנחיות בספר Rust Fuzz, המסמך הרשמי של פרויקט Rust Fuzz.