Coverage Report

Created: 2025-10-04 18:33

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/libfido2/fuzz/udev.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2021 Yubico AB. All rights reserved.
3
 * Use of this source code is governed by a BSD-style
4
 * license that can be found in the LICENSE file.
5
 * SPDX-License-Identifier: BSD-2-Clause
6
 */
7
8
#undef NDEBUG
9
10
#include <sys/types.h>
11
12
#include <linux/hidraw.h>
13
#include <linux/input.h>
14
15
#include <assert.h>
16
#include <errno.h>
17
#include <libudev.h>
18
#include <stdlib.h>
19
20
#include "mutator_aux.h"
21
22
struct udev {
23
        int magic;
24
};
25
26
struct udev_enumerate {
27
        int magic;
28
        struct udev_list_entry *list_entry;
29
};
30
31
struct udev_list_entry {
32
        int magic;
33
};
34
35
struct udev_device {
36
        int magic;
37
        struct udev_device *parent;
38
};
39
40
2.78M
#define UDEV_MAGIC              0x584492cc
41
9.62M
#define UDEV_DEVICE_MAGIC       0x569180dd
42
13.3k
#define UDEV_LIST_ENTRY_MAGIC   0x497422ee
43
13.4k
#define UDEV_ENUM_MAGIC         0x583570ff
44
45
40.7M
#define ASSERT_TYPE(x, m)               assert((x) != NULL && (x)->magic == (m))
46
11.4M
#define ASSERT_UDEV(x)                  ASSERT_TYPE((x), UDEV_MAGIC)
47
53.6k
#define ASSERT_UDEV_ENUM(x)             ASSERT_TYPE((x), UDEV_ENUM_MAGIC)
48
11.7M
#define ASSERT_UDEV_LIST_ENTRY(x)       ASSERT_TYPE((x), UDEV_LIST_ENTRY_MAGIC)
49
17.5M
#define ASSERT_UDEV_DEVICE(x)           ASSERT_TYPE((x), UDEV_DEVICE_MAGIC)
50
51
static const char *uevent;
52
static const struct blob *report_descriptor;
53
54
struct udev *__wrap_udev_new(void);
55
struct udev_device *__wrap_udev_device_get_parent_with_subsystem_devtype(
56
    struct udev_device *, const char *, const char *);
57
struct udev_device *__wrap_udev_device_new_from_syspath(struct udev *,
58
    const char *);
59
struct udev_enumerate *__wrap_udev_enumerate_new(struct udev *);
60
struct udev_list_entry *__wrap_udev_enumerate_get_list_entry(
61
    struct udev_enumerate *);
62
struct udev_list_entry *__wrap_udev_list_entry_get_next(
63
    struct udev_list_entry *);
64
const char *__wrap_udev_device_get_sysattr_value(struct udev_device *,
65
    const char *);
66
const char *__wrap_udev_list_entry_get_name(struct udev_list_entry *);
67
const char *__wrap_udev_device_get_devnode(struct udev_device *);
68
const char *__wrap_udev_device_get_sysnum(struct udev_device *);
69
int __wrap_udev_enumerate_add_match_subsystem(struct udev_enumerate *,
70
    const char *);
71
int __wrap_udev_enumerate_scan_devices(struct udev_enumerate *);
72
int __wrap_ioctl(int, unsigned long , ...);
73
void __wrap_udev_device_unref(struct udev_device *);
74
void __wrap_udev_enumerate_unref(struct udev_enumerate *);
75
void __wrap_udev_unref(struct udev *);
76
void set_udev_parameters(const char *, const struct blob *);
77
78
struct udev_device *
79
__wrap_udev_device_get_parent_with_subsystem_devtype(struct udev_device *child,
80
    const char *subsystem, const char *devtype)
