Coverage Report

Created: 2024-07-27 06:08

/src/spice-usbredir/fuzzing/usbredirparserfuzz.cc
Line
Count
Source (jump to first uncovered line)
1
/* usbredirparserfuzz.cc -- fuzzing for usbredirparser
2
3
   Copyright 2021 Michael Hanselmann
4
5
   This program is free software; you can redistribute it and/or
6
   modify it under the terms of the GNU General Public
7
   License as published by the Free Software Foundation; either
8
   version 2 of the License, or (at your option) any later version.
9
10
   This program is distributed in the hope that it will be useful,
11
   but WITHOUT ANY WARRANTY; without even the implied warranty of
12
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
   General Public License for more details.
14
15
   You should have received a copy of the GNU General Public License
16
   along with this library; if not, see <http://www.gnu.org/licenses/>.
17
*/
18
19
#include <array>
20
#include <algorithm>
21
#include <memory>
22
#include <type_traits>
23
24
#include <cassert>
25
#include <cinttypes>
26
#include <cstring>
27
#include <limits>
28
29
#include <sys/types.h>
30
#include <unistd.h>
31
32
#include <fuzzer/FuzzedDataProvider.h>
33
34
#include "usbredirfilter.h"
35
#include "usbredirparser.h"
36
37
namespace {
38
struct ParserDeleter {
39
3.20k
    void operator()(struct usbredirparser *p) {
40
3.20k
        usbredirparser_destroy(p);
41
3.20k
    }
42
};
43
44
std::unique_ptr<struct usbredirparser, ParserDeleter> parser;
45
std::unique_ptr<FuzzedDataProvider> fdp;
46
47
void parser_log(void *priv, int level, const char *msg)
48
866k
{
49
866k
}
50
51
int wobbly_read_write_count(int count)
52
5.77M
{
53
5.77M
    if (count > (1024 * 1024)) {
54
170
        return count;
55
170
    }
56
57
5.77M
    return std::min(count, fdp->ConsumeIntegralInRange(1, 4 * count));
58
5.77M
}
59
60
int parser_read(void *priv, uint8_t *data, int count)
61
3.58M
{
62
    // Simulate short reads
63
3.58M
    return fdp->ConsumeData(data, wobbly_read_write_count(count));
64
3.58M
}
65
66
// Read over complete input buffer to detect buffer overflows
67
void read_all(const void *data, size_t count)
68
2.19M
{
69
#ifdef __cpp_lib_smart_ptr_for_overwrite
70
    const auto buf = std::make_unique_for_overwrite<uint8_t[]>(count);
71
#else
72
2.19M
    const auto buf = std::make_unique<uint8_t[]>(count);
73
2.19M
#endif
74
75
2.19M
    memcpy(buf.get(), data, count);
76
2.19M
}
77
78
template <typename T, typename = std::enable_if_t<std::is_class<T>::value>>
79
void read_all(const T *ptr)
80
3.13k
{
81
3.13k
    read_all(ptr, sizeof(T));
82
3.13k
}
usbredirparserfuzz.cc:void (anonymous namespace)::read_all<usb_redir_control_packet_header, void>(usb_redir_control_packet_header const*)
Line
Count
Source
80
659
{
81
659
    read_all(ptr, sizeof(T));
82
659
}
usbredirparserfuzz.cc:void (anonymous namespace)::read_all<usb_redir_bulk_packet_header, void>(usb_redir_bulk_packet_header const*)
Line
Count
Source
80
538
{
81
538
    read_all(ptr, sizeof(T));
82
538
}
usbredirparserfuzz.cc:void (anonymous namespace)::read_all<usb_redir_iso_packet_header, void>(usb_redir_iso_packet_header const*)
Line
Count
Source
80
549
{
81
549
    read_all(ptr, sizeof(T));
82
549
}
usbredirparserfuzz.cc:void (anonymous namespace)::read_all<usb_redir_interrupt_packet_header, void>(usb_redir_interrupt_packet_header const*)
Line
Count
Source
80
486
{
81
486
    read_all(ptr, sizeof(T));
82
486
}
usbredirparserfuzz.cc:void (anonymous namespace)::read_all<usb_redir_start_bulk_receiving_header, void>(usb_redir_start_bulk_receiving_header const*)
Line
Count
Source
80
216
{
81
216
    read_all(ptr, sizeof(T));
82
216
}
usbredirparserfuzz.cc:void (anonymous namespace)::read_all<usb_redir_stop_bulk_receiving_header, void>(usb_redir_stop_bulk_receiving_header const*)
Line
Count
Source
80
202
{
81
202
    read_all(ptr, sizeof(T));
82
202
}
usbredirparserfuzz.cc:void (anonymous namespace)::read_all<usb_redir_bulk_receiving_status_header, void>(usb_redir_bulk_receiving_status_header const*)
Line
Count
Source
80
230
{
81
230
    read_all(ptr, sizeof(T));
82
230
}
usbredirparserfuzz.cc:void (anonymous namespace)::read_all<usb_redir_buffered_bulk_packet_header, void>(usb_redir_buffered_bulk_packet_header const*)
Line
Count
Source
80
253
{
81
253
    read_all(ptr, sizeof(T));
82
253
}
83
84
int parser_write(void *priv, uint8_t *data, int count)
85
2.19M
{
86
    // Simulate short writes
87
2.19M
    count = wobbly_read_write_count(count);
88
89
2.19M
    read_all(data, count);
90
91
2.19M
    return count;
92
2.19M
}
93
94
void parser_device_connect(void *priv,
95
    struct usb_redir_device_connect_header *device_connect)
96
240
{
97
240
}
98
99
void parser_device_disconnect(void *priv)
100
118k
{
101
118k
}
102
103
void parser_reset(void *priv)
104
252
{
105
252
}
106
107
void parser_interface_info(void *priv,
108
    struct usb_redir_interface_info_header *info)
109
199
{
110
199
}
111
112
void parser_ep_info(void *priv,
113
    struct usb_redir_ep_info_header *ep_info)
114
220
{
115
220
}
116
117
void parser_set_configuration(void *priv, uint64_t id,
118
    struct usb_redir_set_configuration_header *set_configuration)
119
322
{
120
322
}
121
122
void parser_get_configuration(void *priv, uint64_t id)
123
197
{
124
197
}
125
126
void parser_configuration_status(void *priv, uint64_t id,
127
    struct usb_redir_configuration_status_header *config_status)
128
220
{
129
220
}
130
131
void parser_set_alt_setting(void *priv, uint64_t id,
132
    struct usb_redir_set_alt_setting_header *set_alt_setting)
133
194
{
134
194
}
135
136
void parser_get_alt_setting(void *priv, uint64_t id,
137
    struct usb_redir_get_alt_setting_header *get_alt_setting)
138
196
{
139
196
}
140
141
void parser_alt_setting_status(void *priv, uint64_t id,
142
    struct usb_redir_alt_setting_status_header *alt_setting_status)
143
195
{
144
195
}
145
146
void parser_start_iso_stream(void *priv, uint64_t id,
147
    struct usb_redir_start_iso_stream_header *start_iso_stream)
148
194
{
149
194
}
150
151
void parser_stop_iso_stream(void *priv, uint64_t id,
152
    struct usb_redir_stop_iso_stream_header *stop_iso_stream)
153
197
{
154
197
}
155
156
void parser_iso_stream_status(void *priv, uint64_t id,
157
    struct usb_redir_iso_stream_status_header *iso_stream_status)
158
318
{
159
318
}
160
161
void parser_start_interrupt_receiving(void *priv, uint64_t id,
162
    struct usb_redir_start_interrupt_receiving_header *start_interrupt_receiving)
163
354
{
164
354
}
165
166
void parser_stop_interrupt_receiving(void *priv, uint64_t id,
167
    struct usb_redir_stop_interrupt_receiving_header *stop_interrupt_receiving)
168
322
{
169
322
}
170
171
void parser_interrupt_receiving_status(void *priv, uint64_t id,
172
    struct usb_redir_interrupt_receiving_status_header *interrupt_receiving_status)
173
334
{
174
334
}
175
176
void parser_alloc_bulk_streams(void *priv, uint64_t id,
177
    struct usb_redir_alloc_bulk_streams_header *alloc_bulk_streams)
178
209
{
179
209
}
180
181
void parser_free_bulk_streams(void *priv, uint64_t id,
182
    struct usb_redir_free_bulk_streams_header *free_bulk_streams)
183
194
{
184
194
}
185
186
void parser_bulk_streams_status(void *priv, uint64_t id,
187
    struct usb_redir_bulk_streams_status_header *bulk_streams_status)
188
194
{
189
194
}
190
191
void parser_cancel_data_packet(void *priv, uint64_t id)
192
194
{
193
194
}
194
195
void parser_filter_reject(void *priv)
196
196
{
197
196
}
198
199
void parser_filter_filter(void *priv,
200
    struct usbredirfilter_rule *rules, int rules_count)
201
474
{
202
474
    usbredirfilter_free(rules);
203
474
}
204
205
void parser_control_packet(void *priv, uint64_t id,
206
    struct usb_redir_control_packet_header *control_packet,
207
    uint8_t *data, int data_len)
208
659
{
209
659
    read_all(control_packet);
210
659
    read_all(data, data_len);
211
659
    usbredirparser_free_packet_data(parser.get(), data);
212
659
}
213
214
void parser_bulk_packet(void *priv, uint64_t id,
215
    struct usb_redir_bulk_packet_header *bulk_packet,
216
    uint8_t *data, int data_len)
217
538
{
218
538
    read_all(bulk_packet);
219
538
    read_all(data, data_len);
220
538
    usbredirparser_free_packet_data(parser.get(), data);
221
538
}
222
223
void parser_iso_packet(void *priv, uint64_t id,
224
    struct usb_redir_iso_packet_header *iso_packet,
225
    uint8_t *data, int data_len)
226
549
{
227
549
    read_all(iso_packet);
228
549
    read_all(data, data_len);
229
549
    usbredirparser_free_packet_data(parser.get(), data);
230
549
}
231
232
void parser_interrupt_packet(void *priv, uint64_t id,
233
    struct usb_redir_interrupt_packet_header *interrupt_packet,
234
    uint8_t *data, int data_len)
235
486
{
236
486
    read_all(interrupt_packet);
237
486
    read_all(data, data_len);
238
486
    usbredirparser_free_packet_data(parser.get(), data);
239
486
}
240
241
void parser_buffered_bulk_packet(void *priv, uint64_t id,
242
    struct usb_redir_buffered_bulk_packet_header *buffered_bulk_header,
243
    uint8_t *data, int data_len)
244
253
{
245
253
    read_all(buffered_bulk_header);
246
253
    read_all(data, data_len);
247
253
    usbredirparser_free_packet_data(parser.get(), data);
248
253
}
249
250
void *parser_alloc_lock()
251
3.20k
{
252
3.20k
    return nullptr;
253
3.20k
}
254
255
void parser_lock(void *lock)
256
0
{
257
0
}
258
259
void parser_unlock(void *lock)
260
0
{
261
0
}
262
263
void parser_free_lock(void *lock)
264
0
{
265
0
}
266
267
void parser_hello(void *priv, struct usb_redir_hello_header *h)
268
76
{
269
76
}
270
271
void parser_device_disconnect_ack(void *priv)
272
205
{
273
205
}
274
275
void parser_start_bulk_receiving(void *priv, uint64_t id,
276
    struct usb_redir_start_bulk_receiving_header *start_bulk_receiving)
277
216
{
278
216
    read_all(start_bulk_receiving);
279
216
}
280
281
void parser_stop_bulk_receiving(void *priv, uint64_t id,
282
    struct usb_redir_stop_bulk_receiving_header *stop_bulk_receiving)
283
202
{
284
202
    read_all(stop_bulk_receiving);
285
202
}
286
287
void parser_bulk_receiving_status(void *priv, uint64_t id,
288
    struct usb_redir_bulk_receiving_status_header *bulk_receiving_status)
289
230
{
290
230
    read_all(bulk_receiving_status);
291
230
}
292
293
int try_unserialize(struct usbredirparser *parser, FuzzedDataProvider *fdp)
294
1.02k
{
295
1.02k
    std::vector<uint8_t> state;
296
1.02k
    size_t len = fdp->ConsumeIntegralInRange<size_t>(1, 64 * 1024);
297
298
1.02k
    state.reserve(len);
299
300
1.02k
    if (len >= 4) {
301
991
        const uint32_t magic = USBREDIRPARSER_SERIALIZE_MAGIC;
302
991
        assert(state.empty());
303
991
        state.resize(sizeof(magic));
304
991
        memcpy(state.data(), &magic, sizeof(magic));
305
306
991
        len -= 4;
307
991
    }
308
309
1.02k
    if (len > 0) {
310
1.02k
        const std::vector<uint8_t> payload{fdp->ConsumeBytes<uint8_t>(len)};
311
312
1.02k
        state.insert(state.end(), payload.cbegin(), payload.cend());
313
1.02k
    }
314
315
1.02k
    if (state.empty()) {
316
3
        return 0;
317
3
    }
318
319
1.02k
    state.shrink_to_fit();
320
321
1.02k
    return usbredirparser_unserialize(parser, &state[0], state.size());
322
1.02k
}
323
324
int try_serialize(struct usbredirparser *parser)
325
50.5k
{
326
50.5k
    uint8_t *state = nullptr;
327
50.5k
    int len = 0;
328
50.5k
    int ret;
329
330
50.5k
    ret = usbredirparser_serialize(parser, &state, &len);
331
332
50.5k
    if (ret == 0) {
333
50.5k
        free(state);
334
50.5k
    }
335
336
50.5k
    return ret;
337
50.5k
}
338
}  // namespace
339
340
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
341
3.20k
{
342
3.20k
    std::array<uint32_t, USB_REDIR_CAPS_SIZE> caps = {0};
343
3.20k
    int ret;
344
345
3.20k
    fdp = std::make_unique<FuzzedDataProvider>(data, size);
346
347
3.20k
    parser.reset(usbredirparser_create());
348
3.20k
    if (parser == nullptr) {
349
0
        return 1;
350
0
    }
351
352
3.20k
    parser->log_func = parser_log;
353
3.20k
    parser->read_func = parser_read;
354
3.20k
    parser->write_func = parser_write;
355
3.20k
    parser->device_connect_func = parser_device_connect;
356
3.20k
    parser->device_disconnect_func = parser_device_disconnect;
357
3.20k
    parser->reset_func = parser_reset;
358
3.20k
    parser->interface_info_func = parser_interface_info;
359
3.20k
    parser->ep_info_func = parser_ep_info;
360
3.20k
    parser->set_configuration_func = parser_set_configuration;
361
3.20k
    parser->get_configuration_func = parser_get_configuration;
362
3.20k
    parser->configuration_status_func = parser_configuration_status;
363
3.20k
    parser->set_alt_setting_func = parser_set_alt_setting;
364
3.20k
    parser->get_alt_setting_func = parser_get_alt_setting;
365
3.20k
    parser->alt_setting_status_func = parser_alt_setting_status;
366
3.20k
    parser->start_iso_stream_func = parser_start_iso_stream;
367
3.20k
    parser->stop_iso_stream_func = parser_stop_iso_stream;
368
3.20k
    parser->iso_stream_status_func = parser_iso_stream_status;
369
3.20k
    parser->start_interrupt_receiving_func = parser_start_interrupt_receiving;
370
3.20k
    parser->stop_interrupt_receiving_func = parser_stop_interrupt_receiving;
371
3.20k
    parser->interrupt_receiving_status_func = parser_interrupt_receiving_status;
372
3.20k
    parser->alloc_bulk_streams_func = parser_alloc_bulk_streams;
373
3.20k
    parser->free_bulk_streams_func = parser_free_bulk_streams;
374
3.20k
    parser->bulk_streams_status_func = parser_bulk_streams_status;
375
3.20k
    parser->cancel_data_packet_func = parser_cancel_data_packet;
376
3.20k
    parser->control_packet_func = parser_control_packet;
377
3.20k
    parser->bulk_packet_func = parser_bulk_packet;
378
3.20k
    parser->iso_packet_func = parser_iso_packet;
379
3.20k
    parser->interrupt_packet_func = parser_interrupt_packet;
380
3.20k
    parser->alloc_lock_func = parser_alloc_lock;
381
3.20k
    parser->lock_func = parser_lock;
382
3.20k
    parser->unlock_func = parser_unlock;
383
3.20k
    parser->free_lock_func = parser_free_lock;
384
3.20k
    parser->hello_func = parser_hello;
385
3.20k
    parser->filter_reject_func = parser_filter_reject;
386
3.20k
    parser->filter_filter_func = parser_filter_filter;
387
3.20k
    parser->device_disconnect_ack_func = parser_device_disconnect_ack;
388
3.20k
    parser->start_bulk_receiving_func = parser_start_bulk_receiving;
389
3.20k
    parser->stop_bulk_receiving_func = parser_stop_bulk_receiving;
390
3.20k
    parser->bulk_receiving_status_func = parser_bulk_receiving_status;
391
3.20k
    parser->buffered_bulk_packet_func = parser_buffered_bulk_packet;
392
393
3.20k
    for (uint32_t &cap : caps) {
394
3.20k
        cap = fdp->ConsumeIntegral<decltype(caps)::value_type>();
395
3.20k
    }
396
397
3.20k
    const int init_flags = fdp->ConsumeIntegral<uint8_t>() &
398
3.20k
        (usbredirparser_fl_usb_host | usbredirparser_fl_no_hello);
399
400
3.20k
    usbredirparser_init(parser.get(), "fuzzer", caps.data(), caps.size(),
401
3.20k
                        init_flags);
402
403
3.20k
    if (fdp->ConsumeBool() && try_unserialize(parser.get(), fdp.get()) != 0) {
404
730
        goto out;
405
730
    }
406
407
235k
    while (fdp->remaining_bytes() > 0 ||
408
235k
           usbredirparser_has_data_to_write(parser.get())) {
409
234k
        if (fdp->ConsumeBool() && try_serialize(parser.get()) != 0) {
410
0
            goto out;
411
0
        }
412
413
234k
        if (fdp->remaining_bytes() > 0) {
414
234k
            ret = usbredirparser_do_read(parser.get());
415
416
234k
            switch (ret) {
417
232k
            case usbredirparser_read_parse_error:
418
                // Keep reading
419
232k
                break;
420
1.32k
            default:
421
1.32k
                goto out;
422
234k
            }
423
424
232k
            if (fdp->ConsumeBool() && try_serialize(parser.get()) != 0) {
425
0
                goto out;
426
0
            }
427
232k
        }
428
429
234k
        while (usbredirparser_has_data_to_write(parser.get())) {
430
1.41k
            ret = usbredirparser_do_write(parser.get());
431
1.41k
            if (ret < 0) {
432
0
                goto out;
433
0
            }
434
1.41k
        }
435
232k
    }
436
437
3.20k
out:
438
3.20k
    parser.reset();
439
440
3.20k
    return 0;
441
2.47k
}
442
443
/* vim: set sw=4 sts=4 et : */