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