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