1 /******************************************************************************
2 *
3 * Copyright (C) 2020 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 *****************************************************************************
18 * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
19 */
20 #include <fuzzer/FuzzedDataProvider.h>
21 #include <media/MediaMetricsItem.h>
22 #include <mediametricsservice/AudioTypes.h>
23 #include <mediametricsservice/MediaMetricsService.h>
24 #include <mediametricsservice/StringUtils.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <utils/Log.h>
28 #include <algorithm>
29
30 using namespace android;
31
32 // low water mark
33 constexpr size_t kLogItemsLowWater = 1;
34 // high water mark
35 constexpr size_t kLogItemsHighWater = 2;
36
37 class MediaMetricsServiceFuzzer {
38 public:
39 void invokeStartsWith(const uint8_t *data, size_t size);
40 void invokeInstantiate(const uint8_t *data, size_t size);
41 void invokePackageInstallerCheck(const uint8_t *data, size_t size);
42 void invokeItemManipulation(const uint8_t *data, size_t size);
43 void invokeItemExpansion(const uint8_t *data, size_t size);
44 void invokeTimeMachineStorage(const uint8_t *data, size_t size);
45 void invokeTransactionLog(const uint8_t *data, size_t size);
46 void invokeAnalyticsAction(const uint8_t *data, size_t size);
47 void invokeAudioAnalytics(const uint8_t *data, size_t size);
48 void invokeTimedAction(const uint8_t *data, size_t size);
49 void process(const uint8_t *data, size_t size);
50 std::atomic_int mValue = 0;
51 };
52
invokeStartsWith(const uint8_t * data,size_t size)53 void MediaMetricsServiceFuzzer::invokeStartsWith(const uint8_t *data, size_t size) {
54 FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
55 while (fdp.remaining_bytes()) {
56 android::mediametrics::startsWith(fdp.ConsumeRandomLengthString(),
57 fdp.ConsumeRandomLengthString());
58 }
59 }
60
invokeInstantiate(const uint8_t * data,size_t size)61 void MediaMetricsServiceFuzzer::invokeInstantiate(const uint8_t *data, size_t size) {
62 FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
63 sp mediaMetricsService = new MediaMetricsService();
64
65 while (fdp.remaining_bytes()) {
66 std::unique_ptr<mediametrics::Item> random_key(
67 mediametrics::Item::create(fdp.ConsumeRandomLengthString()));
68 mediaMetricsService->submit(random_key.get());
69 random_key->setInt32(fdp.ConsumeRandomLengthString().c_str(),
70 fdp.ConsumeIntegral<int32_t>());
71 mediaMetricsService->submit(random_key.get());
72
73 std::unique_ptr<mediametrics::Item> audiotrack_key(
74 mediametrics::Item::create("audiotrack"));
75 mediaMetricsService->submit(audiotrack_key.get());
76 audiotrack_key->addInt32(fdp.ConsumeRandomLengthString().c_str(),
77 fdp.ConsumeIntegral<int32_t>());
78 mediaMetricsService->submit(audiotrack_key.get());
79 }
80 }
81
invokePackageInstallerCheck(const uint8_t * data,size_t size)82 void MediaMetricsServiceFuzzer::invokePackageInstallerCheck(const uint8_t *data, size_t size) {
83 FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
84 while (fdp.remaining_bytes()) {
85 MediaMetricsService::useUidForPackage(fdp.ConsumeRandomLengthString().c_str(),
86 fdp.ConsumeRandomLengthString().c_str());
87 }
88 }
89
invokeItemManipulation(const uint8_t * data,size_t size)90 void MediaMetricsServiceFuzzer::invokeItemManipulation(const uint8_t *data, size_t size) {
91 FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
92
93 mediametrics::Item item(fdp.ConsumeRandomLengthString().c_str());
94 while (fdp.remaining_bytes()) {
95 const uint8_t action = fdp.ConsumeIntegralInRange<uint8_t>(0, 16);
96 const std::string key = fdp.ConsumeRandomLengthString();
97 if (fdp.remaining_bytes() < 1 || key.length() < 1) {
98 break;
99 }
100 switch (action) {
101 case 0: {
102 item.setInt32(key.c_str(), fdp.ConsumeIntegral<int32_t>());
103 break;
104 }
105 case 1: {
106 item.addInt32(key.c_str(), fdp.ConsumeIntegral<int32_t>());
107 break;
108 }
109 case 2: {
110 int32_t i32 = 0;
111 item.getInt32(key.c_str(), &i32);
112 break;
113 }
114 case 3: {
115 item.setInt64(key.c_str(), fdp.ConsumeIntegral<int64_t>());
116 break;
117 }
118 case 4: {
119 item.addInt64(key.c_str(), fdp.ConsumeIntegral<int64_t>());
120 break;
121 }
122 case 5: {
123 int64_t i64 = 0;
124 item.getInt64(key.c_str(), &i64);
125 break;
126 }
127 case 6: {
128 item.setDouble(key.c_str(), fdp.ConsumeFloatingPoint<double>());
129 break;
130 }
131 case 7: {
132 item.addDouble(key.c_str(), fdp.ConsumeFloatingPoint<double>());
133 break;
134 }
135 case 8: {
136 double d = 0;
137 item.getDouble(key.c_str(), &d);
138 break;
139 }
140 case 9: {
141 item.setCString(key.c_str(), fdp.ConsumeRandomLengthString().c_str());
142 break;
143 }
144 case 10: {
145 char *s = nullptr;
146 item.getCString(key.c_str(), &s);
147 if (s) free(s);
148 break;
149 }
150 case 11: {
151 std::string s;
152 item.getString(key.c_str(), &s);
153 break;
154 }
155 case 12: {
156 item.setRate(key.c_str(), fdp.ConsumeIntegral<int64_t>(),
157 fdp.ConsumeIntegral<int64_t>());
158 break;
159 }
160 case 13: {
161 int64_t b = 0, h = 0;
162 double d = 0;
163 item.getRate(key.c_str(), &b, &h, &d);
164 break;
165 }
166 case 14: {
167 (void)item.filter(key.c_str());
168 break;
169 }
170 case 15: {
171 const char *arr[1] = {""};
172 arr[0] = const_cast<char *>(key.c_str());
173 (void)item.filterNot(1, arr);
174 break;
175 }
176 case 16: {
177 (void)item.toString().c_str();
178 break;
179 }
180 }
181 }
182
183 Parcel p;
184 mediametrics::Item item2;
185
186 (void)item.writeToParcel(&p);
187 p.setDataPosition(0); // rewind for reading
188 (void)item2.readFromParcel(p);
189
190 char *byteData = nullptr;
191 size_t length = 0;
192 (void)item.writeToByteString(&byteData, &length);
193 (void)item2.readFromByteString(byteData, length);
194 if (byteData) {
195 free(byteData);
196 }
197
198 sp mediaMetricsService = new MediaMetricsService();
199 mediaMetricsService->submit(&item2);
200 }
201
invokeItemExpansion(const uint8_t * data,size_t size)202 void MediaMetricsServiceFuzzer::invokeItemExpansion(const uint8_t *data, size_t size) {
203 FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
204
205 mediametrics::LogItem<1> item("FuzzItem");
206 item.setPid(fdp.ConsumeIntegral<int16_t>()).setUid(fdp.ConsumeIntegral<int16_t>());
207
208 while (fdp.remaining_bytes()) {
209 int32_t i = fdp.ConsumeIntegral<int32_t>();
210 item.set(std::to_string(i).c_str(), (int32_t)i);
211 }
212 item.updateHeader();
213
214 mediametrics::Item item2;
215 (void)item2.readFromByteString(item.getBuffer(), item.getLength());
216
217 sp mediaMetricsService = new MediaMetricsService();
218 mediaMetricsService->submit(&item2);
219 }
220
invokeTimeMachineStorage(const uint8_t * data,size_t size)221 void MediaMetricsServiceFuzzer::invokeTimeMachineStorage(const uint8_t *data, size_t size) {
222 FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
223
224 auto item = std::make_shared<mediametrics::Item>("FuzzKey");
225 int32_t i32 = fdp.ConsumeIntegral<int32_t>();
226 int64_t i64 = fdp.ConsumeIntegral<int64_t>();
227 double d = fdp.ConsumeFloatingPoint<double>();
228 std::string str = fdp.ConsumeRandomLengthString();
229 std::pair<int64_t, int64_t> pair(fdp.ConsumeIntegral<int64_t>(),
230 fdp.ConsumeIntegral<int64_t>());
231 (*item).set("i32", i32).set("i64", i64).set("double", d).set("string", str).set("rate", pair);
232
233 android::mediametrics::TimeMachine timeMachine;
234 timeMachine.put(item, true);
235
236 timeMachine.get("Key", "i32", &i32, -1);
237
238 timeMachine.get("Key", "i64", &i64, -1);
239
240 timeMachine.get("Key", "double", &d, -1);
241
242 timeMachine.get("Key", "string", &str, -1);
243
244 timeMachine.get("Key.i32", &i32, -1);
245
246 timeMachine.get("Key.i64", &i64, -1);
247
248 timeMachine.get("Key.double", &d, -1);
249
250 str.clear();
251 timeMachine.get("Key.string", &str, -1);
252 }
253
invokeTransactionLog(const uint8_t * data,size_t size)254 void MediaMetricsServiceFuzzer::invokeTransactionLog(const uint8_t *data, size_t size) {
255 FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
256
257 auto item = std::make_shared<mediametrics::Item>("Key1");
258 (*item)
259 .set("one", fdp.ConsumeIntegral<int32_t>())
260 .set("two", fdp.ConsumeIntegral<int32_t>())
261 .setTimestamp(fdp.ConsumeIntegral<int32_t>());
262
263 android::mediametrics::TransactionLog transactionLog(
264 kLogItemsLowWater, kLogItemsHighWater); // keep at most 2 items
265 transactionLog.size();
266
267 transactionLog.put(item);
268 transactionLog.size();
269
270 auto item2 = std::make_shared<mediametrics::Item>("Key2");
271 (*item2)
272 .set("three", fdp.ConsumeIntegral<int32_t>())
273 .set("[Key1]three", fdp.ConsumeIntegral<int32_t>())
274 .setTimestamp(fdp.ConsumeIntegral<int32_t>());
275
276 transactionLog.put(item2);
277 transactionLog.size();
278
279 auto item3 = std::make_shared<mediametrics::Item>("Key3");
280 (*item3)
281 .set("six", fdp.ConsumeIntegral<int32_t>())
282 .set("[Key1]four", fdp.ConsumeIntegral<int32_t>()) // affects Key1
283 .set("[Key1]five", fdp.ConsumeIntegral<int32_t>()) // affects key1
284 .setTimestamp(fdp.ConsumeIntegral<int32_t>());
285
286 transactionLog.put(item3);
287 transactionLog.size();
288 }
289
invokeAnalyticsAction(const uint8_t * data,size_t size)290 void MediaMetricsServiceFuzzer::invokeAnalyticsAction(const uint8_t *data, size_t size) {
291 FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
292
293 mediametrics::AnalyticsActions analyticsActions;
294 bool action = false;
295
296 while (fdp.remaining_bytes()) {
297 analyticsActions.addAction(
298 (fdp.ConsumeRandomLengthString() + std::string(".event")).c_str(),
299 fdp.ConsumeRandomLengthString(),
300 std::make_shared<mediametrics::AnalyticsActions::Function>(
301 [&](const std::shared_ptr<const android::mediametrics::Item> &) {
302 action = true;
303 }));
304 }
305
306 FuzzedDataProvider fdp2 = FuzzedDataProvider(data, size);
307
308 while (fdp2.remaining_bytes()) {
309 // make a test item
310 auto item = std::make_shared<mediametrics::Item>(fdp2.ConsumeRandomLengthString().c_str());
311 (*item).set("event", fdp2.ConsumeRandomLengthString().c_str());
312
313 // get the actions and execute them
314 auto actions = analyticsActions.getActionsForItem(item);
315 for (const auto &action : actions) {
316 action->operator()(item);
317 }
318 }
319 }
320
invokeAudioAnalytics(const uint8_t * data,size_t size)321 void MediaMetricsServiceFuzzer::invokeAudioAnalytics(const uint8_t *data, size_t size) {
322 FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
323 std::shared_ptr<android::mediametrics::StatsdLog> statsdLog =
324 std::make_shared<android::mediametrics::StatsdLog>(10);
325 android::mediametrics::AudioAnalytics audioAnalytics{statsdLog};
326
327 while (fdp.remaining_bytes()) {
328 auto item = std::make_shared<mediametrics::Item>(fdp.ConsumeRandomLengthString().c_str());
329 int32_t transactionUid = fdp.ConsumeIntegral<int32_t>(); // arbitrary
330 (*item)
331 .set(fdp.ConsumeRandomLengthString().c_str(), fdp.ConsumeIntegral<int32_t>())
332 .set(fdp.ConsumeRandomLengthString().c_str(), fdp.ConsumeIntegral<int32_t>())
333 .set(AMEDIAMETRICS_PROP_ALLOWUID, transactionUid)
334 .setUid(transactionUid)
335 .setTimestamp(fdp.ConsumeIntegral<int32_t>());
336 audioAnalytics.submit(item, fdp.ConsumeBool());
337 }
338
339 audioAnalytics.dump(1000);
340 }
341
invokeTimedAction(const uint8_t * data,size_t size)342 void MediaMetricsServiceFuzzer::invokeTimedAction(const uint8_t *data, size_t size) {
343 FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
344 android::mediametrics::TimedAction timedAction;
345
346 while (fdp.remaining_bytes()) {
347 timedAction.postIn(std::chrono::seconds(fdp.ConsumeIntegral<int32_t>()),
348 [this] { ++mValue; });
349 timedAction.size();
350 }
351 }
352
process(const uint8_t * data,size_t size)353 void MediaMetricsServiceFuzzer::process(const uint8_t *data, size_t size) {
354 invokeStartsWith(data, size);
355 invokeInstantiate(data, size);
356 invokePackageInstallerCheck(data, size);
357 invokeItemManipulation(data, size);
358 invokeItemExpansion(data, size);
359 invokeTimeMachineStorage(data, size);
360 invokeTransactionLog(data, size);
361 invokeAnalyticsAction(data, size);
362 invokeAudioAnalytics(data, size);
363 invokeTimedAction(data, size);
364 }
365
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)366 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
367 if (size < 1) {
368 return 0;
369 }
370 MediaMetricsServiceFuzzer mediaMetricsServiceFuzzer;
371 mediaMetricsServiceFuzzer.process(data, size);
372 return 0;
373 }
374