1 /*
2  * Copyright 2020 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 #include <fcntl.h>
18 #include <fuzzer/FuzzedDataProvider.h>
19 #include "osi/include/alarm.h"
20 #include "osi/include/semaphore.h"
21 
22 #include "common/message_loop_thread.h"
23 
24 using base::Closure;
25 using base::TimeDelta;
26 using bluetooth::common::MessageLoopThread;
27 
28 #define MAX_CONCURRENT_ALARMS 25
29 #define MAX_BUFFER_LEN 4096
30 #define MAX_ALARM_DURATION 25
31 
32 static semaphore_t* semaphore;
33 static int cb_counter;
34 static base::MessageLoop* message_loop_;
35 
get_main_message_loop()36 base::MessageLoop* get_main_message_loop() { return message_loop_; }
37 
cb(void * data)38 static void cb(void* data) {
39   ++cb_counter;
40   semaphore_post(semaphore);
41 }
42 
setup()43 void setup() {
44   cb_counter = 0;
45   semaphore = semaphore_new(0);
46 }
teardown()47 void teardown() { semaphore_free(semaphore); }
48 
fuzz_init_alarm(FuzzedDataProvider * dataProvider)49 alarm_t* fuzz_init_alarm(FuzzedDataProvider* dataProvider) {
50   size_t name_len =
51       dataProvider->ConsumeIntegralInRange<size_t>(0, MAX_BUFFER_LEN);
52   std::vector<char> alarm_name_vect =
53       dataProvider->ConsumeBytesWithTerminator<char>(name_len, '\0');
54   char* alarm_name = alarm_name_vect.data();
55 
56   // Determine if our alarm will be periodic
57   if (dataProvider->ConsumeBool()) {
58     return alarm_new_periodic(alarm_name);
59   } else {
60     return alarm_new(alarm_name);
61   }
62 }
63 
fuzz_set_alarm(alarm_t * alarm,uint64_t interval,alarm_callback_t cb,FuzzedDataProvider * dataProvider)64 bool fuzz_set_alarm(alarm_t* alarm, uint64_t interval, alarm_callback_t cb,
65                     FuzzedDataProvider* dataProvider) {
66   // Generate a random buffer (or null)
67   void* data_buffer = nullptr;
68   size_t buff_len =
69       dataProvider->ConsumeIntegralInRange<size_t>(1, MAX_BUFFER_LEN);
70   if (buff_len == 0) {
71     return false;
72   }
73 
74   // allocate our space
75   std::vector<uint8_t> data_vector =
76       dataProvider->ConsumeBytes<uint8_t>(buff_len);
77   data_buffer = data_vector.data();
78 
79   // Make sure alarm is non-null
80   if (alarm) {
81     // Should this alarm be regular or on mloop?
82     if (dataProvider->ConsumeBool()) {
83       alarm_set_on_mloop(alarm, interval, cb, data_buffer);
84     } else {
85       alarm_set(alarm, interval, cb, data_buffer);
86     }
87   }
88 
89   return true;
90 }
91 
LLVMFuzzerTestOneInput(const uint8_t * Data,size_t Size)92 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) {
93   // Init our wrapper
94   FuzzedDataProvider dataProvider(Data, Size);
95 
96   // Perform setup
97   setup();
98 
99   alarm_t* alarm = nullptr;
100   // Should our alarm be valid or null?
101   if (dataProvider.ConsumeBool()) {
102     // Init our alarm
103     alarm = fuzz_init_alarm(&dataProvider);
104   }
105 
106   // Set up the alarm & cancel
107   // Alarm must be non-null, or set() will trigger assert
108   if (alarm) {
109     if (!fuzz_set_alarm(alarm, MAX_ALARM_DURATION, cb, &dataProvider)) {
110       return 0;
111     }
112     alarm_cancel(alarm);
113   }
114 
115   // Check if scheduled
116   alarm_is_scheduled(alarm);
117 
118   if (alarm) {
119     // Set up another set of alarms & let these ones run
120     int num_alarms =
121         dataProvider.ConsumeIntegralInRange<uint8_t>(0, MAX_CONCURRENT_ALARMS);
122     for (int i = 0; i < num_alarms; i++) {
123       uint64_t interval =
124           dataProvider.ConsumeIntegralInRange<uint64_t>(0, MAX_ALARM_DURATION);
125       if (fuzz_set_alarm(alarm, interval, cb, &dataProvider)) {
126         return 0;
127       }
128       alarm_get_remaining_ms(alarm);
129     }
130 
131     // Wait for them to complete
132     for (int i = 1; i <= num_alarms; i++) {
133       semaphore_wait(semaphore);
134     }
135   }
136 
137   // Free the alarm object
138   alarm_free(alarm);
139 
140   // dump debug data to /dev/null
141   int debug_fd = open("/dev/null", O_RDWR);
142   alarm_debug_dump(debug_fd);
143 
144   // Cleanup
145   alarm_cleanup();
146 
147   // Perform teardown
148   teardown();
149 
150   return 0;
151 }
152