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