Loading libs/binder/rust/tests/parcel_fuzzer/Android.bp 0 → 100644 +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", ], }, } libs/binder/rust/tests/parcel_fuzzer/parcel_fuzzer.rs 0 → 100644 +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); } } } }); libs/binder/rust/tests/parcel_fuzzer/read_utils.rs 0 → 100644 +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 } libs/binder/tests/parcel_fuzzer/Android.bp +3 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,9 @@ aidl_interface { java: { enabled: false, }, rust: { enabled: true, }, }, } Loading Loading
libs/binder/rust/tests/parcel_fuzzer/Android.bp 0 → 100644 +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", ], }, }
libs/binder/rust/tests/parcel_fuzzer/parcel_fuzzer.rs 0 → 100644 +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); } } } });
libs/binder/rust/tests/parcel_fuzzer/read_utils.rs 0 → 100644 +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 }
libs/binder/tests/parcel_fuzzer/Android.bp +3 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,9 @@ aidl_interface { java: { enabled: false, }, rust: { enabled: true, }, }, } Loading