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