Browse Source

evdev: decode struct input_absinfo regardless of in-kernel definitions

* evdev.c (struct_input_absinfo): New typedef.
(abs_ioctl): Add code argument. Add orig_sz, res_sz, sz, read_sz local
variables. Decode resolution field regardless of
HAVE_STRUCT_INPUT_ABSINFO_RESOLUTION.
(evdev_read_ioctl, evdev_write_ioctl): Pass code to abs_ioctl.
* tests/ioctl_evdev-success.c (print_input_absinfo): Update expected
output.
(main): Add absinfo_sz, absinfo_24, absinfo_32 local variables; add
additional checks for struct input_absinfo.

References: https://bugzilla.redhat.com/show_bug.cgi?id=1758201
Eugene Syromyatnikov 1 month ago
parent
commit
f4a67819e9
2 changed files with 99 additions and 30 deletions
  1. 52
    26
      evdev.c
  2. 47
    4
      tests/ioctl_evdev-success.c

+ 52
- 26
evdev.c View File

@@ -37,6 +37,15 @@
37 37
 #  define SYN_MAX 0xf
38 38
 # endif
39 39
 
40
+typedef struct {
41
+	int32_t value;
42
+	int32_t minimum;
43
+	int32_t maximum;
44
+	int32_t fuzz;
45
+	int32_t flat;
46
+	int32_t resolution; /**< Added by Linux commit v2.6.31-rc1~100^2~1 */
47
+} struct_input_absinfo;
48
+
40 49
 /** Added by Linux commit v2.6.37-rc1~5^2~3^2~47 */
