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