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, Parcel, Stability, TransactionCode,
25 };
26 use binder::{
27 declare_binder_interface, BinderFeatures, Interface, Parcelable, ParcelableHolder, SpIBinder,
28 StatusCode,
29 };
30 use binder_random_parcel_rs::create_random_parcel;
31 use libfuzzer_sys::{arbitrary::Arbitrary, fuzz_target};
32
33 #[derive(Arbitrary, Debug)]
34 enum ReadOperation {
35 SetDataPosition { pos: i32 },
36 GetDataSize,
37 ReadParcelableHolder { is_vintf: bool },
38 ReadBasicTypes { instructions: Vec<usize> },
39 }
40
41 #[derive(Arbitrary, Debug)]
42 enum Operation<'a> {
43 Transact { code: u32, flag: u32, data: &'a [u8] },
44 Append { start: i32, len: i32, data1: &'a [u8], data2: &'a [u8], append_all: bool },
45 Read { read_operations: Vec<ReadOperation>, data: &'a [u8] },
46 }
47
48 /// Interface to fuzz transact with random parcel
49 pub trait BinderTransactTest: Interface {}
50
51 declare_binder_interface! {
52 BinderTransactTest["Binder_Transact_Test"] {
53 native: BnBinderTransactTest(on_transact),
54 proxy: BpBinderTransactTest,
55 }
56 }
57
58 impl BinderTransactTest for Binder<BnBinderTransactTest> {}
59
60 impl BinderTransactTest for BpBinderTransactTest {}
61
62 impl BinderTransactTest for () {}
63
on_transact( _service: &dyn BinderTransactTest, _code: TransactionCode, _parcel: &BorrowedParcel<'_>, _reply: &mut BorrowedParcel<'_>, ) -> Result<(), StatusCode>64 fn on_transact(
65 _service: &dyn BinderTransactTest,
66 _code: TransactionCode,
67 _parcel: &BorrowedParcel<'_>,
68 _reply: &mut BorrowedParcel<'_>,
69 ) -> Result<(), StatusCode> {
70 Err(StatusCode::UNKNOWN_ERROR)
71 }
72
do_transact(code: u32, data: &[u8], flag: u32)73 fn do_transact(code: u32, data: &[u8], flag: u32) {
74 let p: Parcel = create_random_parcel(data);
75 let spibinder: Option<SpIBinder> =
76 Some(BnBinderTransactTest::new_binder((), BinderFeatures::default()).as_binder());
77 let _reply = spibinder.submit_transact(code, p, flag);
78 }
79
do_append_fuzz(start: i32, len: i32, data1: &[u8], data2: &[u8], append_all: bool)80 fn do_append_fuzz(start: i32, len: i32, data1: &[u8], data2: &[u8], append_all: bool) {
81 let mut p1 = create_random_parcel(data1);
82 let p2 = create_random_parcel(data2);
83
84 // Fuzz both append methods
85 if append_all {
86 match p1.append_all_from(&p2) {
87 Ok(result) => result,
88 Err(e) => {
89 println!("Error occurred while appending a parcel using append_all_from: {:?}", e)
90 }
91 }
92 } else {
93 match p1.append_from(&p2, start, len) {
94 Ok(result) => result,
95 Err(e) => {
96 println!("Error occurred while appending a parcel using append_from: {:?}", e)
97 }
98 }
99 };
100 }
101
do_read_fuzz(read_operations: Vec<ReadOperation>, data: &[u8])102 fn do_read_fuzz(read_operations: Vec<ReadOperation>, data: &[u8]) {
103 let parcel = create_random_parcel(data);
104
105 for operation in read_operations {
106 match operation {
107 ReadOperation::SetDataPosition { pos } => {
108 // Safety: Safe if pos is less than current size of the parcel.
109 // It relies on C++ code for bound checks
110 unsafe {
111 match parcel.set_data_position(pos) {
112 Ok(result) => result,
113 Err(e) => println!("error occurred while setting data position: {:?}", e),
114 }
115 }
116 }
117
118 ReadOperation::GetDataSize => {
119 let data_size = parcel.get_data_size();
120 println!("data size from parcel: {:?}", data_size);
121 }
122
123 ReadOperation::ReadParcelableHolder { is_vintf } => {
124 let stability = if is_vintf { Stability::Vintf } else { Stability::Local };
125 let mut holder: ParcelableHolder = ParcelableHolder::new(stability);
126 match holder.read_from_parcel(parcel.borrowed_ref()) {
127 Ok(result) => result,
128 Err(err) => {
129 println!("error occurred while reading from parcel: {:?}", err)
130 }
131 }
132 }
133
134 ReadOperation::ReadBasicTypes { instructions } => {
135 for instruction in instructions.iter() {
136 let read_index = instruction % READ_FUNCS.len();
137 READ_FUNCS[read_index](parcel.borrowed_ref());
138 }
139 }
140 }
141 }
142 }
143
144 fuzz_target!(|operation: Operation| {
145 match operation {
146 Operation::Transact { code, flag, data } => {
147 do_transact(code, data, flag);
148 }
149
150 Operation::Append { start, len, data1, data2, append_all } => {
151 do_append_fuzz(start, len, data1, data2, append_all);
152 }
153
154 Operation::Read { read_operations, data } => {
155 do_read_fuzz(read_operations, data);
156 }
157 }
158 });
159