41 50
 typedef struct {
42 51
 	uint8_t  flags;
@@ -53,6 +62,9 @@ typedef struct {
53 62
 	uint64_t codes_ptr;
54 63
 } struct_input_mask;
55 64
 
65
+static_assert(sizeof(struct input_absinfo) <= sizeof(struct_input_absinfo),
66
+	      "Unexpected struct input_absinfo size, please update "
67
+	      "the decoder");
56 68
 # ifdef HAVE_STRUCT_INPUT_KEYMAP_ENTRY
57 69
 static_assert(sizeof(struct input_keymap_entry)
58 70
 	      == sizeof(struct_input_keymap_entry),
@@ -83,36 +95,50 @@ static_assert(sizeof(struct input_mask) == sizeof(struct_input_mask),
83 95
 # endif
84 96
 
85 97
 static int
86
-abs_ioctl(struct tcb *const tcp, const kernel_ulong_t arg)
98
+abs_ioctl(struct tcb *const tcp, const unsigned int code,
99
+	  const kernel_ulong_t arg)
87 100
 {
101
+	static const size_t orig_sz = offsetofend(struct_input_absinfo, flat);
102
+	static const size_t res_sz = offsetofend(struct_input_absinfo,
103
+						 resolution);
104
+
105
+	struct_input_absinfo absinfo;
106
+	size_t sz = _IOC_SIZE(code);
107
+	size_t read_sz = MIN(sz, sizeof(absinfo));
108
+
109
+	if (sz < orig_sz)
110
+		return RVAL_DECODED;
111
+
88 112
 	tprints(", ");
89 113
 
90
-	struct input_absinfo absinfo;
91
-
92
-	if (!umove_or_printaddr(tcp, arg, &absinfo)) {
93
-		tprintf("{value=%u"
94
-			", minimum=%u, ",
95
-			absinfo.value,
96
-			absinfo.minimum);
97
-
98
-		if (!abbrev(tcp)) {
99
-			tprintf("maximum=%u"
100
-				", fuzz=%u"
101
-				", flat=%u",
102
-				absinfo.maximum,
103
-				absinfo.fuzz,
104
-				absinfo.flat);
105
-# ifdef HAVE_STRUCT_INPUT_ABSINFO_RESOLUTION
106
-			tprintf(", resolution=%u",
107
-				absinfo.resolution);
108
-# endif
109
-		} else {
110
-			tprints("...");
111
-		}
114
+	if (umoven_or_printaddr(tcp, arg, read_sz, &absinfo))
115
+		return RVAL_IOCTL_DECODED;
116
+
117
+	tprintf("{value=%u"
118
+		", minimum=%u, ",
119
+		absinfo.value,
120
+		absinfo.minimum);
112 121
 
113
-		tprints("}");
122
+	if (!abbrev(tcp)) {
123
+		tprintf("maximum=%u"
124
+			", fuzz=%u"
125
+			", flat=%u",
126
+			absinfo.maximum,
127
+			absinfo.fuzz,
128
+			absinfo.flat);
129
+		if (sz >= res_sz) {
130
+			tprintf(", resolution=%u%s",
131
+				absinfo.resolution,
132
+				sz > res_sz ? ", ..." : "");
133
+		} else if (sz > orig_sz) {
134
+			tprints(", ...");
135
+		}
136
+	} else {
137
+		tprints("...");
114 138
 	}
115 139
 
140
+	tprints("}");
141
+
116 142
 	return RVAL_IOCTL_DECODED;
117 143
 }
118 144
 
@@ -402,7 +428,7 @@ evdev_read_ioctl(struct tcb *const tcp, const unsigned int code,
402 428
 
403 429
 	/* multi-number fixed-length commands */
404 430
 	if ((_IOC_NR(code) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0)))
405
-		return abs_ioctl(tcp, arg);
431
+		return abs_ioctl(tcp, code, arg);
406 432
 
407 433
 	/* multi-number variable-length commands */
408 434
 	if ((_IOC_NR(code) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0, 0)))
@@ -443,7 +469,7 @@ evdev_write_ioctl(struct tcb *const tcp, const unsigned int code,
443 469
 
444 470
 	/* multi-number fixed-length commands */
445 471
 	if ((_IOC_NR(code) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0)))
446
-		return abs_ioctl(tcp, arg);
472
+		return abs_ioctl(tcp, code, arg);
447 473
 
448 474
 	return 0;
449 475
 }

+ 47
- 4
tests/ioctl_evdev-success.c View File

@@ -56,6 +56,9 @@ static void
56 56
 print_input_absinfo(long rc, const void *ptr, const void *arg)
57 57
 {
58 58
 	const struct input_absinfo *absinfo = ptr;
59
+# if VERBOSE
60
+	const uintptr_t sz = (uintptr_t) arg;
61
+# endif
59 62
 
60 63
 	if (rc < 0) {
61 64
 		printf("%p", absinfo);
@@ -67,9 +70,20 @@ print_input_absinfo(long rc, const void *ptr, const void *arg)
67 70
 	PRINT_FIELD_U(", ", *absinfo, maximum);
68 71
 	PRINT_FIELD_U(", ", *absinfo, fuzz);
69 72
 	PRINT_FIELD_U(", ", *absinfo, flat);
73
+	if (sz > offsetofend(struct input_absinfo, flat)) {
74
+		if (sz >= 24) {
70 75
 #  ifdef HAVE_STRUCT_INPUT_ABSINFO_RESOLUTION
71
-	PRINT_FIELD_U(", ", *absinfo, resolution);
76
+			PRINT_FIELD_U(", ", *absinfo, resolution);
77
+#  else
78
+			printf(", resolution=%u", *((int *) ptr + 5));
72 79
 #  endif
80
+
81
+			if (sz > 24)
82
+				printf(", ...");
83
+		} else {
84
+			printf(", ...");
85
+		}
86
+	}
73 87
 # else
74 88
 	printf(", ...");
75 89
 # endif
@@ -201,10 +215,22 @@ main(int argc, char **argv)
201 215
 				   ", EVIOCGID, NULL) returning %lu",
202 216
 				   inject_retval);
203 217
 
218
+	static const void *absinfo_sz =
219
+		(const void *) (uintptr_t) sizeof(struct input_absinfo);
220
+
204 221
 	TAIL_ALLOC_OBJECT_CONST_PTR(struct input_id, id);
205 222
 	TAIL_ALLOC_OBJECT_CONST_PTR(struct input_absinfo, absinfo);
206 223
 	TAIL_ALLOC_OBJECT_CONST_PTR(int, bad_addr_slot);
207 224
 
225
+	struct input_absinfo *absinfo_24 = tail_alloc(MAX(sizeof(*absinfo_24),
226
+							  24));
227
+	struct input_absinfo *absinfo_32 = tail_alloc(MAX(sizeof(*absinfo_32),
228
+							  32));
229
+
230
+	fill_memory(absinfo, sizeof(struct input_absinfo));
231
+	fill_memory(absinfo_24, 24);
232
+	fill_memory(absinfo_32, 32);
233
+
208 234
 # ifdef EVIOCGMTSLOTS
209 235
 	static const unsigned int mtslots[] = { ABS_MT_SLOT, 1, 3 };
210 236
 	static const char * const mtslots_str[] = {
@@ -282,9 +308,26 @@ main(int argc, char **argv)
282 308
 		const void *ptr;
283 309
 	} a[] = {
284 310
 		{ { ARG_STR(EVIOCGID), id, print_input_id }, NULL },
285
-		{ { ARG_STR(EVIOCGABS(ABS_X)), absinfo, print_input_absinfo }, NULL },
286
-		{ { ARG_STR(EVIOCGABS(ABS_Y)), absinfo, print_input_absinfo }, NULL },
287
-		{ { ARG_STR(EVIOCGABS(ABS_Y)), absinfo, print_input_absinfo }, NULL },
311
+		{ { _IOC(_IOC_READ, 'E', 0x40 + ABS_Y, 19), "EVIOCGABS(ABS_Y)",
312
+		    absinfo, NULL }, NULL },
313
+		{ { _IOC(_IOC_READ, 'E', 0x40 + ABS_Y, 20),
314
+		    "EVIOCGABS(ABS_Y)", absinfo, print_input_absinfo },
315
+		  (const void *) (uintptr_t) 20 },
316
+		{ { _IOC(_IOC_READ, 'E', 0x40 + ABS_Y, 21),
317
+		    "EVIOCGABS(ABS_Y)", absinfo_24, print_input_absinfo },
318
+		  (const void *) (uintptr_t) 21 },
319
+		{ { _IOC(_IOC_READ, 'E', 0x40 + ABS_Y, 24),
320
+		    "EVIOCGABS(ABS_Y)", absinfo_24, print_input_absinfo },
321
+		  (const void *) (uintptr_t) 24 },
322
+		{ { _IOC(_IOC_READ, 'E', 0x40 + ABS_Y, 32),
323
+		    "EVIOCGABS(ABS_Y)", absinfo_32, print_input_absinfo },
324
+		  (const void *) (uintptr_t) 32 },
325
+		{ { ARG_STR(EVIOCGABS(ABS_X)), absinfo, print_input_absinfo },
326
+		  absinfo_sz},
327
+		{ { ARG_STR(EVIOCGABS(ABS_Y)), absinfo, print_input_absinfo },
328
+		  absinfo_sz },
329
+		{ { ARG_STR(EVIOCGABS(ABS_Y)), absinfo, print_input_absinfo },
330
+		  absinfo_sz },
288 331
 		{ { ARG_STR(EVIOCGBIT(0, 0)), ev_more, print_getbit },
289 332
 			inject_retval * 8 <= EV_LED
290 333
 				? (const void *) &ev_more_str_2

Loading…
Cancel
Save