Line | Count | Source (jump to first uncovered line) |
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 | | #include <sys/types.h> |
9 | | |
10 | | #include <linux/hidraw.h> |
11 | | #include <linux/input.h> |
12 | | |
13 | | #include <assert.h> |
14 | | #include <errno.h> |
15 | | #include <libudev.h> |
16 | | #include <stdlib.h> |
17 | | |
18 | | #include "mutator_aux.h" |
19 | | |
20 | | struct udev { |
21 | | int magic; |
22 | | }; |
23 | | |
24 | | struct udev_enumerate { |
25 | | int magic; |
26 | | struct udev_list_entry *list_entry; |
27 | | }; |
28 | | |
29 | | struct udev_list_entry { |
30 | | int magic; |
31 | | }; |
32 | | |
33 | | struct udev_device { |
34 | | int magic; |
35 | | struct udev_device *parent; |
36 | | }; |
37 | | |
38 | 551k | #define UDEV_MAGIC 0x584492cc |
39 | 1.63M | #define UDEV_DEVICE_MAGIC 0x569180dd |
40 | 2.34k | #define UDEV_LIST_ENTRY_MAGIC 0x497422ee |
41 | 2.36k | #define UDEV_ENUM_MAGIC 0x583570ff |
42 | | |
43 | 7.01M | #define ASSERT_TYPE(x, m) assert((x) != NULL && (x)->magic == (m)) |
44 | 2.14M | #define ASSERT_UDEV(x) ASSERT_TYPE((x), UDEV_MAGIC) |
45 | 9.42k | #define ASSERT_UDEV_ENUM(x) ASSERT_TYPE((x), UDEV_ENUM_MAGIC) |
46 | 2.09M | #define ASSERT_UDEV_LIST_ENTRY(x) ASSERT_TYPE((x), UDEV_LIST_ENTRY_MAGIC) |
47 | 2.76M | #define ASSERT_UDEV_DEVICE(x) ASSERT_TYPE((x), UDEV_DEVICE_MAGIC) |
48 | | |
49 | | static const char *uevent; |
50 | | static const struct blob *report_descriptor; |
51 | | |
52 | | struct udev *__wrap_udev_new(void); |
53 | | struct udev_device *__wrap_udev_device_get_parent_with_subsystem_devtype( |
54 | | struct udev_device *, const char *, const char *); |
55 | | struct udev_device *__wrap_udev_device_new_from_syspath(struct udev *, |
56 | | const char *); |
57 | | struct udev_enumerate *__wrap_udev_enumerate_new(struct udev *); |
58 | | struct udev_list_entry *__wrap_udev_enumerate_get_list_entry( |
59 | | struct udev_enumerate *); |
60 | | struct udev_list_entry *__wrap_udev_list_entry_get_next( |
61 | | struct udev_list_entry *); |
62 | | const char *__wrap_udev_device_get_sysattr_value(struct udev_device *, |
63 | | const char *); |
64 | | const char *__wrap_udev_list_entry_get_name(struct udev_list_entry *); |
65 | | const char *__wrap_udev_device_get_devnode(struct udev_device *); |
66 | | const char *__wrap_udev_device_get_sysnum(struct udev_device *); |
67 | | int __wrap_udev_enumerate_add_match_subsystem(struct udev_enumerate *, |
68 | | const char *); |
69 | | int __wrap_udev_enumerate_scan_devices(struct udev_enumerate *); |
70 | | int __wrap_ioctl(int, unsigned long , ...); |
71 | | void __wrap_udev_device_unref(struct udev_device *); |
72 | | void __wrap_udev_enumerate_unref(struct udev_enumerate *); |
73 | | void __wrap_udev_unref(struct udev *); |
74 | | void set_udev_parameters(const char *, const struct blob *); |
75 | | |
76 | | struct udev_device * |
77 | | __wrap_udev_device_get_parent_with_subsystem_devtype(struct udev_device *child, |
78 | | const char *subsystem, const char *devtype) |
79 | 48.1k | { |
80 | 48.1k | ASSERT_UDEV_DEVICE(child); |
81 | 0 | fido_log_debug("%s", subsystem); /* XXX consume */ |
82 | 48.1k | fido_log_debug("%s", devtype); /* XXX consume */ |
83 | 48.1k | if (child->parent != NULL) |
84 | 2.89k | return child->parent; |
85 | 45.2k | if ((child->parent = calloc(1, sizeof(*child->parent))) == NULL) |
86 | 113 | return NULL; |
87 | 45.1k | child->parent->magic = UDEV_DEVICE_MAGIC; |
88 | | |
89 | 45.1k | return child->parent; |
90 | 45.2k | } |
91 | | |
92 | | const char * |
93 | | __wrap_udev_device_get_sysattr_value(struct udev_device *udev_device, |
94 | | const char *sysattr) |
95 | 48.0k | { |
96 | 48.0k | ASSERT_UDEV_DEVICE(udev_device); |
97 | 48.0k | if (uniform_random(400) < 1) |
98 | 141 | return NULL; |
99 | 47.9k | if (!strcmp(sysattr, "manufacturer") || !strcmp(sysattr, "product")) |
100 | 2.87k | return "product info"; /* XXX randomise? */ |
101 | 45.0k | else if (!strcmp(sysattr, "uevent")) |
102 | 45.0k | return uevent; |
103 | | |
104 | 0 | return NULL; |
105 | 47.9k | } |
106 | | |
107 | | const char * |
108 | | __wrap_udev_list_entry_get_name(struct udev_list_entry *entry) |
109 | 1.04M | { |
110 | 1.04M | ASSERT_UDEV_LIST_ENTRY(entry); |
111 | 1.04M | return uniform_random(400) < 1 ? NULL : "name"; /* XXX randomise? */ |
112 | 1.04M | } |
113 | | |
114 | | struct udev_device * |
115 | | __wrap_udev_device_new_from_syspath(struct udev *udev, const char *syspath) |
116 | 1.59M | { |
117 | 1.59M | struct udev_device *udev_device; |
118 | | |
119 | 1.59M | ASSERT_UDEV(udev); |
120 | 0 | fido_log_debug("%s", syspath); |
121 | 1.59M | if ((udev_device = calloc(1, sizeof(*udev_device))) == NULL) |
122 | 3.87k | return NULL; |
123 | 1.58M | udev_device->magic = UDEV_DEVICE_MAGIC; |
124 | | |
125 | 1.58M | return udev_device; |
126 | 1.59M | } |
127 | | |
128 | | const char * |
129 | | __wrap_udev_device_get_devnode(struct udev_device *udev_device) |
130 | 487k | { |
131 | 487k | ASSERT_UDEV_DEVICE(udev_device); |
132 | 487k | return uniform_random(400) < 1 ? NULL : "/dev/zero"; |
133 | 487k | } |
134 | | |
135 | | const char * |
136 | | __wrap_udev_device_get_sysnum(struct udev_device *udev_device) |
137 | 547k | { |
138 | 547k | ASSERT_UDEV_DEVICE(udev_device); |
139 | 547k | return uniform_random(400) < 1 ? NULL : "101010"; /* XXX randomise? */ |
140 | 547k | } |
141 | | |
142 | | void |
143 | | __wrap_udev_device_unref(struct udev_device *udev_device) |
144 | 1.58M | { |
145 | 1.58M | ASSERT_UDEV_DEVICE(udev_device); |
146 | 1.58M | if (udev_device->parent) { |
147 | 45.1k | ASSERT_UDEV_DEVICE(udev_device->parent); |
148 | 0 | free(udev_device->parent); |
149 | 45.1k | } |
150 | 0 | free(udev_device); |
151 | 1.58M | } |
152 | | |
153 | | struct udev * |
154 | | __wrap_udev_new(void) |
155 | 552k | { |
156 | 552k | struct udev *udev; |
157 | | |
158 | 552k | if ((udev = calloc(1, sizeof(*udev))) == NULL) |
159 | 1.42k | return NULL; |
160 | 551k | udev->magic = UDEV_MAGIC; |
161 | | |
162 | 551k | return udev; |
163 | 552k | } |
164 | | |
165 | | struct udev_enumerate * |
166 | | __wrap_udev_enumerate_new(struct udev *udev) |
167 | 2.36k | { |
168 | 2.36k | struct udev_enumerate *udev_enum; |
169 | | |
170 | 2.36k | ASSERT_UDEV(udev); |
171 | 2.36k | if ((udev_enum = calloc(1, sizeof(*udev_enum))) == NULL) |
172 | 7 | return NULL; |
173 | 2.36k | udev_enum->magic = UDEV_ENUM_MAGIC; |
174 | | |
175 | 2.36k | return udev_enum; |
176 | 2.36k | } |
177 | | |
178 | | int |
179 | | __wrap_udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enum, |
180 | | const char *subsystem) |
181 | 2.36k | { |
182 | 2.36k | ASSERT_UDEV_ENUM(udev_enum); |
183 | 0 | fido_log_debug("%s:", subsystem); |
184 | 2.36k | return uniform_random(400) < 1 ? -EINVAL : 0; |
185 | 2.36k | } |
186 | | |
187 | | int |
188 | | __wrap_udev_enumerate_scan_devices(struct udev_enumerate *udev_enum) |
189 | 2.35k | { |
190 | 2.35k | ASSERT_UDEV_ENUM(udev_enum); |
191 | 2.35k | return uniform_random(400) < 1 ? -EINVAL : 0; |
192 | 2.35k | } |
193 | | |
194 | | struct udev_list_entry * |
195 | | __wrap_udev_enumerate_get_list_entry(struct udev_enumerate *udev_enum) |
196 | 2.34k | { |
197 | 2.34k | ASSERT_UDEV_ENUM(udev_enum); |
198 | 2.34k | if ((udev_enum->list_entry = calloc(1, |
199 | 2.34k | sizeof(*udev_enum->list_entry))) == NULL) |
200 | 4 | return NULL; |
201 | 2.34k | udev_enum->list_entry->magic = UDEV_LIST_ENTRY_MAGIC; |
202 | | |
203 | 2.34k | return udev_enum->list_entry; |
204 | 2.34k | } |
205 | | |
206 | | struct udev_list_entry * |
207 | | __wrap_udev_list_entry_get_next(struct udev_list_entry *udev_list_entry) |
208 | 1.04M | { |
209 | 1.04M | ASSERT_UDEV_LIST_ENTRY(udev_list_entry); |
210 | 1.04M | return uniform_random(400) < 1 ? NULL : udev_list_entry; |
211 | 1.04M | } |
212 | | |
213 | | void |
214 | | __wrap_udev_enumerate_unref(struct udev_enumerate *udev_enum) |
215 | 2.36k | { |
216 | 2.36k | ASSERT_UDEV_ENUM(udev_enum); |
217 | 2.36k | if (udev_enum->list_entry) |
218 | 2.36k | ASSERT_UDEV_LIST_ENTRY(udev_enum->list_entry); |
219 | 0 | free(udev_enum->list_entry); |
220 | 2.36k | free(udev_enum); |
221 | 2.36k | } |
222 | | |
223 | | void |
224 | | __wrap_udev_unref(struct udev *udev) |
225 | 551k | { |
226 | 551k | ASSERT_UDEV(udev); |
227 | 0 | free(udev); |
228 | 551k | } |
229 | | |
230 | | int |
231 | | __wrap_ioctl(int fd, unsigned long request, ...) |
232 | 968k | { |
233 | 968k | va_list ap; |
234 | 968k | struct hidraw_report_descriptor *hrd; |
235 | | |
236 | 968k | (void)fd; |
237 | | |
238 | 968k | if (uniform_random(400) < 1) { |
239 | 2.41k | errno = EINVAL; |
240 | 2.41k | return -1; |
241 | 2.41k | } |
242 | | |
243 | 965k | va_start(ap, request); |
244 | | |
245 | 965k | switch (IOCTL_REQ(request)) { |
246 | 483k | case IOCTL_REQ(HIDIOCGRDESCSIZE): |
247 | 483k | *va_arg(ap, int *) = (int)report_descriptor->len; |
248 | 483k | break; |
249 | 482k | case IOCTL_REQ(HIDIOCGRDESC): |
250 | 482k | hrd = va_arg(ap, struct hidraw_report_descriptor *); |
251 | 482k | assert(hrd->size == report_descriptor->len); |
252 | 0 | memcpy(hrd->value, report_descriptor->body, hrd->size); |
253 | 482k | break; |
254 | 0 | default: |
255 | 0 | warnx("%s: unknown request 0x%lx", __func__, request); |
256 | 0 | abort(); |
257 | 965k | } |
258 | | |
259 | 965k | va_end(ap); |
260 | | |
261 | 965k | return 0; |
262 | 965k | } |
263 | | |
264 | | void |
265 | | set_udev_parameters(const char *uevent_ptr, |
266 | | const struct blob *report_descriptor_ptr) |
267 | 1.21k | { |
268 | 1.21k | uevent = uevent_ptr; |
269 | 1.21k | report_descriptor = report_descriptor_ptr; |
270 | 1.21k | } |