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