#define _POSIX_C_SOURCE 200809L #include "hid_device.h" #include #include #include #include #include #include #include #include #include #include #include "../src/profile.inc" static unsigned calls, closes, opens; static int mode, flags, ret_override = -2; /* Linker wrappers never forward ANY call to /dev or ioctl. The actual * production transport runs against these syscall doubles, including validation. */ int __wrap_open(const char *path, int oflag, ...) { ++opens; assert(!strcmp(path, "/dev/hidraw77")); flags = oflag; if (mode == 8) { errno = EACCES; return -1; } return 77; } int __wrap_open64(const char *path, int oflag, ...) { return __wrap_open(path, oflag); } int __wrap_close(int fd) { assert(fd == 77); ++closes; return 0; } int __wrap_flock(int fd, int operation) { assert(fd == 77 && operation == (LOCK_EX | LOCK_NB)); if (mode == 7) { errno = EWOULDBLOCK; return -1; } return 0; } int __wrap_ioctl(int fd, unsigned long request, ...) { assert(fd == 77); ++calls; va_list ap; va_start(ap, request); void *argument = va_arg(ap, void *); va_end(ap); if (request == HIDIOCGRAWINFO) { struct hidraw_devinfo *info = argument; info->bustype = mode == 1 ? BUS_USB : BUS_I2C; info->vendor = mode == 2 ? 0x1234 : 0x0b05; info->product = mode == 3 ? 0x9999 : 0x5570; return 0; } if (request == HIDIOCGRDESCSIZE) { *(int *)argument = mode == 4 ? HID_MAX_DESCRIPTOR_SIZE+1 : (int)sizeof profile; return 0; } if (request == HIDIOCGRDESC) { struct hidraw_report_descriptor *d = argument; assert(d->size == sizeof profile); memcpy(d->value, profile, sizeof profile); if (mode == 5) d->value[0] ^= 1; if (mode == 6) ++d->size; return 0; } assert(request == HIDIOCGFEATURE(23) || request == HIDIOCGFEATURE(29) || request == HIDIOCSFEATURE(2) || request == HIDIOCSFEATURE(3) || request == HIDIOCSFEATURE(10)); uint8_t *r = argument; unsigned n = _IOC_SIZE(request); if (_IOC_NR(request) == _IOC_NR(HIDIOCSFEATURE(2))) r[0] = 0; /* ensure caller const bytes survive */ if (ret_override == -1) { errno = EIO; return -1; } return ret_override == -2 ? (int)n : ret_override; } int main(void) { assert(hid_open_verified("hidraw77") == 77 && (flags & O_ACCMODE) == O_RDONLY); assert(__wrap_close(77) == 0); assert(hid_open_control("hidraw77") == 77 && (flags & O_ACCMODE) == O_RDWR && (flags & O_NOFOLLOW) && (flags & O_CLOEXEC)); assert(__wrap_close(77) == 0); for (mode = 1; mode <= 8; ++mode) { unsigned before = closes; assert(hid_open_control("hidraw77") == -1); assert(closes == before + (mode == 8 ? 0u : 1u)); assert(errno == (mode <= 3 ? ENODEV : mode <= 6 ? EPROTO : mode == 7 ? EWOULDBLOCK : EACCES)); } mode = 0; int fd = 77; uint8_t r[29] = {0x41}; assert(hid_get(&fd, r, 23) == 23); r[0] = 0x43; assert(hid_get(&fd, r, 29) == 29); const uint8_t selector[] = {0x42, 0, 0}, host[] = {0x46, 0}, automatic[] = {0x46, 1}; assert(hid_set(&fd, selector, 3) == 3 && selector[0] == 0x42); assert(hid_set(&fd, host, 2) == 2 && host[0] == 0x46); assert(hid_set(&fd, automatic, 2) == 2); uint8_t range[10] = {0x45, 1, 0, 0, 0, 0, 180, 190, 254, 255}; assert(hid_set(&fd, range, 10) == 10 && range[0] == 0x45); unsigned before = calls; range[1] = 8; assert(hid_set(&fd, range, 10) == -1 && errno == EINVAL); range[1] = 1; range[4] = 1; assert(hid_set(&fd, range, 10) == -1); assert(hid_set(&fd, selector, 2) == -1 && hid_set(NULL, host, 2) == -1); r[0] = 0x31; assert(hid_get(&fd, r, 23) == -1); assert(calls == before); ret_override = 1; assert(hid_set(&fd, host, 2) == -1 && errno == EPROTO); ret_override = 0; assert(hid_set(&fd, host, 2) == -1 && errno == EPROTO); ret_override = 3; assert(hid_set(&fd, host, 2) == -1 && errno == EPROTO); ret_override = -1; assert(hid_set(&fd, host, 2) == -1 && errno == EIO); assert(hid_open_control("../../hidraw77") == -1 && errno == EINVAL); assert(opens == 10); puts("Production hidraw transport verified via syscall doubles; no device opened."); return 0; }