1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) 2022-2024 Red Hat */ 3 4 #include "hid_common.h" 5 6 /* for older kernels */ 7 #ifndef HIDIOCREVOKE 8 #define HIDIOCREVOKE _IOW('H', 0x0D, int) /* Revoke device access */ 9 #endif /* HIDIOCREVOKE */ 10 11 FIXTURE(hidraw) { 12 struct uhid_device hid; 13 int hidraw_fd; 14 }; 15 static void close_hidraw(FIXTURE_DATA(hidraw) * self) 16 { 17 if (self->hidraw_fd) 18 close(self->hidraw_fd); 19 self->hidraw_fd = 0; 20 } 21 22 FIXTURE_TEARDOWN(hidraw) { 23 void *uhid_err; 24 25 uhid_destroy(_metadata, &self->hid); 26 27 close_hidraw(self); 28 pthread_join(self->hid.tid, &uhid_err); 29 } 30 #define TEARDOWN_LOG(fmt, ...) do { \ 31 TH_LOG(fmt, ##__VA_ARGS__); \ 32 hidraw_teardown(_metadata, self, variant); \ 33 } while (0) 34 35 FIXTURE_SETUP(hidraw) 36 { 37 int err; 38 39 err = setup_uhid(_metadata, &self->hid, BUS_USB, 0x0001, 0x0a37, rdesc, sizeof(rdesc)); 40 ASSERT_OK(err); 41 42 self->hidraw_fd = open_hidraw(&self->hid); 43 ASSERT_GE(self->hidraw_fd, 0) TH_LOG("open_hidraw"); 44 } 45 46 /* 47 * A simple test to see if the fixture is working fine. 48 * If this fails, none of the other tests will pass. 49 */ 50 TEST_F(hidraw, test_create_uhid) 51 { 52 } 53 54 /* 55 * Inject one event in the uhid device, 56 * check that we get the same data through hidraw 57 */ 58 TEST_F(hidraw, raw_event) 59 { 60 __u8 buf[10] = {0}; 61 int err; 62 63 /* inject one event */ 64 buf[0] = 1; 65 buf[1] = 42; 66 uhid_send_event(_metadata, &self->hid, buf, 6); 67 68 /* read the data from hidraw */ 69 memset(buf, 0, sizeof(buf)); 70 err = read(self->hidraw_fd, buf, sizeof(buf)); 71 ASSERT_EQ(err, 6) TH_LOG("read_hidraw"); 72 ASSERT_EQ(buf[0], 1); 73 ASSERT_EQ(buf[1], 42); 74 } 75 76 /* 77 * After initial opening/checks of hidraw, revoke the hidraw 78 * node and check that we can not read any more data. 79 */ 80 TEST_F(hidraw, raw_event_revoked) 81 { 82 __u8 buf[10] = {0}; 83 int err; 84 85 /* inject one event */ 86 buf[0] = 1; 87 buf[1] = 42; 88 uhid_send_event(_metadata, &self->hid, buf, 6); 89 90 /* read the data from hidraw */ 91 memset(buf, 0, sizeof(buf)); 92 err = read(self->hidraw_fd, buf, sizeof(buf)); 93 ASSERT_EQ(err, 6) TH_LOG("read_hidraw"); 94 ASSERT_EQ(buf[0], 1); 95 ASSERT_EQ(buf[1], 42); 96 97 /* call the revoke ioctl */ 98 err = ioctl(self->hidraw_fd, HIDIOCREVOKE, NULL); 99 ASSERT_OK(err) TH_LOG("couldn't revoke the hidraw fd"); 100 101 /* inject one other event */ 102 buf[0] = 1; 103 buf[1] = 43; 104 uhid_send_event(_metadata, &self->hid, buf, 6); 105 106 /* read the data from hidraw */ 107 memset(buf, 0, sizeof(buf)); 108 err = read(self->hidraw_fd, buf, sizeof(buf)); 109 ASSERT_EQ(err, -1) TH_LOG("read_hidraw"); 110 ASSERT_EQ(errno, ENODEV) TH_LOG("unexpected error code while reading the hidraw node: %d", 111 errno); 112 } 113 114 /* 115 * Revoke the hidraw node and check that we can not do any ioctl. 116 */ 117 TEST_F(hidraw, ioctl_revoked) 118 { 119 int err, desc_size = 0; 120 121 /* call the revoke ioctl */ 122 err = ioctl(self->hidraw_fd, HIDIOCREVOKE, NULL); 123 ASSERT_OK(err) TH_LOG("couldn't revoke the hidraw fd"); 124 125 /* do an ioctl */ 126 err = ioctl(self->hidraw_fd, HIDIOCGRDESCSIZE, &desc_size); 127 ASSERT_EQ(err, -1) TH_LOG("ioctl_hidraw"); 128 ASSERT_EQ(errno, ENODEV) TH_LOG("unexpected error code while doing an ioctl: %d", 129 errno); 130 } 131 132 /* 133 * Setup polling of the fd, and check that revoke works properly. 134 */ 135 TEST_F(hidraw, poll_revoked) 136 { 137 struct pollfd pfds[1]; 138 __u8 buf[10] = {0}; 139 int err, ready; 140 141 /* setup polling */ 142 pfds[0].fd = self->hidraw_fd; 143 pfds[0].events = POLLIN; 144 145 /* inject one event */ 146 buf[0] = 1; 147 buf[1] = 42; 148 uhid_send_event(_metadata, &self->hid, buf, 6); 149 150 while (true) { 151 ready = poll(pfds, 1, 5000); 152 ASSERT_EQ(ready, 1) TH_LOG("poll return value"); 153 154 if (pfds[0].revents & POLLIN) { 155 memset(buf, 0, sizeof(buf)); 156 err = read(self->hidraw_fd, buf, sizeof(buf)); 157 ASSERT_EQ(err, 6) TH_LOG("read_hidraw"); 158 ASSERT_EQ(buf[0], 1); 159 ASSERT_EQ(buf[1], 42); 160 161 /* call the revoke ioctl */ 162 err = ioctl(self->hidraw_fd, HIDIOCREVOKE, NULL); 163 ASSERT_OK(err) TH_LOG("couldn't revoke the hidraw fd"); 164 } else { 165 break; 166 } 167 } 168 169 ASSERT_TRUE(pfds[0].revents & POLLHUP); 170 } 171 172 /* 173 * After initial opening/checks of hidraw, revoke the hidraw 174 * node and check that we can not read any more data. 175 */ 176 TEST_F(hidraw, write_event_revoked) 177 { 178 struct timespec time_to_wait; 179 __u8 buf[10] = {0}; 180 int err; 181 182 /* inject one event from hidraw */ 183 buf[0] = 1; /* report ID */ 184 buf[1] = 2; 185 buf[2] = 42; 186 187 pthread_mutex_lock(&uhid_output_mtx); 188 189 memset(output_report, 0, sizeof(output_report)); 190 clock_gettime(CLOCK_REALTIME, &time_to_wait); 191 time_to_wait.tv_sec += 2; 192 193 err = write(self->hidraw_fd, buf, 3); 194 ASSERT_EQ(err, 3) TH_LOG("unexpected error while writing to hidraw node: %d", err); 195 196 err = pthread_cond_timedwait(&uhid_output_cond, &uhid_output_mtx, &time_to_wait); 197 ASSERT_OK(err) TH_LOG("error while calling waiting for the condition"); 198 199 ASSERT_EQ(output_report[0], 1); 200 ASSERT_EQ(output_report[1], 2); 201 ASSERT_EQ(output_report[2], 42); 202 203 /* call the revoke ioctl */ 204 err = ioctl(self->hidraw_fd, HIDIOCREVOKE, NULL); 205 ASSERT_OK(err) TH_LOG("couldn't revoke the hidraw fd"); 206 207 /* inject one other event */ 208 buf[0] = 1; 209 buf[1] = 43; 210 err = write(self->hidraw_fd, buf, 3); 211 ASSERT_LT(err, 0) TH_LOG("unexpected success while writing to hidraw node: %d", err); 212 ASSERT_EQ(errno, ENODEV) TH_LOG("unexpected error code while writing to hidraw node: %d", 213 errno); 214 215 pthread_mutex_unlock(&uhid_output_mtx); 216 } 217 218 int main(int argc, char **argv) 219 { 220 return test_harness_run(argc, argv); 221 } 222