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