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
20 #include "common/message_loop_thread.h"
21 #include "osi/include/alarm.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 uint64_t 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 *)66 static void cb(void* /*data*/) {
67 ++cb_counter;
68 semaphore.post();
69 }
70
setup()71 void setup() { cb_counter = 0; }
teardown()72 void teardown() {}
73
fuzz_init_alarm(FuzzedDataProvider * dataProvider)74 alarm_t* fuzz_init_alarm(FuzzedDataProvider* dataProvider) {
75 size_t name_len = dataProvider->ConsumeIntegralInRange<size_t>(0, MAX_BUFFER_LEN);
76 std::vector<char> alarm_name_vect =
77 dataProvider->ConsumeBytesWithTerminator<char>(name_len, '\0');
78 char* alarm_name = alarm_name_vect.data();
79
80 // Determine if our alarm will be periodic
81 if (dataProvider->ConsumeBool()) {
82 return alarm_new_periodic(alarm_name);
83 } else {
84 return alarm_new(alarm_name);
85 }
86 }
87
fuzz_set_alarm(alarm_t * alarm,uint64_t interval,alarm_callback_t cb,FuzzedDataProvider * dataProvider)88 bool fuzz_set_alarm(alarm_t* alarm, uint64_t interval, alarm_callback_t cb,
89 FuzzedDataProvider* dataProvider) {
90 // Generate a random buffer (or null)
91 void* data_buffer = nullptr;
92 size_t buff_len = dataProvider->ConsumeIntegralInRange<size_t>(1, MAX_BUFFER_LEN);
93 if (buff_len == 0) {
94 return false;
95 }
96
97 // allocate our space
98 std::vector<uint8_t> data_vector = dataProvider->ConsumeBytes<uint8_t>(buff_len);
99 data_buffer = data_vector.data();
100
101 // Make sure alarm is non-null
102 if (alarm) {
103 // Should this alarm be regular or on mloop?
104 if (dataProvider->ConsumeBool()) {
105 alarm_set_on_mloop(alarm, interval, cb, data_buffer);
106 } else {
107 alarm_set(alarm, interval, cb, data_buffer);
108 }
109 }
110
111 return true;
112 }
113
LLVMFuzzerTestOneInput(const uint8_t * Data,size_t Size)114 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) {
115 // Init our wrapper
116 FuzzedDataProvider dataProvider(Data, Size);
117
118 // Perform setup
119 setup();
120
121 alarm_t* alarm = nullptr;
122 // Should our alarm be valid or null?
123 if (dataProvider.ConsumeBool()) {
124 // Init our alarm
125 alarm = fuzz_init_alarm(&dataProvider);
126 }
127
128 // Set up the alarm & cancel
129 // Alarm must be non-null, or set() will trigger assert
130 if (alarm) {
131 if (!fuzz_set_alarm(alarm, MAX_ALARM_DURATION, cb, &dataProvider)) {
132 alarm_free(alarm);
133 return 0;
134 }
135 alarm_cancel(alarm);
136 }
137
138 // Check if scheduled
139 alarm_is_scheduled(alarm);
140
141 if (alarm) {
142 // Set up another set of alarms & let these ones run
143 int num_alarms = dataProvider.ConsumeIntegralInRange<uint8_t>(0, MAX_CONCURRENT_ALARMS);
144 for (int i = 0; i < num_alarms; i++) {
145 uint64_t interval = dataProvider.ConsumeIntegralInRange<uint64_t>(0, MAX_ALARM_DURATION);
146 if (!fuzz_set_alarm(alarm, interval, cb, &dataProvider)) {
147 num_alarms = i;
148 break;
149 }
150 alarm_get_remaining_ms(alarm);
151 }
152
153 // Wait for them to complete
154 for (int i = 1; i <= num_alarms; i++) {
155 semaphore.wait();
156 }
157 }
158
159 // Free the alarm object
160 alarm_free(alarm);
161
162 // dump debug data to /dev/null
163 int debug_fd = open("/dev/null", O_RDWR);
164 alarm_debug_dump(debug_fd);
165
166 // Cleanup
167 alarm_cleanup();
168
169 // Perform teardown
170 teardown();
171
172 return 0;
173 }
174