81
1.03M
{
82
1.03M
        ASSERT_UDEV_DEVICE(child);
83
1.03M
        fido_log_debug("%s", subsystem); /* XXX consume */
84
1.03M
        fido_log_debug("%s", devtype); /* XXX consume */
85
1.03M
        if (child->parent != NULL)
86
19.5k
                return child->parent;
87
1.01M
        if ((child->parent = calloc(1, sizeof(*child->parent))) == NULL)
88
2.36k
                return NULL;
89
1.01M
        child->parent->magic = UDEV_DEVICE_MAGIC;
90
91
1.01M
        return child->parent;
92
1.01M
}
93
94
const char *
95
__wrap_udev_device_get_sysattr_value(struct udev_device *udev_device,
96
    const char *sysattr)
97
1.03M
{
98
1.03M
        ASSERT_UDEV_DEVICE(udev_device);
99
1.03M
        if (uniform_random(400) < 1)
100
2.15k
                return NULL;
101
1.03M
        if (!strcmp(sysattr, "manufacturer") || !strcmp(sysattr, "product"))
102
19.3k
                return "product info"; /* XXX randomise? */
103
1.01M
        else if (!strcmp(sysattr, "uevent"))
104
1.01M
                return uevent;
105
106
0
        return NULL;
107
1.03M
}
108
109
const char *
110
__wrap_udev_list_entry_get_name(struct udev_list_entry *entry)
111
5.87M
{
112
5.87M
        ASSERT_UDEV_LIST_ENTRY(entry);
113
5.87M
        return uniform_random(400) < 1 ? NULL : "name"; /* XXX randomise? */
114
5.87M
}
115
116
struct udev_device *
117
__wrap_udev_device_new_from_syspath(struct udev *udev, const char *syspath)
118
8.63M
{
119
8.63M
        struct udev_device *udev_device;
120
121
8.63M
        ASSERT_UDEV(udev);
122
8.63M
        fido_log_debug("%s", syspath);
123
8.63M
        if ((udev_device = calloc(1, sizeof(*udev_device))) == NULL)
124
22.0k
                return NULL;
125
8.61M
        udev_device->magic = UDEV_DEVICE_MAGIC;
126
127
8.61M
        return udev_device;
128
8.63M
}
129
130
const char *
131
__wrap_udev_device_get_devnode(struct udev_device *udev_device)
132
3.04M
{
133
3.04M
        ASSERT_UDEV_DEVICE(udev_device);
134
3.04M
        return uniform_random(400) < 1 ? NULL : "/dev/zero";
135
3.04M
}
136
137
const char *
138
__wrap_udev_device_get_sysnum(struct udev_device *udev_device)
139
2.76M
{
140
2.76M
        ASSERT_UDEV_DEVICE(udev_device);
141
2.76M
        return uniform_random(400) < 1 ? NULL : "101010"; /* XXX randomise? */
142
2.76M
}
143
144
void
145
__wrap_udev_device_unref(struct udev_device *udev_device)
146
8.61M
{
147
8.61M
        ASSERT_UDEV_DEVICE(udev_device);
148
8.61M
        if (udev_device->parent) {
149
1.01M
                ASSERT_UDEV_DEVICE(udev_device->parent);
150
1.01M
                free(udev_device->parent);
151
1.01M
        }
152
8.61M
        free(udev_device);
153
8.61M
}
154
155
struct udev *
156
__wrap_udev_new(void)
157
2.79M
{
158
2.79M
        struct udev *udev;
159
160
2.79M
        if ((udev = calloc(1, sizeof(*udev))) == NULL)
161
6.62k
                return NULL;
162
2.78M
        udev->magic = UDEV_MAGIC;
163
164
2.78M
        return udev;
165
2.79M
}
166
167
struct udev_enumerate *
168
__wrap_udev_enumerate_new(struct udev *udev)
169
13.4k
{
170
13.4k
        struct udev_enumerate *udev_enum;
171
172
13.4k
        ASSERT_UDEV(udev);
173
13.4k
        if ((udev_enum = calloc(1, sizeof(*udev_enum))) == NULL)
174
27
                return NULL;
175
13.4k
        udev_enum->magic = UDEV_ENUM_MAGIC;
176
177
13.4k
        return udev_enum;
178
13.4k
}
179
180
int
181
__wrap_udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enum,
182
    const char *subsystem)
