hidraw.c 5.7 KB

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