وحدات Fuzz

يتم توفير ميزة fuzzing في لغة Rust من خلال حزمة 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 في ملف إنشاء 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 على fuzzer بسيط:

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 لمعالجتها كإدخال من أجل إجراء عملية fuzzing على الدالة المستهدَفة.

في هذا المثال، يتم التحقّق من طول البيانات فقط لتحديد ما إذا كان سيتم استدعاء الدالة heap_oob، التي يؤدي استدعاؤها إلى قراءة خارج النطاق. libFuzzer هو fuzzer موجّه بالتغطية، لذا فهو يتقارب بسرعة مع الطول الذي يسبب المشكلة، لأنّه يحدّد أنّ أول 326 بايت من البيانات لا تؤدي إلى مسارات تنفيذ جديدة.

يمكنك العثور على هذا المثال في الشجرة ضمن المسار tools/security/fuzzing/example_rust_fuzzer/. للاطّلاع على مثال أكثر تعقيدًا قليلاً على fuzzer آخر (يُجري عملية fuzzing على rustlib اعتمادية) في الشجرة، يُرجى الاطّلاع على legacy_blob_fuzzer.

للحصول على إرشادات حول كيفية كتابة أدوات fuzzing بلغة Rust تراعي البنية، يُرجى الاطّلاع على كتاب Rust Fuzz، وهو المستندات الرسمية لمشروع Rust Fuzz.