xref: /freebsd/contrib/libfido2/fuzz/udev.c (revision a4e5e0106ac7145f56eb39a691e302cabb4635be)
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 #define UDEV_MAGIC		0x584492cc
39 #define UDEV_DEVICE_MAGIC	0x569180dd
40 #define UDEV_LIST_ENTRY_MAGIC	0x497422ee
41 #define UDEV_ENUM_MAGIC		0x583570ff
42 
43 #define ASSERT_TYPE(x, m)		assert((x) != NULL && (x)->magic == (m))
44 #define ASSERT_UDEV(x)			ASSERT_TYPE((x), UDEV_MAGIC)
45 #define ASSERT_UDEV_ENUM(x)		ASSERT_TYPE((x), UDEV_ENUM_MAGIC)
46 #define ASSERT_UDEV_LIST_ENTRY(x)	ASSERT_TYPE((x), UDEV_LIST_ENTRY_MAGIC)
47 #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 {
80 	ASSERT_UDEV_DEVICE(child);
81 	fido_log_debug("%s", subsystem); /* XXX consume */
82 	fido_log_debug("%s", devtype); /* XXX consume */
83 	if (child->parent != NULL)
84 		return child->parent;
85 	if ((child->parent = calloc(1, sizeof(*child->parent))) == NULL)
86 		return NULL;
87 	child->parent->magic = UDEV_DEVICE_MAGIC;
88 
89 	return child->parent;
90 }
91 
92 const char *
93 __wrap_udev_device_get_sysattr_value(struct udev_device *udev_device,
94     const char *sysattr)
95 {
96 	ASSERT_UDEV_DEVICE(udev_device);
97 	if (uniform_random(400) < 1)
98 		return NULL;
99 	if (!strcmp(sysattr, "manufacturer") || !strcmp(sysattr, "product"))
100 		return "product info"; /* XXX randomise? */
101 	else if (!strcmp(sysattr, "uevent"))
102 		return uevent;
103 
104 	return NULL;
105 }
106 
107 const char *
108 __wrap_udev_list_entry_get_name(struct udev_list_entry *entry)
109 {
110 	ASSERT_UDEV_LIST_ENTRY(entry);
111 	return uniform_random(400) < 1 ? NULL : "name"; /* XXX randomise? */
112 }
113 
114 struct udev_device *
115 __wrap_udev_device_new_from_syspath(struct udev *udev, const char *syspath)
116 {
117 	struct udev_device *udev_device;
118 
119 	ASSERT_UDEV(udev);
120 	fido_log_debug("%s", syspath);
121 	if ((udev_device = calloc(1, sizeof(*udev_device))) == NULL)
122 		return NULL;
123 	udev_device->magic = UDEV_DEVICE_MAGIC;
124 
125 	return udev_device;
126 }
127 
128 const char *
129 __wrap_udev_device_get_devnode(struct udev_device *udev_device)
130 {
131 	ASSERT_UDEV_DEVICE(udev_device);
132 	return uniform_random(400) < 1 ? NULL : "/dev/zero";
133 }
134 
135 const char *
136 __wrap_udev_device_get_sysnum(struct udev_device *udev_device)
137 {
138 	ASSERT_UDEV_DEVICE(udev_device);
139 	return uniform_random(400) < 1 ? NULL : "101010"; /* XXX randomise? */
140 }
141 
142 void
143 __wrap_udev_device_unref(struct udev_device *udev_device)
144 {
145 	ASSERT_UDEV_DEVICE(udev_device);
146 	if (udev_device->parent) {
147 		ASSERT_UDEV_DEVICE(udev_device->parent);
148 		free(udev_device->parent);
149 	}
150 	free(udev_device);
151 }
152 
153 struct udev *
154 __wrap_udev_new(void)
155 {
156 	struct udev *udev;
157 
158 	if ((udev = calloc(1, sizeof(*udev))) == NULL)
159 		return NULL;
160 	udev->magic = UDEV_MAGIC;
161 
162 	return udev;
163 }
164 
165 struct udev_enumerate *
166 __wrap_udev_enumerate_new(struct udev *udev)
167 {
168 	struct udev_enumerate *udev_enum;
169 
170 	ASSERT_UDEV(udev);
171 	if ((udev_enum = calloc(1, sizeof(*udev_enum))) == NULL)
172 		return NULL;
173 	udev_enum->magic = UDEV_ENUM_MAGIC;
174 
175 	return udev_enum;
176 }
177 
178 int
179 __wrap_udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enum,
180     const char *subsystem)
181 {
182 	ASSERT_UDEV_ENUM(udev_enum);
183 	fido_log_debug("%s:", subsystem);
184 	return uniform_random(400) < 1 ? -EINVAL : 0;
185 }
186 
187 int
188 __wrap_udev_enumerate_scan_devices(struct udev_enumerate *udev_enum)
189 {
190 	ASSERT_UDEV_ENUM(udev_enum);
191 	return uniform_random(400) < 1 ? -EINVAL : 0;
192 }
193 
194 struct udev_list_entry *
195 __wrap_udev_enumerate_get_list_entry(struct udev_enumerate *udev_enum)
196 {
197 	ASSERT_UDEV_ENUM(udev_enum);
198 	if ((udev_enum->list_entry = calloc(1,
199 	    sizeof(*udev_enum->list_entry))) == NULL)
200 		return NULL;
201 	udev_enum->list_entry->magic = UDEV_LIST_ENTRY_MAGIC;
202 
203 	return udev_enum->list_entry;
204 }
205 
206 struct udev_list_entry *
207 __wrap_udev_list_entry_get_next(struct udev_list_entry *udev_list_entry)
208 {
209 	ASSERT_UDEV_LIST_ENTRY(udev_list_entry);
210 	return uniform_random(400) < 1 ? NULL : udev_list_entry;
211 }
212 
213 void
214 __wrap_udev_enumerate_unref(struct udev_enumerate *udev_enum)
215 {
216 	ASSERT_UDEV_ENUM(udev_enum);
217 	if (udev_enum->list_entry)
218 		ASSERT_UDEV_LIST_ENTRY(udev_enum->list_entry);
219 	free(udev_enum->list_entry);
220 	free(udev_enum);
221 }
222 
223 void
224 __wrap_udev_unref(struct udev *udev)
225 {
226 	ASSERT_UDEV(udev);
227 	free(udev);
228 }
229 
230 int
231 __wrap_ioctl(int fd, unsigned long request, ...)
232 {
233 	va_list ap;
234 	struct hidraw_report_descriptor *hrd;
235 
236 	(void)fd;
237 
238 	if (uniform_random(400) < 1) {
239 		errno = EINVAL;
240 		return -1;
241 	}
242 
243 	va_start(ap, request);
244 
245 	switch (IOCTL_REQ(request)) {
246 	case IOCTL_REQ(HIDIOCGRDESCSIZE):
247 		*va_arg(ap, int *) = (int)report_descriptor->len;
248 		break;
249 	case IOCTL_REQ(HIDIOCGRDESC):
250 		hrd = va_arg(ap, struct hidraw_report_descriptor *);
251 		assert(hrd->size == report_descriptor->len);
252 		memcpy(hrd->value, report_descriptor->body, hrd->size);
253 		break;
254 	default:
255 		warnx("%s: unknown request 0x%lx", __func__, request);
256 		abort();
257 	}
258 
259 	va_end(ap);
260 
261 	return 0;
262 }
263 
264 void
265 set_udev_parameters(const char *uevent_ptr,
266     const struct blob *report_descriptor_ptr)
267 {
268 	uevent = uevent_ptr;
269 	report_descriptor = report_descriptor_ptr;
270 }
271