xref: /aosp_15_r20/frameworks/native/libs/binder/rust/tests/parcel_fuzzer/parcel_fuzzer.rs (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #![allow(missing_docs)]
18 #![no_main]
19 
20 mod read_utils;
21 
22 use crate::read_utils::READ_FUNCS;
23 use binder::binder_impl::{
24     Binder, BorrowedParcel, IBinderInternal, LocalStabilityType, Parcel, TransactionCode,
25     VintfStabilityType,
26 };
27 use binder::{
28     declare_binder_interface, BinderFeatures, Interface, Parcelable, ParcelableHolder, SpIBinder,
29     StatusCode,
30 };
31 use binder_random_parcel_rs::create_random_parcel;
32 use libfuzzer_sys::{arbitrary::Arbitrary, fuzz_target};
33 
34 #[derive(Arbitrary, Debug)]
35 enum ReadOperation {
36     SetDataPosition { pos: i32 },
37     GetDataSize,
38     ReadParcelableHolder { is_vintf: bool },
39     ReadBasicTypes { instructions: Vec<usize> },
40 }
41 
42 #[derive(Arbitrary, Debug)]
43 enum Operation<'a> {
44     Transact { code: u32, flag: u32, data: &'a [u8] },
45     Append { start: i32, len: i32, data1: &'a [u8], data2: &'a [u8], append_all: bool },
46     Read { read_operations: Vec<ReadOperation>, data: &'a [u8] },
47 }
48 
49 /// Interface to fuzz transact with random parcel
50 pub trait BinderTransactTest: Interface {}
51 
52 declare_binder_interface! {
53     BinderTransactTest["Binder_Transact_Test"] {
54         native: BnBinderTransactTest(on_transact),
55         proxy: BpBinderTransactTest,
56     }
57 }
58 
59 impl BinderTransactTest for Binder<BnBinderTransactTest> {}
60 
61 impl BinderTransactTest for BpBinderTransactTest {}
62 
63 impl BinderTransactTest for () {}
64 
on_transact( _service: &dyn BinderTransactTest, _code: TransactionCode, _parcel: &BorrowedParcel<'_>, _reply: &mut BorrowedParcel<'_>, ) -> Result<(), StatusCode>65 fn on_transact(
66     _service: &dyn BinderTransactTest,
67     _code: TransactionCode,
68     _parcel: &BorrowedParcel<'_>,
69     _reply: &mut BorrowedParcel<'_>,
70 ) -> Result<(), StatusCode> {
71     Err(StatusCode::UNKNOWN_ERROR)
72 }
73 
do_transact(code: u32, data: &[u8], flag: u32)74 fn do_transact(code: u32, data: &[u8], flag: u32) {
75     let p: Parcel = create_random_parcel(data);
76     let spibinder: Option<SpIBinder> =
77         Some(BnBinderTransactTest::new_binder((), BinderFeatures::default()).as_binder());
78     let _reply = spibinder.submit_transact(code, p, flag);
79 }
80 
do_append_fuzz(start: i32, len: i32, data1: &[u8], data2: &[u8], append_all: bool)81 fn do_append_fuzz(start: i32, len: i32, data1: &[u8], data2: &[u8], append_all: bool) {
82     let mut p1 = create_random_parcel(data1);
83     let p2 = create_random_parcel(data2);
84 
85     // Fuzz both append methods
86     if append_all {
87         match p1.append_all_from(&p2) {
88             Ok(result) => result,
89             Err(e) => {
90                 println!("Error occurred while appending a parcel using append_all_from: {:?}", e)
91             }
92         }
93     } else {
94         match p1.append_from(&p2, start, len) {
95             Ok(result) => result,
96             Err(e) => {
97                 println!("Error occurred while appending a parcel using append_from: {:?}", e)
98             }
99         }
100     };
101 }
102 
do_read_fuzz(read_operations: Vec<ReadOperation>, data: &[u8])103 fn do_read_fuzz(read_operations: Vec<ReadOperation>, data: &[u8]) {
104     let parcel = create_random_parcel(data);
105 
106     for operation in read_operations {
107         match operation {
108             ReadOperation::SetDataPosition { pos } => {
109                 // Safety: Safe if pos is less than current size of the parcel.
110                 // It relies on C++ code for bound checks
111                 unsafe {
112                     match parcel.set_data_position(pos) {
113                         Ok(result) => result,
114                         Err(e) => println!("error occurred while setting data position: {:?}", e),
115                     }
116                 }
117             }
118 
119             ReadOperation::GetDataSize => {
120                 let data_size = parcel.get_data_size();
121                 println!("data size from parcel: {:?}", data_size);
122             }
123 
124             ReadOperation::ReadParcelableHolder { is_vintf } => {
125                 let result = if is_vintf {
126                     ParcelableHolder::<VintfStabilityType>::new()
127                         .read_from_parcel(parcel.borrowed_ref())
128                 } else {
129                     ParcelableHolder::<LocalStabilityType>::new()
130                         .read_from_parcel(parcel.borrowed_ref())
131                 };
132                 if let Err(e) = result {
133                     println!("error occurred while reading from parcel: {e:?}")
134                 }
135             }
136 
137             ReadOperation::ReadBasicTypes { instructions } => {
138                 for instruction in instructions.iter() {
139                     let read_index = instruction % READ_FUNCS.len();
140                     READ_FUNCS[read_index](parcel.borrowed_ref());
141                 }
142             }
143         }
144     }
145 }
146 
147 fuzz_target!(|operation: Operation| {
148     match operation {
149         Operation::Transact { code, flag, data } => {
150             do_transact(code, data, flag);
151         }
152 
153         Operation::Append { start, len, data1, data2, append_all } => {
154             do_append_fuzz(start, len, data1, data2, append_all);
155         }
156 
157         Operation::Read { read_operations, data } => {
158             do_read_fuzz(read_operations, data);
159         }
160     }
161 });
162