Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d78788d9 authored by Pawan Wagh's avatar Pawan Wagh Committed by Automerger Merge Worker
Browse files

Merge "Fuzzer for rust parcels" am: f8956600 am: 7001d777

parents a5f45de5 7001d777
Loading
Loading
Loading
Loading
+25 −0
Original line number Diff line number Diff line
package {
    // See: http://go/android-license-faq
    default_applicable_licenses: ["frameworks_native_license"],
}

rust_fuzz {
    name: "parcel_fuzzer_rs",
    srcs: [
        "parcel_fuzzer.rs",
    ],
    rustlibs: [
        "libarbitrary",
        "libnum_traits",
        "libbinder_rs",
        "libbinder_random_parcel_rs",
        "binderReadParcelIface-rust",
    ],

    fuzz_config: {
        cc: [
            "waghpawan@google.com",
            "smoreland@google.com",
        ],
    },
}
+164 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 The Android Open Source Project
 *
 * 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
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#![allow(missing_docs)]
#![no_main]

#[macro_use]
extern crate libfuzzer_sys;

mod read_utils;

use crate::read_utils::get_read_funcs;
use binder::binder_impl::{
    Binder, BorrowedParcel, IBinderInternal, Parcel, Stability, TransactionCode,
};
use binder::{
    declare_binder_interface, BinderFeatures, Interface, Parcelable, ParcelableHolder, SpIBinder,
    StatusCode,
};
use binder_random_parcel_rs::create_random_parcel;
use libfuzzer_sys::arbitrary::Arbitrary;

#[derive(Arbitrary, Debug)]
enum ReadOperations {
    SetDataPosition { pos: i32 },
    GetDataSize,
    ReadParcelableHolder { is_vintf: bool },
    ReadBasicTypes { indexes: Vec<usize> },
}

