1 /*
2 * Copyright (C) 2019 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 #define FUZZ_LOG_TAG "main"
17
18 #include "binder.h"
19 #include "binder_ndk.h"
20 #include "hwbinder.h"
21 #include "util.h"
22
23 #include <iostream>
24
25 #include <android-base/logging.h>
26 #include <android/binder_auto_utils.h>
27 #include <android/binder_libbinder.h>
28 #include <fuzzbinder/random_parcel.h>
29 #include <fuzzer/FuzzedDataProvider.h>
30
31 #include <cstdlib>
32 #include <ctime>
33 #include <sys/resource.h>
34 #include <sys/time.h>
35
36 #include "../../Utils.h"
37
38 using android::fillRandomParcel;
39 using android::RandomParcelOptions;
40 using android::sp;
41 using android::HexString;
42
fillRandomParcel(::android::hardware::Parcel * p,FuzzedDataProvider && provider,RandomParcelOptions * options)43 void fillRandomParcel(::android::hardware::Parcel* p, FuzzedDataProvider&& provider,
44 RandomParcelOptions* options) {
45 // TODO: functionality to create random parcels for libhwbinder parcels
46 (void)options;
47
48 std::vector<uint8_t> input = provider.ConsumeRemainingBytes<uint8_t>();
49
50 if (input.size() % 4 != 0) {
51 input.resize(input.size() + (sizeof(uint32_t) - input.size() % sizeof(uint32_t)));
52 }
53 CHECK_EQ(0, input.size() % 4);
54
55 p->setDataCapacity(input.size());
56 for (size_t i = 0; i < input.size(); i += 4) {
57 p->writeInt32(*((int32_t*)(input.data() + i)));
58 }
59
60 CHECK_EQ(0, memcmp(input.data(), p->data(), p->dataSize()));
61 }
fillRandomParcel(NdkParcelAdapter * p,FuzzedDataProvider && provider,RandomParcelOptions * options)62 static void fillRandomParcel(NdkParcelAdapter* p, FuzzedDataProvider&& provider,
63 RandomParcelOptions* options) {
64 // fill underlying parcel using functions to fill random libbinder parcel
65 fillRandomParcel(p->parcel(), std::move(provider), options);
66 }
67
68 template <typename P, typename B>
doTransactFuzz(const char * backend,const sp<B> & binder,FuzzedDataProvider && provider)69 void doTransactFuzz(const char* backend, const sp<B>& binder, FuzzedDataProvider&& provider) {
70 uint32_t code = provider.ConsumeIntegral<uint32_t>();
71 uint32_t flag = provider.ConsumeIntegral<uint32_t>();
72
73 FUZZ_LOG() << "backend: " << backend;
74
75 RandomParcelOptions options;
76
77 P reply;
78 P data;
79 fillRandomParcel(&data, std::move(provider), &options);
80 (void)binder->transact(code, data, &reply, flag);
81 }
82
83 // start with a Parcel full of data (e.g. like you get from another process)
84 template <typename P>
doReadFuzz(const char * backend,const std::vector<ParcelRead<P>> & reads,FuzzedDataProvider && provider)85 void doReadFuzz(const char* backend, const std::vector<ParcelRead<P>>& reads,
86 FuzzedDataProvider&& provider) {
87 // Allow some majority of the bytes to be dedicated to telling us what to
88 // do. The fixed value added here represents that we want to test doing a
89 // lot of 'instructions' even on really short parcels.
90 size_t maxInstructions = 20 + (provider.remaining_bytes() * 2 / 3);
91 // but don't always use that many instructions. We want to allow the fuzzer
92 // to explore large parcels with few instructions if it wants to.
93 std::vector<uint8_t> instructions = provider.ConsumeBytes<uint8_t>(
94 provider.ConsumeIntegralInRange<size_t>(0, maxInstructions));
95
96 RandomParcelOptions options;
97
98 P p;
99 fillRandomParcel(&p, std::move(provider), &options); // consumes provider
100
101 // since we are only using a byte to index
102 CHECK_LE(reads.size(), 255u) << reads.size();
103
104 FUZZ_LOG() << "backend: " << backend;
105 FUZZ_LOG() << "input: " << HexString(p.data(), p.dataSize());
106 FUZZ_LOG() << "instructions: " << HexString(instructions.data(), instructions.size());
107
108 FuzzedDataProvider instructionsProvider(instructions.data(), instructions.size());
109 while (instructionsProvider.remaining_bytes() > 0) {
110 uint8_t idx = instructionsProvider.ConsumeIntegralInRange<uint8_t>(0, reads.size() - 1);
111
112 FUZZ_LOG() << "Instruction " << idx << " avail: " << p.dataAvail()
113 << " pos: " << p.dataPosition() << " cap: " << p.dataCapacity();
114
115 reads[idx](p, instructionsProvider);
116 }
117 }
118
119 template <typename P>
doReadWriteFuzz(const char * backend,const std::vector<ParcelRead<P>> & reads,const std::vector<ParcelWrite<P>> & writes,FuzzedDataProvider && provider)120 void doReadWriteFuzz(const char* backend, const std::vector<ParcelRead<P>>& reads,
121 const std::vector<ParcelWrite<P>>& writes, FuzzedDataProvider&& provider) {
122 RandomParcelOptions options;
123 P p;
124
125 // since we are only using a byte to index
126 CHECK_LE(reads.size() + writes.size(), 255u) << reads.size();
127
128 FUZZ_LOG() << "backend: " << backend;
129
130 while (provider.remaining_bytes() > 0) {
131 uint8_t idx = provider.ConsumeIntegralInRange<uint8_t>(0, reads.size() + writes.size() - 1);
132
133 FUZZ_LOG() << "Instruction " << idx << " avail: " << p.dataAvail()
134 << " pos: " << p.dataPosition() << " cap: " << p.dataCapacity();
135
136 if (idx < reads.size()) {
137 reads.at(idx)(p, provider);
138 } else {
139 writes.at(idx - reads.size())(p, provider, &options);
140 }
141 }
142 }
143
NothingClass_onCreate(void * args)144 void* NothingClass_onCreate(void* args) {
145 return args;
146 }
NothingClass_onDestroy(void *)147 void NothingClass_onDestroy(void* /*userData*/) {}
NothingClass_onTransact(AIBinder *,transaction_code_t,const AParcel *,AParcel *)148 binder_status_t NothingClass_onTransact(AIBinder*, transaction_code_t, const AParcel*, AParcel*) {
149 return STATUS_UNKNOWN_ERROR;
150 }
151 static AIBinder_Class* kNothingClass =
152 AIBinder_Class_define("nothing", NothingClass_onCreate, NothingClass_onDestroy,
153 NothingClass_onTransact);
154
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)155 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
156 if (size <= 1) return 0; // no use
157
158 // avoid timeouts, see b/142617274, b/142473153
159 if (size > 50000) return 0;
160
161 FuzzedDataProvider provider = FuzzedDataProvider(data, size);
162
163 const std::function<void(FuzzedDataProvider&&)> fuzzBackend[] = {
164 [](FuzzedDataProvider&& provider) {
165 doTransactFuzz<
166 ::android::hardware::Parcel>("hwbinder",
167 sp<::android::hardware::BHwBinder>::make(),
168 std::move(provider));
169 },
170 [](FuzzedDataProvider&& provider) {
171 doTransactFuzz<::android::Parcel>("binder", sp<::android::BBinder>::make(),
172 std::move(provider));
173 },
174 [](FuzzedDataProvider&& provider) {
175 // fuzz from the libbinder layer since it's a superset of the
176 // interface you get at the libbinder_ndk layer
177 auto ndkBinder = ndk::SpAIBinder(AIBinder_new(kNothingClass, nullptr));
178 auto binder = AIBinder_toPlatformBinder(ndkBinder.get());
179 doTransactFuzz<::android::Parcel>("binder_ndk", binder, std::move(provider));
180 },
181 [](FuzzedDataProvider&& provider) {
182 doReadFuzz<::android::hardware::Parcel>("hwbinder", HWBINDER_PARCEL_READ_FUNCTIONS,
183 std::move(provider));
184 },
185 [](FuzzedDataProvider&& provider) {
186 doReadFuzz<::android::Parcel>("binder", BINDER_PARCEL_READ_FUNCTIONS,
187 std::move(provider));
188 },
189 [](FuzzedDataProvider&& provider) {
190 doReadFuzz<NdkParcelAdapter>("binder_ndk", BINDER_NDK_PARCEL_READ_FUNCTIONS,
191 std::move(provider));
192 },
193 [](FuzzedDataProvider&& provider) {
194 doReadWriteFuzz<::android::Parcel>("binder", BINDER_PARCEL_READ_FUNCTIONS,
195 BINDER_PARCEL_WRITE_FUNCTIONS,
196 std::move(provider));
197 },
198 [](FuzzedDataProvider&& provider) {
199 doReadWriteFuzz<NdkParcelAdapter>("binder_ndk", BINDER_NDK_PARCEL_READ_FUNCTIONS,
200 BINDER_NDK_PARCEL_WRITE_FUNCTIONS,
201 std::move(provider));
202 },
203 };
204
205 provider.PickValueInArray(fuzzBackend)(std::move(provider));
206
207 return 0;
208 }
209