]> www.infradead.org Git - linux.git/commitdiff
selftests/hid: Add HIDIOCREVOKE tests
authorBenjamin Tissoires <bentiss@kernel.org>
Tue, 27 Aug 2024 08:19:32 +0000 (17:19 +0900)
committerBenjamin Tissoires <bentiss@kernel.org>
Thu, 29 Aug 2024 08:39:37 +0000 (10:39 +0200)
Add 4 tests for the new revoke ioctl, for read/write/ioctl and poll.

Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
Link: https://patch.msgid.link/20240827-hidraw-revoke-v5-4-d004a7451aea@kernel.org
Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
tools/testing/selftests/hid/hidraw.c

index 37372709130c276d9795933802b10560cabd85a8..f8b4f7ff292c2f832006ad74723a4166ee31c098 100644 (file)
@@ -3,6 +3,11 @@
 
 #include "hid_common.h"
 
+/* for older kernels */
+#ifndef HIDIOCREVOKE
+#define HIDIOCREVOKE         _IOW('H', 0x0D, int) /* Revoke device access */
+#endif /* HIDIOCREVOKE */
+
 FIXTURE(hidraw) {
        int dev_id;
        int uhid_fd;
@@ -84,6 +89,148 @@ TEST_F(hidraw, raw_event)
        ASSERT_EQ(buf[1], 42);
 }
 
+/*
+ * After initial opening/checks of hidraw, revoke the hidraw
+ * node and check that we can not read any more data.
+ */
+TEST_F(hidraw, raw_event_revoked)
+{
+       __u8 buf[10] = {0};
+       int err;
+
+       /* inject one event */
+       buf[0] = 1;
+       buf[1] = 42;
+       uhid_send_event(_metadata, self->uhid_fd, buf, 6);
+
+       /* read the data from hidraw */
+       memset(buf, 0, sizeof(buf));
+       err = read(self->hidraw_fd, buf, sizeof(buf));
+       ASSERT_EQ(err, 6) TH_LOG("read_hidraw");
+       ASSERT_EQ(buf[0], 1);
+       ASSERT_EQ(buf[1], 42);
+
+       /* call the revoke ioctl */
+       err = ioctl(self->hidraw_fd, HIDIOCREVOKE, NULL);
+       ASSERT_OK(err) TH_LOG("couldn't revoke the hidraw fd");
+
+       /* inject one other event */
+       buf[0] = 1;
+       buf[1] = 43;
+       uhid_send_event(_metadata, self->uhid_fd, buf, 6);
+
+       /* read the data from hidraw */
+       memset(buf, 0, sizeof(buf));
+       err = read(self->hidraw_fd, buf, sizeof(buf));
+       ASSERT_EQ(err, -1) TH_LOG("read_hidraw");
+       ASSERT_EQ(errno, ENODEV) TH_LOG("unexpected error code while reading the hidraw node: %d",
+                                       errno);
+}
+
+/*
+ * Revoke the hidraw node and check that we can not do any ioctl.
+ */
+TEST_F(hidraw, ioctl_revoked)
+{
+       int err, desc_size = 0;
+
+       /* call the revoke ioctl */
+       err = ioctl(self->hidraw_fd, HIDIOCREVOKE, NULL);
+       ASSERT_OK(err) TH_LOG("couldn't revoke the hidraw fd");
+
+       /* do an ioctl */
+       err = ioctl(self->hidraw_fd, HIDIOCGRDESCSIZE, &desc_size);
+       ASSERT_EQ(err, -1) TH_LOG("ioctl_hidraw");
+       ASSERT_EQ(errno, ENODEV) TH_LOG("unexpected error code while doing an ioctl: %d",
+                                       errno);
+}
+
+/*
+ * Setup polling of the fd, and check that revoke works properly.
+ */
+TEST_F(hidraw, poll_revoked)
+{
+       struct pollfd pfds[1];
+       __u8 buf[10] = {0};
+       int err, ready;
+
+       /* setup polling */
+       pfds[0].fd = self->hidraw_fd;
+       pfds[0].events = POLLIN;
+
+       /* inject one event */
+       buf[0] = 1;
+       buf[1] = 42;
+       uhid_send_event(_metadata, self->uhid_fd, buf, 6);
+
+       while (true) {
+               ready = poll(pfds, 1, 5000);
+               ASSERT_EQ(ready, 1) TH_LOG("poll return value");
+
+               if (pfds[0].revents & POLLIN) {
+                       memset(buf, 0, sizeof(buf));
+                       err = read(self->hidraw_fd, buf, sizeof(buf));
+                       ASSERT_EQ(err, 6) TH_LOG("read_hidraw");
+                       ASSERT_EQ(buf[0], 1);
+                       ASSERT_EQ(buf[1], 42);
+
+                       /* call the revoke ioctl */
+                       err = ioctl(self->hidraw_fd, HIDIOCREVOKE, NULL);
+                       ASSERT_OK(err) TH_LOG("couldn't revoke the hidraw fd");
+               } else {
+                       break;
+               }
+       }
+
+       ASSERT_TRUE(pfds[0].revents & POLLHUP);
+}
+
+/*
+ * After initial opening/checks of hidraw, revoke the hidraw
+ * node and check that we can not read any more data.
+ */
+TEST_F(hidraw, write_event_revoked)
+{
+       struct timespec time_to_wait;
+       __u8 buf[10] = {0};
+       int err;
+
+       /* inject one event from hidraw */
+       buf[0] = 1; /* report ID */
+       buf[1] = 2;
+       buf[2] = 42;
+
+       pthread_mutex_lock(&uhid_output_mtx);
+
+       memset(output_report, 0, sizeof(output_report));
+       clock_gettime(CLOCK_REALTIME, &time_to_wait);
+       time_to_wait.tv_sec += 2;
+
+       err = write(self->hidraw_fd, buf, 3);
+       ASSERT_EQ(err, 3) TH_LOG("unexpected error while writing to hidraw node: %d", err);
+
+       err = pthread_cond_timedwait(&uhid_output_cond, &uhid_output_mtx, &time_to_wait);
+       ASSERT_OK(err) TH_LOG("error while calling waiting for the condition");
+
+       ASSERT_EQ(output_report[0], 1);
+       ASSERT_EQ(output_report[1], 2);
+       ASSERT_EQ(output_report[2], 42);
+
+       /* call the revoke ioctl */
+       err = ioctl(self->hidraw_fd, HIDIOCREVOKE, NULL);
+       ASSERT_OK(err) TH_LOG("couldn't revoke the hidraw fd");
+
+       /* inject one other event */
+       buf[0] = 1;
+       buf[1] = 43;
+       err = write(self->hidraw_fd, buf, 3);
+       ASSERT_LT(err, 0) TH_LOG("unexpected success while writing to hidraw node: %d", err);
+       ASSERT_EQ(errno, ENODEV) TH_LOG("unexpected error code while writing to hidraw node: %d",
+                                       errno);
+
+       pthread_mutex_unlock(&uhid_output_mtx);
+}
+
 int main(int argc, char **argv)
 {
        return test_harness_run(argc, argv);