#[derive(Arbitrary, Debug)]
enum Operations<'a> {
    Transact { code: u32, flag: u32, data: &'a [u8] },
    Append { start: i32, len: i32, data1: &'a [u8], data2: &'a [u8], append_all: bool },
    Read { indexes: Vec<ReadOperations>, data: &'a [u8] },
}

/// Interface to fuzz transact with random parcel
pub trait BinderTransactTest: Interface {}

declare_binder_interface! {
    BinderTransactTest["Binder_Transact_Test"] {
        native: BnBinderTransactTest(on_transact),
        proxy: BpBinderTransactTest,
    }
}

impl BinderTransactTest for Binder<BnBinderTransactTest> {}

impl BinderTransactTest for BpBinderTransactTest {}

impl BinderTransactTest for () {}

fn on_transact(
    _service: &dyn BinderTransactTest,
    _code: TransactionCode,
    _parcel: &BorrowedParcel<'_>,
    _reply: &mut BorrowedParcel<'_>,
) -> Result<(), StatusCode> {
    Err(StatusCode::UNKNOWN_ERROR)
}

fn do_transact(code: u32, data: &[u8], flag: u32) {
    let p: Parcel = create_random_parcel(data);
    let spibinder: Option<SpIBinder> =
        Some(BnBinderTransactTest::new_binder((), BinderFeatures::default()).as_binder());
    let _reply = spibinder.submit_transact(code, p, flag);
}

fn do_append_fuzz(start: i32, len: i32, data1: &[u8], data2: &[u8], append_all: bool) {
    let mut p1 = create_random_parcel(data1);
    let p2 = create_random_parcel(data2);

    // Fuzz both append methods
    if append_all {
        match p1.append_all_from(&p2) {
            Ok(result) => result,
            Err(e) => {
                println!("Error occurred while appending a parcel using append_all_from: {:?}", e)
            }
        }
    } else {
        match p1.append_from(&p2, start, len) {
            Ok(result) => result,
            Err(e) => {
                println!("Error occurred while appending a parcel using append_from: {:?}", e)
            }
        }
    };
}

fn do_read_fuzz(read_operations: Vec<ReadOperations>, data: &[u8]) {
    let read_funcs = get_read_funcs();
    let parcel = create_random_parcel(data);

    for operation in read_operations {
        match operation {
            ReadOperations::SetDataPosition { pos } => {
                unsafe {
                    // Safety: Safe if pos is less than current size of the parcel.
                    // It relies on C++ code for bound checks
                    match parcel.set_data_position(pos) {
                        Ok(result) => result,
                        Err(e) => println!("error occurred while setting data position: {:?}", e),
                    }
                }
            }

            ReadOperations::GetDataSize => {
                let data_size = parcel.get_data_size();
                println!("data size from parcel: {:?}", data_size);
            }

            ReadOperations::ReadParcelableHolder { is_vintf } => {
                let stability = if is_vintf { Stability::Vintf } else { Stability::Local };
                let mut holder: ParcelableHolder = ParcelableHolder::new(stability);
                match holder.read_from_parcel(parcel.borrowed_ref()) {
                    Ok(result) => result,
                    Err(err) => {
                        println!("error occurred while reading from parcel: {:?}", err)
                    }
                }
            }

            ReadOperations::ReadBasicTypes { indexes } => {
                for index in indexes.iter() {
                    let read_index = index % read_funcs.len();
                    read_funcs[read_index](parcel.borrowed_ref());
                }
            }
        }
    }
}

fuzz_target!(|operations: Vec<Operations>| {
    for operation in operations {
        match operation {
            Operations::Transact { code, flag, data } => {
                do_transact(code, data, flag);
            }

            Operations::Append { start, len, data1, data2, append_all } => {
                do_append_fuzz(start, len, data1, data2, append_all);
            }

            Operations::Read { indexes, data } => {
                do_read_fuzz(indexes, data);
            }
        }
    }
});
+137 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 The Android Open Source Project
 *
 * 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
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

use binder::binder_impl::BorrowedParcel;
use binder::{ParcelFileDescriptor, Parcelable, SpIBinder};
use binderReadParcelIface::aidl::EmptyParcelable::EmptyParcelable;
use binderReadParcelIface::aidl::GenericDataParcelable::GenericDataParcelable;
use binderReadParcelIface::aidl::SingleDataParcelable::SingleDataParcelable;

macro_rules! read_parcel_interface {
    ($data_type:ty) => {
        |parcel| {
            let _res = parcel.read::<$data_type>();
        }
    };
}

#[derive(Debug, Default)]
pub struct SomeParcelable {
    pub data: i32,
}

impl binder::Parcelable for SomeParcelable {
    fn write_to_parcel(
        &self,
        parcel: &mut binder::binder_impl::BorrowedParcel,
    ) -> std::result::Result<(), binder::StatusCode> {
        parcel.sized_write(|subparcel| subparcel.write(&self.data))
    }

    fn read_from_parcel(
        &mut self,
        parcel: &binder::binder_impl::BorrowedParcel,
    ) -> std::result::Result<(), binder::StatusCode> {
        parcel.sized_read(|subparcel| match subparcel.read() {
            Ok(result) => {
                self.data = result;
                Ok(())
            }
            Err(e) => Err(e),
        })
    }
}

binder::impl_deserialize_for_parcelable!(SomeParcelable);

pub fn get_read_funcs() -> Vec<Box<dyn Fn(&BorrowedParcel<'_>)>> {
    let read_funcs: Vec<Box<dyn Fn(&BorrowedParcel<'_>)>> = vec![
        //read basic types
        Box::new(read_parcel_interface!(bool)),
        Box::new(read_parcel_interface!(i8)),
        Box::new(read_parcel_interface!(i32)),
        Box::new(read_parcel_interface!(i64)),
        Box::new(read_parcel_interface!(f32)),
        Box::new(read_parcel_interface!(f64)),
        Box::new(read_parcel_interface!(u16)),
        Box::new(read_parcel_interface!(u32)),
        Box::new(read_parcel_interface!(u64)),
        Box::new(read_parcel_interface!(String)),
        //read vec of basic types
        Box::new(read_parcel_interface!(Vec<i8>)),
        Box::new(read_parcel_interface!(Vec<i32>)),
        Box::new(read_parcel_interface!(Vec<i64>)),
        Box::new(read_parcel_interface!(Vec<f32>)),
        Box::new(read_parcel_interface!(Vec<f64>)),
        Box::new(read_parcel_interface!(Vec<u16>)),
        Box::new(read_parcel_interface!(Vec<u32>)),
        Box::new(read_parcel_interface!(Vec<u64>)),
        Box::new(read_parcel_interface!(Vec<String>)),
        Box::new(read_parcel_interface!(Option<Vec<i8>>)),
        Box::new(read_parcel_interface!(Option<Vec<i32>>)),
        Box::new(read_parcel_interface!(Option<Vec<i64>>)),
        Box::new(read_parcel_interface!(Option<Vec<f32>>)),
        Box::new(read_parcel_interface!(Option<Vec<f64>>)),
        Box::new(read_parcel_interface!(Option<Vec<u16>>)),
        Box::new(read_parcel_interface!(Option<Vec<u32>>)),
        Box::new(read_parcel_interface!(Option<Vec<u64>>)),
        Box::new(read_parcel_interface!(Option<Vec<String>>)),
        Box::new(read_parcel_interface!(ParcelFileDescriptor)),
        Box::new(read_parcel_interface!(Vec<Option<ParcelFileDescriptor>>)),
        Box::new(read_parcel_interface!(Option<Vec<ParcelFileDescriptor>>)),
        Box::new(read_parcel_interface!(Option<Vec<Option<ParcelFileDescriptor>>>)),
        Box::new(read_parcel_interface!(SpIBinder)),
        Box::new(read_parcel_interface!(Vec<Option<SpIBinder>>)),
        Box::new(read_parcel_interface!(Option<Vec<SpIBinder>>)),
        Box::new(read_parcel_interface!(Option<Vec<Option<SpIBinder>>>)),
        Box::new(read_parcel_interface!(SomeParcelable)),
        Box::new(read_parcel_interface!(Vec<Option<SomeParcelable>>)),
        Box::new(read_parcel_interface!(Option<Vec<SomeParcelable>>)),
        Box::new(read_parcel_interface!(Option<Vec<Option<SomeParcelable>>>)),
        // Fuzz read_from_parcel for AIDL generated parcelables
        Box::new(|parcel| {
            let mut empty_parcelable: EmptyParcelable = EmptyParcelable::default();
            match empty_parcelable.read_from_parcel(parcel) {
                Ok(result) => result,
                Err(e) => {
                    println!("EmptyParcelable: error occurred while reading from a parcel: {:?}", e)
                }
            }
        }),
        Box::new(|parcel| {
            let mut single_parcelable: SingleDataParcelable = SingleDataParcelable::default();
            match single_parcelable.read_from_parcel(parcel) {
                Ok(result) => result,
                Err(e) => println!(
                    "SingleDataParcelable: error occurred while reading from a parcel: {:?}",
                    e
                ),
            }
        }),
        Box::new(|parcel| {
            let mut generic_parcelable: GenericDataParcelable = GenericDataParcelable::default();
            match generic_parcelable.read_from_parcel(parcel) {
                Ok(result) => result,
                Err(e) => println!(
                    "GenericDataParcelable: error occurred while reading from a parcel: {:?}",
                    e
                ),
            }
        }),
    ];

    read_funcs
}
+3 −0
Original line number Diff line number Diff line
@@ -20,6 +20,9 @@ aidl_interface {
        java: {
            enabled: false,
        },
        rust: {
            enabled: true,
        },
    },
}