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