Home | History | Annotate | Line # | Download | only in fuzz
      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