Coverage Report

Created: 2025-10-10 06:35

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/spice-usbredir/fuzzing/usbredirparserfuzz.cc
Line
Count
Source
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.19k
    void operator()(struct usbredirparser *p) {
40
3.19k
        usbredirparser_destroy(p);
41
3.19k
    }
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
796k
{
49
796k
}
50
51
int wobbly_read_write_count(int count)
52
4.44M
{
53
4.44M
    if (count > (1024 * 1024)) {
54
160
        return count;
55
160
    }
56
57
4.44M
    return std::min(count, fdp->ConsumeIntegralInRange(1, 4 * count));
58
4.44M
}
59
60
int parser_read(void *priv, uint8_t *data, int count)
61
2.31M
{
62
    // Simulate short reads
63
2.31M
    return fdp->ConsumeData(data, wobbly_read_write_count(count));
64
2.31M
}
65
66
// Read over complete input buffer to detect buffer overflows
67
void read_all(const void *data, size_t count)
68
2.13M
{
69
#ifdef __cpp_lib_smart_ptr_for_overwrite
70
    const auto buf = std::make_unique_for_overwrite<uint8_t[]>(count);
71
#else
72
2.13M
    const auto buf = std::make_unique<uint8_t[]>(count);
73
2.13M
#endif
74
75
2.13M
    memcpy(buf.get(), data, count);
76
2.13M
}
77
78
template <typename T, typename = std::enable_if_t<std::is_class<T>::value>>
79
void read_all(const T *ptr)
80
3.38k
{
81
3.38k
    read_all(ptr, sizeof(T));
82
3.38k
}
usbredirparserfuzz.cc:void (anonymous namespace)::read_all<usb_redir_control_packet_header, void>(usb_redir_control_packet_header const*)
Line
Count
Source
80
617
{
81
617
    read_all(ptr, sizeof(T));
82
617
}
usbredirparserfuzz.cc:void (anonymous namespace)::read_all<usb_redir_bulk_packet_header, void>(usb_redir_bulk_packet_header const*)
Line
Count
Source
80
475
{
81
475
    read_all(ptr, sizeof(T));
82
475
}
usbredirparserfuzz.cc:void (anonymous namespace)::read_all<usb_redir_iso_packet_header, void>(usb_redir_iso_packet_header const*)
Line
Count
Source
80
729
{
81
729
    read_all(ptr, sizeof(T));
82
729
}
usbredirparserfuzz.cc:void (anonymous namespace)::read_all<usb_redir_interrupt_packet_header, void>(usb_redir_interrupt_packet_header const*)
Line
Count
Source
80
528
{
81
528
    read_all(ptr, sizeof(T));
82
528
}
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
226
{
81
226
    read_all(ptr, sizeof(T));
82
226
}
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
229
{
81
229
    read_all(ptr, sizeof(T));
82
229
}
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
379
{
81
379
    read_all(ptr, sizeof(T));
82
379
}
83
84
int parser_write(void *priv, uint8_t *data, int count)
85
2.13M
{
86
    // Simulate short writes
87
2.13M
    count = wobbly_read_write_count(count);
88
89
2.13M
    read_all(data, count);
90
91
2.13M
    return count;
92
2.13M
}
93
94
void parser_device_connect(void *priv,
95
    struct usb_redir_device_connect_header *device_connect)
96
194
{
97
194
}
98
99
void parser_device_disconnect(void *priv)
100
106k
{
101
106k
}
102
103
void parser_reset(void *priv)
104
240
{
105
240
}
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
222
{
115
222
}
116
117
void parser_set_configuration(void *priv, uint64_t id,
118
    struct usb_redir_set_configuration_header *set_configuration)
119
341
{
120
341
}
121
122
void parser_get_configuration(void *priv, uint64_t id)
123
323
{
124
323
}
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
670
{
139
670
}
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
199
{
154
199
}
155
156
void parser_iso_stream_status(void *priv, uint64_t id,
157
    struct usb_redir_iso_stream_status_header *iso_stream_status)
158
196
{
159
196
}
160
161
void parser_start_interrupt_receiving(void *priv, uint64_t id,
162
    struct usb_redir_start_interrupt_receiving_header *start_interrupt_receiving)
163
567
{
164
567
}
165
166
void parser_stop_interrupt_receiving(void *priv, uint64_t id,
167
    struct usb_redir_stop_interrupt_receiving_header *stop_interrupt_receiving)
168
417
{
169
417
}
170
171
void parser_interrupt_receiving_status(void *priv, uint64_t id,
172
    struct usb_redir_interrupt_receiving_status_header *interrupt_receiving_status)