183
13.4k
{
184
13.4k
        ASSERT_UDEV_ENUM(udev_enum);
185
13.4k
        fido_log_debug("%s:", subsystem);
186
13.4k
        return uniform_random(400) < 1 ? -EINVAL : 0;
187
13.4k
}
188
189
int
190
__wrap_udev_enumerate_scan_devices(struct udev_enumerate *udev_enum)
191
13.4k
{
192
13.4k
        ASSERT_UDEV_ENUM(udev_enum);
193
13.4k
        return uniform_random(400) < 1 ? -EINVAL : 0;
194
13.4k
}
195
196
struct udev_list_entry *
197
__wrap_udev_enumerate_get_list_entry(struct udev_enumerate *udev_enum)
198
13.3k
{
199
13.3k
        ASSERT_UDEV_ENUM(udev_enum);
200
13.3k
        if ((udev_enum->list_entry = calloc(1,
201
13.3k
            sizeof(*udev_enum->list_entry))) == NULL)
202
22
                return NULL;
203
13.3k
        udev_enum->list_entry->magic = UDEV_LIST_ENTRY_MAGIC;
204
205
13.3k
        return udev_enum->list_entry;
206
13.3k
}
207
208
struct udev_list_entry *
209
__wrap_udev_list_entry_get_next(struct udev_list_entry *udev_list_entry)
210
5.87M
{
211
5.87M
        ASSERT_UDEV_LIST_ENTRY(udev_list_entry);
212
5.87M
        return uniform_random(400) < 1 ? NULL : udev_list_entry;
213
5.87M
}
214
215
void
216
__wrap_udev_enumerate_unref(struct udev_enumerate *udev_enum)
217
13.4k
{
218
13.4k
        ASSERT_UDEV_ENUM(udev_enum);
219
13.4k
        if (udev_enum->list_entry)
220
13.4k
                ASSERT_UDEV_LIST_ENTRY(udev_enum->list_entry);
221
13.4k
        free(udev_enum->list_entry);
222
13.4k
        free(udev_enum);
223
13.4k
}
224
225
void
226
__wrap_udev_unref(struct udev *udev)
227
2.78M
{
228
2.78M
        ASSERT_UDEV(udev);
229
2.78M
        free(udev);
230
2.78M
}
231
232
int
233
__wrap_ioctl(int fd, unsigned long request, ...)
234
6.05M
{
235
6.05M
        va_list ap;
236
6.05M
        struct hidraw_report_descriptor *hrd;
237
238
6.05M
        (void)fd;
239
240
6.05M
        if (uniform_random(400) < 1) {
241
15.3k
                errno = EINVAL;
242
15.3k
                return -1;
243
15.3k
        }
244
245
6.05M
        va_start(ap, request);
246
247
6.03M
        switch (IOCTL_REQ(request)) {
248
3.02M
        case IOCTL_REQ(HIDIOCGRDESCSIZE):
249
3.02M
                *va_arg(ap, int *) = (int)report_descriptor->len;
250
3.02M
                break;
251
3.01M
        case IOCTL_REQ(HIDIOCGRDESC):
252
3.01M
                hrd = va_arg(ap, struct hidraw_report_descriptor *);
253
3.01M
                assert(hrd->size == report_descriptor->len);
254
3.01M
                memcpy(hrd->value, report_descriptor->body, hrd->size);
255
3.01M
                break;
256
0
        default:
257
0
                warnx("%s: unknown request 0x%lx", __func__, request);
258
0
                abort();
259
6.03M
        }
260
261
6.03M
        va_end(ap);
262
263
6.03M
        return 0;
264
6.03M
}
265
266
void
267
set_udev_parameters(const char *uevent_ptr,
268
    const struct blob *report_descriptor_ptr)
269
6.87k
{
270
6.87k
        uevent = uevent_ptr;
271
6.87k
        report_descriptor = report_descriptor_ptr;
272
6.87k
}