• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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