173
303
{
174
303
}
175
176
void parser_alloc_bulk_streams(void *priv, uint64_t id,
177
    struct usb_redir_alloc_bulk_streams_header *alloc_bulk_streams)
178
196
{
179
196
}
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
337
{
193
337
}
194
195
void parser_filter_reject(void *priv)
196
201
{
197
201
}
198
199
void parser_filter_filter(void *priv,
200
    struct usbredirfilter_rule *rules, int rules_count)
201
543
{
202
543
    usbredirfilter_free(rules);
203
543
}
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
617
{
209
617
    read_all(control_packet);
210
617
    read_all(data, data_len);
211
617
    usbredirparser_free_packet_data(parser.get(), data);
212
617
}
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
475
{
218
475
    read_all(bulk_packet);
219
475
    read_all(data, data_len);
220
475
    usbredirparser_free_packet_data(parser.get(), data);
221
475
}
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
729
{
227
729
    read_all(iso_packet);
228
729
    read_all(data, data_len);
229
729
    usbredirparser_free_packet_data(parser.get(), data);
230
729
}
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
528
{
236
528
    read_all(interrupt_packet);
237
528
    read_all(data, data_len);
238
528
    usbredirparser_free_packet_data(parser.get(), data);
239
528
}
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
379
{
245
379
    read_all(buffered_bulk_header);
246
379
    read_all(data, data_len);
247
379
    usbredirparser_free_packet_data(parser.get(), data);
248
379
}
249
250
void *parser_alloc_lock()
251
3.19k
{
252
3.19k
    return nullptr;
253
3.19k
}
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
89
{
269
89
}
270
271
void parser_device_disconnect_ack(void *priv)
272
428
{
273
428
}
274
275
void parser_start_bulk_receiving(void *priv, uint64_t id,
276
    struct usb_redir_start_bulk_receiving_header *start_bulk_receiving)
