diff options
Diffstat (limited to '')
-rw-r--r-- | fuzz/udev.c | 270 |
1 files changed, 270 insertions, 0 deletions
diff --git a/fuzz/udev.c b/fuzz/udev.c new file mode 100644 index 0000000..3194012 --- /dev/null +++ b/fuzz/udev.c @@ -0,0 +1,270 @@ +/* + * Copyright (c) 2021 Yubico AB. All rights reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <sys/types.h> + +#include <linux/hidraw.h> +#include <linux/input.h> + +#include <assert.h> +#include <errno.h> +#include <libudev.h> +#include <stdlib.h> + +#include "mutator_aux.h" + +struct udev { + int magic; +}; + +struct udev_enumerate { + int magic; + struct udev_list_entry *list_entry; +}; + +struct udev_list_entry { + int magic; +}; + +struct udev_device { + int magic; + struct udev_device *parent; +}; + +#define UDEV_MAGIC 0x584492cc +#define UDEV_DEVICE_MAGIC 0x569180dd +#define UDEV_LIST_ENTRY_MAGIC 0x497422ee +#define UDEV_ENUM_MAGIC 0x583570ff + +#define ASSERT_TYPE(x, m) assert((x) != NULL && (x)->magic == (m)) +#define ASSERT_UDEV(x) ASSERT_TYPE((x), UDEV_MAGIC) +#define ASSERT_UDEV_ENUM(x) ASSERT_TYPE((x), UDEV_ENUM_MAGIC) +#define ASSERT_UDEV_LIST_ENTRY(x) ASSERT_TYPE((x), UDEV_LIST_ENTRY_MAGIC) +#define ASSERT_UDEV_DEVICE(x) ASSERT_TYPE((x), UDEV_DEVICE_MAGIC) + +static const char *uevent; +static const struct blob *report_descriptor; + +struct udev *__wrap_udev_new(void); +struct udev_device *__wrap_udev_device_get_parent_with_subsystem_devtype( + struct udev_device *, const char *, const char *); +struct udev_device *__wrap_udev_device_new_from_syspath(struct udev *, + const char *); +struct udev_enumerate *__wrap_udev_enumerate_new(struct udev *); +struct udev_list_entry *__wrap_udev_enumerate_get_list_entry( + struct udev_enumerate *); +struct udev_list_entry *__wrap_udev_list_entry_get_next( + struct udev_list_entry *); +const char *__wrap_udev_device_get_sysattr_value(struct udev_device *, + const char *); +const char *__wrap_udev_list_entry_get_name(struct udev_list_entry *); +const char *__wrap_udev_device_get_devnode(struct udev_device *); +const char *__wrap_udev_device_get_sysnum(struct udev_device *); +int __wrap_udev_enumerate_add_match_subsystem(struct udev_enumerate *, + const char *); +int __wrap_udev_enumerate_scan_devices(struct udev_enumerate *); +int __wrap_ioctl(int, unsigned long , ...); +void __wrap_udev_device_unref(struct udev_device *); +void __wrap_udev_enumerate_unref(struct udev_enumerate *); +void __wrap_udev_unref(struct udev *); +void set_udev_parameters(const char *, const struct blob *); + +struct udev_device * +__wrap_udev_device_get_parent_with_subsystem_devtype(struct udev_device *child, + const char *subsystem, const char *devtype) +{ + ASSERT_UDEV_DEVICE(child); + fido_log_debug("%s", subsystem); /* XXX consume */ + fido_log_debug("%s", devtype); /* XXX consume */ + if (child->parent != NULL) + return child->parent; + if ((child->parent = calloc(1, sizeof(*child->parent))) == NULL) + return NULL; + child->parent->magic = UDEV_DEVICE_MAGIC; + + return child->parent; +} + +const char * +__wrap_udev_device_get_sysattr_value(struct udev_device *udev_device, + const char *sysattr) +{ + ASSERT_UDEV_DEVICE(udev_device); + if (uniform_random(400) < 1) + return NULL; + if (!strcmp(sysattr, "manufacturer") || !strcmp(sysattr, "product")) + return "product info"; /* XXX randomise? */ + else if (!strcmp(sysattr, "uevent")) + return uevent; + + return NULL; +} + +const char * +__wrap_udev_list_entry_get_name(struct udev_list_entry *entry) +{ + ASSERT_UDEV_LIST_ENTRY(entry); + return uniform_random(400) < 1 ? NULL : "name"; /* XXX randomise? */ +} + +struct udev_device * +__wrap_udev_device_new_from_syspath(struct udev *udev, const char *syspath) +{ + struct udev_device *udev_device; + + ASSERT_UDEV(udev); + fido_log_debug("%s", syspath); + if ((udev_device = calloc(1, sizeof(*udev_device))) == NULL) + return NULL; + udev_device->magic = UDEV_DEVICE_MAGIC; + + return udev_device; +} + +const char * +__wrap_udev_device_get_devnode(struct udev_device *udev_device) +{ + ASSERT_UDEV_DEVICE(udev_device); + return uniform_random(400) < 1 ? NULL : "/dev/zero"; +} + +const char * +__wrap_udev_device_get_sysnum(struct udev_device *udev_device) +{ + ASSERT_UDEV_DEVICE(udev_device); + return uniform_random(400) < 1 ? NULL : "101010"; /* XXX randomise? */ +} + +void +__wrap_udev_device_unref(struct udev_device *udev_device) +{ + ASSERT_UDEV_DEVICE(udev_device); + if (udev_device->parent) { + ASSERT_UDEV_DEVICE(udev_device->parent); + free(udev_device->parent); + } + free(udev_device); +} + +struct udev * +__wrap_udev_new(void) +{ + struct udev *udev; + + if ((udev = calloc(1, sizeof(*udev))) == NULL) + return NULL; + udev->magic = UDEV_MAGIC; + + return udev; +} + +struct udev_enumerate * +__wrap_udev_enumerate_new(struct udev *udev) +{ + struct udev_enumerate *udev_enum; + + ASSERT_UDEV(udev); + if ((udev_enum = calloc(1, sizeof(*udev_enum))) == NULL) + return NULL; + udev_enum->magic = UDEV_ENUM_MAGIC; + + return udev_enum; +} + +int +__wrap_udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enum, + const char *subsystem) +{ + ASSERT_UDEV_ENUM(udev_enum); + fido_log_debug("%s:", subsystem); + return uniform_random(400) < 1 ? -EINVAL : 0; +} + +int +__wrap_udev_enumerate_scan_devices(struct udev_enumerate *udev_enum) +{ + ASSERT_UDEV_ENUM(udev_enum); + return uniform_random(400) < 1 ? -EINVAL : 0; +} + +struct udev_list_entry * +__wrap_udev_enumerate_get_list_entry(struct udev_enumerate *udev_enum) +{ + ASSERT_UDEV_ENUM(udev_enum); + if ((udev_enum->list_entry = calloc(1, + sizeof(*udev_enum->list_entry))) == NULL) + return NULL; + udev_enum->list_entry->magic = UDEV_LIST_ENTRY_MAGIC; + + return udev_enum->list_entry; +} + +struct udev_list_entry * +__wrap_udev_list_entry_get_next(struct udev_list_entry *udev_list_entry) +{ + ASSERT_UDEV_LIST_ENTRY(udev_list_entry); + return uniform_random(400) < 1 ? NULL : udev_list_entry; +} + +void +__wrap_udev_enumerate_unref(struct udev_enumerate *udev_enum) +{ + ASSERT_UDEV_ENUM(udev_enum); + if (udev_enum->list_entry) + ASSERT_UDEV_LIST_ENTRY(udev_enum->list_entry); + free(udev_enum->list_entry); + free(udev_enum); +} + +void +__wrap_udev_unref(struct udev *udev) +{ + ASSERT_UDEV(udev); + free(udev); +} + +int +__wrap_ioctl(int fd, unsigned long request, ...) +{ + va_list ap; + struct hidraw_report_descriptor *hrd; + + (void)fd; + + if (uniform_random(400) < 1) { + errno = EINVAL; + return -1; + } + + va_start(ap, request); + + switch (IOCTL_REQ(request)) { + case IOCTL_REQ(HIDIOCGRDESCSIZE): + *va_arg(ap, int *) = (int)report_descriptor->len; + break; + case IOCTL_REQ(HIDIOCGRDESC): + hrd = va_arg(ap, struct hidraw_report_descriptor *); + assert(hrd->size == report_descriptor->len); + memcpy(hrd->value, report_descriptor->body, hrd->size); + break; + default: + warnx("%s: unknown request 0x%lx", __func__, request); + abort(); + } + + va_end(ap); + + return 0; +} + +void +set_udev_parameters(const char *uevent_ptr, + const struct blob *report_descriptor_ptr) +{ + uevent = uevent_ptr; + report_descriptor = report_descriptor_ptr; +} |