1 /*
2 * Copyright (c) 2018-2021 The strace developers.
3 * All rights reserved.
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 */
7
8 #include "tests.h"
9
10 #include <assert.h>
11 #include <inttypes.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <sys/ioctl.h>
15 #include <linux/ioctl.h>
16 #include <linux/input.h>
17 #include "print_fields.h"
18
19 #define NUM_WORDS 4
20
21 static const char *errstr;
22
23 struct evdev_check {
24 unsigned long cmd;
25 const char *cmd_str;
26 const void *arg_ptr;
27 void (*print_arg)(long rc, const void *ptr, const void *arg);
28 };
29
30 static long
31 invoke_test_syscall(unsigned long cmd, const void *p)
32 {
33 long rc = ioctl(-1, cmd, p);
34 errstr = sprintrc(rc);
35 static char inj_errstr[4096];
36
37 snprintf(inj_errstr, sizeof(inj_errstr), "%s (INJECTED)", errstr);
38 errstr = inj_errstr;
39 return rc;
40 }
41
42 static void
43 test_evdev(struct evdev_check *check, const void *arg)
44 {
45 long rc = invoke_test_syscall(check->cmd, check->arg_ptr);
46 printf("ioctl(-1, %s, ", sprintxlat(check->cmd_str, check->cmd, NULL));
47 if (check->print_arg)
48 check->print_arg(rc, check->arg_ptr, arg);
49 else
50 printf("%p", check->arg_ptr);
51 printf(") = %s\n", errstr);
52 }
53
54 static void
55 print_input_absinfo(long rc, const void *ptr, const void *arg)
56 {
57 const struct input_absinfo *absinfo = ptr;
58 #if VERBOSE
59 const uintptr_t sz = (uintptr_t) arg;
60 #endif
61
62 if (rc < 0) {
63 printf("%p", absinfo);
64 return;
65 }
66 printf("{");
67 PRINT_FIELD_U(*absinfo, value);
68 printf(", ");
69 PRINT_FIELD_U(*absinfo, minimum);
70 #if VERBOSE
71 printf(", ");
72 PRINT_FIELD_U(*absinfo, maximum);
73 printf(", ");
74 PRINT_FIELD_U(*absinfo, fuzz);
75 printf(", ");
76 PRINT_FIELD_U(*absinfo, flat);
77 if (sz > offsetofend(struct input_absinfo, flat)) {
78 if (sz >= 24) {
79 printf(", ");
80 PRINT_FIELD_U(*absinfo, resolution);
81
82 if (sz > 24)
83 printf(", ...");
84 } else {
85 printf(", ...");
86 }
87 }
88 #else
89 printf(", ...");
90 #endif
91 printf("}");
92 }
93
94 static void
95 print_input_id(long rc, const void *ptr, const void *arg)
96 {
97 const struct input_id *id = ptr;
98
99 if (rc < 0) {
100 printf("%p", id);
101 return;
102 }
103 printf("{bustype=%" PRIu16
104 ", vendor=%" PRIu16
105 ", product=%" PRIu16
106 ", version=%" PRIu16 "}",
107 id->bustype, id->vendor, id->product, id->version);
108 }
109
110 static void
111 print_mtslots(long rc, const void *ptr, const void *arg)
112 {
113 const unsigned int *buffer = ptr;
114 const char * const * str = arg;
115
116 if (rc < 0) {
117 printf("%p", buffer);
118 return;
119 }
120
121 printf("{code=%s", sprintxlat(*str, *buffer, NULL));
122 printf(", values=[");
123 for (unsigned int i = 1; str[i]; i++)
124 printf("%s%s", i > 1 ? ", " : "", str[i]);
125 printf("]}");
126 }
127
128 static void
129 print_getbit(long rc, const void *ptr, const void *arg)
130 {
131 const char * const *str = arg + sizeof(char *);
132 #if XLAT_RAW || XLAT_VERBOSE
133 const unsigned long *buf = ptr;
134 const unsigned long buf_size = (uintptr_t) (str[-1]);
135 #endif
136
137
138
139 if (rc <= 0) {
140 printf("%p", ptr);
141 return;
142 }
143
144 #if !XLAT_RAW
145 printf("[");
146 for (unsigned long i = 0; str[i]; i++) {
147 # if ! VERBOSE
148 if (i >= 4) {
149 printf(" ...");
150 break;
151 }
152 # endif
153 if (i)
154 printf(" ");
155 printf("%s", str[i]);
156 }
157 printf("]");
158 #endif /* !XLAT_RAW */
159
160 #if XLAT_VERBOSE
161 printf(" /* ");
162 #endif
163
164 #if XLAT_RAW || XLAT_VERBOSE
165 printf("[");
166 const unsigned long cnt =
167 (MIN((unsigned long) rc, buf_size) + sizeof(long) - 1)
168 / sizeof(long);
169 for (unsigned long i = 0; i < cnt; i++)
170 printf("%s%#lx", i ? ", " : "", buf[i]);
171 printf("]");
172 #endif
173
174 #if XLAT_VERBOSE
175 printf(" */");
176 #endif
177 }
178
179 int
180 main(int argc, char **argv)
181 {
182 unsigned long num_skip;
183 long inject_retval;
184 bool locked = false;
185
186 if (argc == 1)
187 return 0;
188
189 if (argc < 3)
190 error_msg_and_fail("Usage: %s NUM_SKIP INJECT_RETVAL", argv[0]);
191
192 num_skip = strtoul(argv[1], NULL, 0);
193 inject_retval = strtol(argv[2], NULL, 0);
194
195 if (inject_retval < 0)
196 error_msg_and_fail("Expected non-negative INJECT_RETVAL, "
197 "but got %ld", inject_retval);
198
199 for (unsigned int i = 0; i < num_skip; i++) {
200 long rc = ioctl(-1, EVIOCGID, NULL);
201 printf("ioctl(-1, %s, NULL) = %s%s\n",
202 XLAT_STR(EVIOCGID), sprintrc(rc),
203 rc == inject_retval ? " (INJECTED)" : "");
204
205 if (rc != inject_retval)
206 continue;
207
208 locked = true;
209 break;
210 }
211
212 if (!locked)
213 error_msg_and_fail("Hasn't locked on ioctl(-1"
214 ", EVIOCGID, NULL) returning %lu",
215 inject_retval);
216
217 static const void *absinfo_sz =
218 (const void *) (uintptr_t) sizeof(struct input_absinfo);
219
220 TAIL_ALLOC_OBJECT_CONST_PTR(struct input_id, id);
221 TAIL_ALLOC_OBJECT_CONST_PTR(struct input_absinfo, absinfo);
222 TAIL_ALLOC_OBJECT_CONST_PTR(int, bad_addr_slot);
223
224 struct input_absinfo *absinfo_24 = tail_alloc(MAX(sizeof(*absinfo_24),
225 24));
226 struct input_absinfo *absinfo_32 = tail_alloc(MAX(sizeof(*absinfo_32),
227 32));
228
229 fill_memory(absinfo, sizeof(struct input_absinfo));
230 fill_memory(absinfo_24, 24);
231 fill_memory(absinfo_32, 32);
232
233 static const unsigned int mtslots[] = { ABS_MT_SLOT, 1, 3 };
234 static const char * const mtslots_str[] = {
235 "ABS_MT_SLOT", "1", "3", NULL };
236
237 /* invalid flag */
238 static const unsigned int invalid_mtslot[] = { -1, 1 };
239 static const char * const invalid_mtslot_str[] = {
240 ""
241 #if !XLAT_RAW && !XLAT_VERBOSE
242 "0xffffffff"
243 #endif
244 #if !XLAT_VERBOSE
245 " /* "
246 #endif
247 "ABS_MT_???"
248 #if !XLAT_VERBOSE
249 " */"
250 #endif
251 , "1", NULL };
252
253 enum { ULONG_BIT = sizeof(unsigned long) * 8 };
254
255 /* set more than 4 bits */
256 static const unsigned long ev_more[NUM_WORDS] = {
257 1 << EV_ABS | 1 << EV_MSC | 1 << EV_LED | 1 << EV_SND
258 | 1 << EV_PWR };
259 static const char * const ev_more_str_2[] = {
260 (char *) (uintptr_t) 4,
261 XLAT_KNOWN(0x3, "EV_ABS"), XLAT_KNOWN(0x4, "EV_MSC"), NULL };
262 static const char * const ev_more_str_3[] = {
263 (char *) (uintptr_t) 4,
264 XLAT_KNOWN(0x3, "EV_ABS"), XLAT_KNOWN(0x4, "EV_MSC"),
265 XLAT_KNOWN(0x11, "EV_LED"), XLAT_KNOWN(0x12, "EV_SND"),
266 XLAT_KNOWN(0x16, "EV_PWR"), NULL };
267
268 /* set less than 4 bits */
269 static const unsigned long ev_less[NUM_WORDS] = {
270 1 << EV_ABS | 1 << EV_MSC | 1 << EV_LED };
271 static const char * const ev_less_str_2[] = {
272 (char *) (uintptr_t) 4,
273 XLAT_KNOWN(0x3, "EV_ABS"), XLAT_KNOWN(0x4, "EV_MSC"), NULL };
274 static const char * const ev_less_str_3[] = {
275 (char *) (uintptr_t) 4,
276 XLAT_KNOWN(0x3, "EV_ABS"), XLAT_KNOWN(0x4, "EV_MSC"),
277 XLAT_KNOWN(0x11, "EV_LED"), NULL };
278
279 /* set zero bit */
280 static const unsigned long ev_zero[NUM_WORDS] = { 0x0 };
281 static const char * const ev_zero_str[] = {
282 (char *) (uintptr_t) 1,
283 "", NULL };
284
285 /* KEY_MAX is 0x2ff which is greater than retval * 8 */
286 static const unsigned long key[NUM_WORDS] = {
287 1 << KEY_1 | 1 << KEY_2,
288 [ KEY_F12 / ULONG_BIT ] = 1 << (KEY_F12 % ULONG_BIT) };
289
290 static const char * const key_str_8[] = {
291 (char *) (uintptr_t) (NUM_WORDS * sizeof(long)),
292 XLAT_KNOWN(0x2, "KEY_1"), XLAT_KNOWN(0x3, "KEY_2"), NULL };
293 static const char * const key_str_16[] = {
294 (char *) (uintptr_t) (NUM_WORDS * sizeof(long)),
295 XLAT_KNOWN(0x2, "KEY_1"), XLAT_KNOWN(0x3, "KEY_2"),
296 XLAT_KNOWN(0x58, "KEY_F12"), NULL };
297
298 assert(sizeof(ev_more) >= (unsigned long) inject_retval);
299 assert(sizeof(ev_less) >= (unsigned long) inject_retval);
300 assert(sizeof(ev_zero) >= (unsigned long) inject_retval);
301 assert(sizeof(key) >= (unsigned long) inject_retval);
302
303 struct {
304 struct evdev_check check;
305 const void *ptr;
306 } a[] = {
307 { { ARG_STR(EVIOCGID), id, print_input_id }, NULL },
308 { { _IOC(_IOC_READ, 'E', 0x40 + ABS_Y, 19), "EVIOCGABS(ABS_Y)",
309 absinfo, NULL }, NULL },
310 { { _IOC(_IOC_READ, 'E', 0x40 + ABS_Y, 20),
311 "EVIOCGABS(ABS_Y)", absinfo, print_input_absinfo },
312 (const void *) (uintptr_t) 20 },
313 { { _IOC(_IOC_READ, 'E', 0x40 + ABS_Y, 21),
314 "EVIOCGABS(ABS_Y)", absinfo_24, print_input_absinfo },
315 (const void *) (uintptr_t) 21 },
316 { { _IOC(_IOC_READ, 'E', 0x40 + ABS_Y, 24),
317 "EVIOCGABS(ABS_Y)", absinfo_24, print_input_absinfo },
318 (const void *) (uintptr_t) 24 },
319 { { _IOC(_IOC_READ, 'E', 0x40 + ABS_Y, 32),
320 "EVIOCGABS(ABS_Y)", absinfo_32, print_input_absinfo },
321 (const void *) (uintptr_t) 32 },
322 { { ARG_STR(EVIOCGABS(ABS_X)), absinfo, print_input_absinfo },
323 absinfo_sz},
324 { { ARG_STR(EVIOCGABS(ABS_Y)), absinfo, print_input_absinfo },
325 absinfo_sz },
326 { { ARG_STR(EVIOCGABS(ABS_Y)), absinfo, print_input_absinfo },
327 absinfo_sz },
328 { { ARG_STR(EVIOCGBIT(0, 0)), ev_more, print_getbit },
329 inject_retval * 8 <= EV_LED
330 ? (const void *) &ev_more_str_2
331 : (const void *) &ev_more_str_3 },
332 { { ARG_STR(EVIOCGBIT(0, 0)), ev_less, print_getbit },
333 inject_retval * 8 <= EV_LED
334 ? (const void *) &ev_less_str_2
335 : (const void *) &ev_less_str_3 },
336 { { ARG_STR(EVIOCGBIT(0, 0)), ev_zero, print_getbit }, &ev_zero_str },
337 { { ARG_STR(EVIOCGBIT(EV_KEY, 0)), key, print_getbit },
338 inject_retval * 8 <= KEY_F12
339 ? (const void *) &key_str_8
340 : (const void *) &key_str_16 },
341 { { ARG_STR(EVIOCGMTSLOTS(12)), mtslots, print_mtslots }, &mtslots_str },
342 { { ARG_STR(EVIOCGMTSLOTS(8)), invalid_mtslot, print_mtslots }, &invalid_mtslot_str }
343 };
344 for (unsigned int i = 0; i < ARRAY_SIZE(a); i++) {
345 test_evdev(&a[i].check, a[i].ptr);
346 }
347
348 puts("+++ exited with 0 +++");
349 return 0;
350 }