277
226
{
278
226
    read_all(start_bulk_receiving);
279
226
}
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
229
{
290
229
    read_all(bulk_receiving_status);
291
229
}
292
293
int try_unserialize(struct usbredirparser *parser, FuzzedDataProvider *fdp)
294
965
{
295
965
    std::vector<uint8_t> state;
296
965
    size_t len = fdp->ConsumeIntegralInRange<size_t>(1, 64 * 1024);
297
298
965
    state.reserve(len);
299
300
965
    if (len >= 4) {
301
937
        const uint32_t magic = USBREDIRPARSER_SERIALIZE_MAGIC;
302
937
        assert(state.empty());
303
937
        state.resize(sizeof(magic));
304
937
        memcpy(state.data(), &magic, sizeof(magic));
305
306
937
        len -= 4;
307
937
    }
308
309
965
    if (len > 0) {
310
964
        const std::vector<uint8_t> payload{fdp->ConsumeBytes<uint8_t>(len)};
311
312
964
        state.insert(state.end(), payload.cbegin(), payload.cend());
313
964
    }
314
315
965
    if (state.empty()) {
316
3
        return 0;
317
3
    }
318
319
962
    state.shrink_to_fit();
320
321
962
    return usbredirparser_unserialize(parser, &state[0], state.size());
322
965
}
323
324
int try_serialize(struct usbredirparser *parser)
325
52.4k
{
326
52.4k
    uint8_t *state = nullptr;
327
52.4k
    int len = 0;
328
52.4k
    int ret;
329
330
52.4k
    ret = usbredirparser_serialize(parser, &state, &len);
331
332
52.4k
    if (ret == 0) {
333
52.4k
        free(state);
334
52.4k
    }
335
336
52.4k
    return ret;
337
52.4k
}
338
}  // namespace
339
340
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
341
3.19k
{
342
3.19k
    std::array<uint32_t, USB_REDIR_CAPS_SIZE> caps = {0};
343
3.19k
    int ret;
344
345
3.19k
    fdp = std::make_unique<FuzzedDataProvider>(data, size);
346
347
3.19k
    parser.reset(usbredirparser_create());
348
3.19k
    if (parser == nullptr) {
349
0
        return 1;
350
0
    }
351
352
3.19k
    parser->log_func = parser_log;
353
3.19k
    parser->read_func = parser_read;
354
3.19k
    parser->write_func = parser_write;
355
3.19k
    parser->device_connect_func = parser_device_connect;
356
3.19k
    parser->device_disconnect_func = parser_device_disconnect;
357
3.19k
    parser->reset_func = parser_reset;
358
3.19k
    parser->interface_info_func = parser_interface_info;
359
3.19k
    parser->ep_info_func = parser_ep_info;
360
3.19k
    parser->set_configuration_func = parser_set_configuration;
361
3.19k
    parser->get_configuration_func = parser_get_configuration;
362
3.19k
    parser->configuration_status_func = parser_configuration_status;
363
3.19k
    parser->set_alt_setting_func = parser_set_alt_setting;
364
3.19k
    parser->get_alt_setting_func = parser_get_alt_setting;
365
3.19k
    parser->alt_setting_status_func = parser_alt_setting_status;
366
3.19k
    parser->start_iso_stream_func = parser_start_iso_stream;
367
3.19k
    parser->stop_iso_stream_func = parser_stop_iso_stream;
368
3.19k
    parser->iso_stream_status_func = parser_iso_stream_status;
369
3.19k
    parser->start_interrupt_receiving_func = parser_start_interrupt_receiving;
370
3.19k
    parser->stop_interrupt_receiving_func = parser_stop_interrupt_receiving;
371
3.19k
    parser->interrupt_receiving_status_func = parser_interrupt_receiving_status;
372
3.19k
    parser->alloc_bulk_streams_func = parser_alloc_bulk_streams;
373
3.19k
    parser->free_bulk_streams_func = parser_free_bulk_streams;
374
3.19k
    parser->bulk_streams_status_func = parser_bulk_streams_status;
375
3.19k
    parser->cancel_data_packet_func = parser_cancel_data_packet;
376
3.19k
    parser->control_packet_func = parser_control_packet;
377
3.19k
    parser->bulk_packet_func = parser_bulk_packet;
378
3.19k
    parser->iso_packet_func = parser_iso_packet;
379
3.19k
    parser->interrupt_packet_func = parser_interrupt_packet;
380
3.19k
    parser->alloc_lock_func = parser_alloc_lock;
381
3.19k
    parser->lock_func = parser_lock;
382
3.19k
    parser->unlock_func = parser_unlock;
383
3.19k
    parser->free_lock_func = parser_free_lock;
384
3.19k
    parser->hello_func = parser_hello;
385
3.19k
    parser->filter_reject_func = parser_filter_reject;
386
3.19k
    parser->filter_filter_func = parser_filter_filter;
387
3.19k
    parser->device_disconnect_ack_func = parser_device_disconnect_ack;
388
3.19k
    parser->start_bulk_receiving_func = parser_start_bulk_receiving;
389
3.19k
    parser->stop_bulk_receiving_func = parser_stop_bulk_receiving;
390
3.19k
    parser->bulk_receiving_status_func = parser_bulk_receiving_status;
391
3.19k
    parser->buffered_bulk_packet_func = parser_buffered_bulk_packet;
392
393
3.19k
    for (uint32_t &cap : caps) {
394
3.19k
        cap = fdp->ConsumeIntegral<decltype(caps)::value_type>();
395
3.19k
    }
396
397
3.19k
    const int init_flags = fdp->ConsumeIntegral<uint8_t>() &
398
3.19k
        (usbredirparser_fl_usb_host | usbredirparser_fl_no_hello);
399
400
3.19k
    usbredirparser_init(parser.get(), "fuzzer", caps.data(), caps.size(),
401
3.19k
                        init_flags);
402
403
3.19k
    if (fdp->ConsumeBool() && try_unserialize(parser.get(), fdp.get()) != 0) {
404
698
        goto out;
405
698
    }
406
407
163k
    while (fdp->remaining_bytes() > 0 ||
408
162k
           usbredirparser_has_data_to_write(parser.get())) {
409
162k
        if (fdp->ConsumeBool() && try_serialize(parser.get()) != 0) {
410
0
            goto out;
411
0
        }
412
413
162k
        if (fdp->remaining_bytes() > 0) {
414
162k
            ret = usbredirparser_do_read(parser.get());
415
416
162k
            switch (ret) {
417
160k
            case usbredirparser_read_parse_error:
418
                // Keep reading
419
160k
                break;
420
1.36k
            default:
421
1.36k
                goto out;
422
162k
            }
423
424
160k
            if (fdp->ConsumeBool() && try_serialize(parser.get()) != 0) {
425
0
                goto out;
426
0
            }
427
160k
        }
428
429
162k
        while (usbredirparser_has_data_to_write(parser.get())) {
430
1.20k
            ret = usbredirparser_do_write(parser.get());
431
1.20k
            if (ret < 0) {
432
0
                goto out;
433
0
            }
434
1.20k
        }
435
161k
    }
436
437
3.19k
out:
438
3.19k
    parser.reset();
439
440
3.19k
    return 0;
441
2.50k
}
442
443
/* vim: set sw=4 sts=4 et : */