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