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