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