xref: /btstack/test/fuzz/fuzz_gatt_client.c (revision 8046a24a193194710101c0c9023edf98ca134a0d)
1 #include <stdint.h>
2 #include <stddef.h>
3 
4 #include "ble/gatt_client.h"
5 #include "btstack_run_loop_posix.h"
6 #include "btstack_memory.h"
7 
8 static  void (*packet_handler)(uint8_t packet_type, uint8_t *packet, uint16_t size);
9 
hci_transport_fuzz_set_baudrate(uint32_t baudrate)10 static int hci_transport_fuzz_set_baudrate(uint32_t baudrate){
11     return 0;
12 }
13 
hci_transport_fuzz_can_send_now(uint8_t packet_type)14 static int hci_transport_fuzz_can_send_now(uint8_t packet_type){
15     return 1;
16 }
17 
hci_transport_fuzz_send_packet(uint8_t packet_type,uint8_t * packet,int size)18 static int hci_transport_fuzz_send_packet(uint8_t packet_type, uint8_t * packet, int size){
19     return 0;
20 }
21 
hci_transport_fuzz_init(const void * transport_config)22 static void hci_transport_fuzz_init(const void * transport_config){
23 }
24 
hci_transport_fuzz_open(void)25 static int hci_transport_fuzz_open(void){
26     return 0;
27 }
28 
hci_transport_fuzz_close(void)29 static int hci_transport_fuzz_close(void){
30     return 0;
31 }
32 
hci_transport_fuzz_register_packet_handler(void (* handler)(uint8_t packet_type,uint8_t * packet,uint16_t size))33 static void hci_transport_fuzz_register_packet_handler(void (*handler)(uint8_t packet_type, uint8_t *packet, uint16_t size)){
34     packet_handler = handler;
35 }
36 
37 static const hci_transport_t hci_transport_fuzz = {
38         /* const char * name; */                                        "FUZZ",
39         /* void   (*init) (const void *transport_config); */            &hci_transport_fuzz_init,
40         /* int    (*open)(void); */                                     &hci_transport_fuzz_open,
41         /* int    (*close)(void); */                                    &hci_transport_fuzz_close,
42         /* void   (*register_packet_handler)(void (*handler)(...); */   &hci_transport_fuzz_register_packet_handler,
43         /* int    (*can_send_packet_now)(uint8_t packet_type); */       &hci_transport_fuzz_can_send_now,
44         /* int    (*send_packet)(...); */                               &hci_transport_fuzz_send_packet,
45         /* int    (*set_baudrate)(uint32_t baudrate); */                &hci_transport_fuzz_set_baudrate,
46         /* void   (*reset_link)(void); */                               NULL,
47         /* void   (*set_sco_config)(uint16_t voice_setting, int num_connections); */ NULL,
48 };
49 
gatt_client_packet_handler(uint8_t packet_type,uint16_t handle,uint8_t * packet,uint16_t size)50 static void gatt_client_packet_handler(uint8_t packet_type, uint16_t handle, uint8_t *packet, uint16_t size){
51 }
52 
set_gatt_service_uuid16(gatt_client_service_t * service,const uint8_t * data,size_t size)53 void set_gatt_service_uuid16(gatt_client_service_t * service, const uint8_t *data, size_t size){
54     service->start_group_handle = 0x0001;
55     service->end_group_handle = 0xffff;
56     memset(service->uuid128, 0, 16);
57     service->uuid16 = big_endian_read_16(data, 0);
58 }
59 
set_gatt_service_uuid128(gatt_client_service_t * service,const uint8_t * data,size_t size)60 void set_gatt_service_uuid128(gatt_client_service_t * service, const uint8_t *data, size_t size){
61     service->start_group_handle = 0x0001;
62     service->end_group_handle = 0xffff;
63     service->uuid16 = 0;
64     memcpy(service->uuid128, data, 16);
65 }
66 
set_gatt_characteristic_uuid16(gatt_client_characteristic_t * characteristic,const uint8_t * data,size_t size)67 void set_gatt_characteristic_uuid16(gatt_client_characteristic_t * characteristic, const uint8_t *data, size_t size){
68     characteristic->start_handle = 0x0001;
69     characteristic->value_handle = 0x0002;
70     characteristic->end_handle = 0xffff;
71     characteristic->uuid16 = big_endian_read_16(data, 0);
72     memset(characteristic->uuid128, 0, 16);
73 }
74 
set_gatt_characteristic_uuid128(gatt_client_characteristic_t * characteristic,const uint8_t * data,size_t size)75 void set_gatt_characteristic_uuid128(gatt_client_characteristic_t * characteristic, const uint8_t *data, size_t size){
76     characteristic->start_handle = 0x0001;
77     characteristic->value_handle = 0x0002;
78     characteristic->end_handle = 0xffff;
79     characteristic->uuid16 = 0;
80     memcpy(characteristic->uuid128, data, 16);
81 }
82 
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)83 int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
84     const hci_con_handle_t ble_handle = 0x0005;
85 
86     static bool gatt_client_initiated = false;
87     if (!gatt_client_initiated){
88         btstack_memory_init();
89         btstack_run_loop_init(btstack_run_loop_posix_get_instance());
90         // init hci, simulate connection
91         hci_init(&hci_transport_fuzz, NULL);
92         hci_setup_test_connections_fuzz();
93 
94         gatt_client_init();
95         gatt_client_mtu_enable_auto_negotiation(0);
96         gatt_client_initiated = true;
97     }
98 
99     // use first byte of random data to pick gatt_client request / set gatt client state
100     // then, only use data from second byte as response
101     // prepare test data
102     if (size < 1) return 0;
103     uint8_t  cmd_type  = (data[0] & 0x1F);
104     size--;
105     data++;
106 
107     uint8_t  uuid128[16];
108     uint16_t uuid16;
109     int offset = 0;
110     gatt_client_service_t service;
111     gatt_client_characteristic_t characteristic;
112     gatt_client_characteristic_descriptor_t descriptor;
113 
114     uint8_t response_type = 0;
115     switch (cmd_type){
116         case 1:
117             gatt_client_discover_primary_services(gatt_client_packet_handler, ble_handle);
118             response_type = ATT_READ_BY_GROUP_TYPE_RESPONSE;
119             break;
120         case 2:
121             offset = 2;
122             if (size < offset) return 0;
123             uuid16 = big_endian_read_16(data, 0);
124             gatt_client_discover_primary_services_by_uuid16(gatt_client_packet_handler, ble_handle, uuid16);
125             response_type = ATT_FIND_BY_TYPE_VALUE_RESPONSE;
126             break;
127         case 3:
128             offset = 16;
129             if (size < offset) return 0;
130             memcpy(uuid128, data, 16);
131             gatt_client_discover_primary_services_by_uuid128(gatt_client_packet_handler, ble_handle, uuid128);
132             response_type = ATT_FIND_BY_TYPE_VALUE_RESPONSE;
133             break;
134         case 4:
135             offset = 2;
136             if (size < offset) return 0;
137             set_gatt_service_uuid16(&service, data, size);
138             gatt_client_find_included_services_for_service(gatt_client_packet_handler, ble_handle, &service);
139             response_type = ATT_READ_BY_TYPE_RESPONSE;
140             break;
141         case 5:
142             offset = 2;
143             if (size < offset) return 0;
144             set_gatt_service_uuid16(&service, data, size);
145             gatt_client_discover_characteristics_for_service(gatt_client_packet_handler, ble_handle, &service);
146             response_type = ATT_READ_BY_TYPE_RESPONSE;
147             break;
148         case 6:
149             offset = 2;
150             if (size < offset) return 0;
151             uuid16 = big_endian_read_16(data, 0);
152             gatt_client_discover_characteristics_for_handle_range_by_uuid16(gatt_client_packet_handler, ble_handle, 0x0001, 0xffff, uuid16);
153             response_type = ATT_READ_BY_TYPE_RESPONSE;
154             break;
155         case 7:
156             offset = 16;
157             if (size < offset) return 0;
158             memcpy(uuid128, data, 16);
159             gatt_client_discover_characteristics_for_handle_range_by_uuid128(gatt_client_packet_handler, ble_handle, 0x0001, 0xffff, uuid128);
160             response_type = ATT_READ_BY_TYPE_RESPONSE;
161             break;
162         case 8:
163             offset = 4;
164             if (size < offset) return 0;
165             set_gatt_service_uuid16(&service, data, size);
166             uuid16 = big_endian_read_16(data, 2);
167             gatt_client_discover_characteristics_for_service_by_uuid16(gatt_client_packet_handler, ble_handle, &service, uuid16);
168             response_type = ATT_READ_BY_TYPE_RESPONSE;
169             break;
170         case 9:
171             offset = 18;
172             if (size < offset) return 0;
173             set_gatt_service_uuid16(&service, data, size);
174             memcpy(uuid128, data + 2, 16);
175             gatt_client_discover_characteristics_for_service_by_uuid128(gatt_client_packet_handler, ble_handle, &service, uuid128);
176             response_type = ATT_READ_BY_TYPE_RESPONSE;
177             break;
178         case 10:
179             offset = 2;
180             if (size < offset) return 0;
181             set_gatt_characteristic_uuid16(&characteristic, data, size);
182             gatt_client_discover_characteristic_descriptors(gatt_client_packet_handler, ble_handle, &characteristic);
183             response_type = ATT_FIND_INFORMATION_REPLY;
184             break;
185         case 11:
186             offset = 2;
187             if (size < offset) return 0;
188             set_gatt_characteristic_uuid16(&characteristic, data, size);
189             gatt_client_read_value_of_characteristic(gatt_client_packet_handler, ble_handle, &characteristic);
190             response_type = ATT_READ_RESPONSE;
191             break;
192         case 12:
193             offset = 2;
194             if (size < offset) return 0;
195             set_gatt_characteristic_uuid16(&characteristic, data, size);
196             gatt_client_read_value_of_characteristics_by_uuid16(gatt_client_packet_handler, ble_handle, characteristic.start_handle, characteristic.end_handle, characteristic.uuid16);
197             response_type = ATT_READ_BY_TYPE_RESPONSE;
198             break;
199         case 13:
200             offset = 16;
201             if (size < offset) return 0;
202             set_gatt_characteristic_uuid128(&characteristic, data, size);
203             gatt_client_read_value_of_characteristics_by_uuid128(gatt_client_packet_handler, ble_handle, characteristic.start_handle, characteristic.end_handle, characteristic.uuid128);
204             response_type = ATT_READ_BY_TYPE_RESPONSE;
205             break;
206         case 14:
207             offset = 2;
208             if (size < offset) return 0;
209             set_gatt_characteristic_uuid16(&characteristic, data, size);
210             gatt_client_read_long_value_of_characteristic(gatt_client_packet_handler, ble_handle, &characteristic);
211             response_type = ATT_READ_BLOB_RESPONSE;
212             break;
213         case 15:
214             offset = 4;
215             if (size < offset) return 0;
216             set_gatt_characteristic_uuid16(&characteristic, data, size);
217             gatt_client_read_long_value_of_characteristic_using_value_handle_with_offset(gatt_client_packet_handler, ble_handle, characteristic.value_handle, big_endian_read_16(data, 2));
218             response_type = ATT_READ_BLOB_RESPONSE;
219             break;
220         case 16:
221             gatt_client_read_multiple_characteristic_values(gatt_client_packet_handler, ble_handle, 0, NULL);
222             response_type = ATT_READ_MULTIPLE_RESPONSE;
223             break;
224         case 17:
225             gatt_client_write_value_of_characteristic(gatt_client_packet_handler, ble_handle, 5, 0, NULL);
226             response_type = ATT_WRITE_RESPONSE;
227             break;
228         case 18:
229             gatt_client_write_long_value_of_characteristic(gatt_client_packet_handler, ble_handle, 5, 0, NULL);
230             response_type = ATT_PREPARE_WRITE_RESPONSE;
231             break;
232         case 19:
233             gatt_client_reliable_write_long_value_of_characteristic(gatt_client_packet_handler, ble_handle, 5, 0, NULL);
234             response_type = ATT_PREPARE_WRITE_RESPONSE;
235             break;
236         case 20:
237             gatt_client_read_characteristic_descriptor_using_descriptor_handle(gatt_client_packet_handler, ble_handle, 5);
238             response_type = ATT_READ_RESPONSE;
239             break;
240         case 21:
241             gatt_client_read_long_characteristic_descriptor_using_descriptor_handle(gatt_client_packet_handler, ble_handle, 5);
242             response_type = ATT_READ_BLOB_RESPONSE;
243             break;
244         case 22:
245             gatt_client_write_characteristic_descriptor_using_descriptor_handle(gatt_client_packet_handler, ble_handle, 5, 0, NULL);
246             response_type = ATT_PREPARE_WRITE_RESPONSE;
247             break;
248         case 23:
249             gatt_client_write_long_characteristic_descriptor_using_descriptor_handle(gatt_client_packet_handler, ble_handle, 5, 0, NULL);
250             response_type = ATT_PREPARE_WRITE_RESPONSE;
251             break;
252         case 24:
253             offset = 2;
254             if (size < offset) return 0;
255             set_gatt_characteristic_uuid16(&characteristic, data, size);
256             gatt_client_write_client_characteristic_configuration(gatt_client_packet_handler, ble_handle, &characteristic, 1);
257 #ifdef ENABLE_GATT_FIND_INFORMATION_FOR_CCC_DISCOVERY
258             response_type = ATT_FIND_INFORMATION_REPLY;
259 #else
260             response_type = ATT_READ_BY_TYPE_RESPONSE;
261 #endif
262             break;
263         case 25:
264             gatt_client_prepare_write(gatt_client_packet_handler, ble_handle, 5, 0, 0, NULL);
265             response_type = ATT_PREPARE_WRITE_RESPONSE;
266             break;
267 
268 #if 0
269         // TODO: won't work as only single packet is simulate
270         case 26:
271             gatt_client_prepare_write(gatt_client_packet_handler, ble_handle, 5, 0, 0, NULL);
272             response_type = ATT_PREPARE_WRITE_RESPONSE;
273             gatt_client_execute_write(gatt_client_packet_handler, ble_handle);
274             break;
275         case 27:
276             gatt_client_prepare_write(gatt_client_packet_handler, ble_handle, 5, 0, 0, NULL);
277             response_type = ATT_PREPARE_WRITE_RESPONSE;
278             gatt_client_cancel_write(gatt_client_packet_handler, ble_handle);
279             break;
280 #endif
281         default:
282             return 0;
283     }
284 
285     data += offset;
286     size -= offset;
287 
288     uint8_t response_buffer[256];
289     response_buffer[0] = response_type;
290     uint32_t bytes_to_copy = btstack_min(size, sizeof(response_buffer)-1);
291     memcpy(&response_buffer[1], data, bytes_to_copy);
292     // send test response
293     gatt_client_att_packet_handler_fuzz(ATT_DATA_PACKET, ble_handle, response_buffer, bytes_to_copy+1);
294     return 0;
295 }
296