1 /**
2 * Copyright © 2009 Red Hat, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 */
23
24 #ifdef HAVE_DIX_CONFIG_H
25 #include <dix-config.h>
26 #endif
27
28 /*
29 * Protocol testing for XISelectEvents request.
30 *
31 * Test approach:
32 *
33 * Wrap XISetEventMask to intercept when the server tries to apply the event
34 * mask. Ensure that the mask passed in is equivalent to the one supplied by
35 * the client. Ensure that invalid devices and invalid masks return errors
36 * as appropriate.
37 *
38 * Tests included:
39 * BadValue for num_masks < 0
40 * BadWindow for invalid windows
41 * BadDevice for non-existing devices
42 * BadImplemenation for devices >= 0xFF
43 * BadValue if HierarchyChanged bit is set for devices other than
44 * XIAllDevices
45 * BadValue for invalid mask bits
46 * Sucecss for excessive mask lengths
47 *
48 */
49
50 #include <stdint.h>
51 #include <X11/X.h>
52 #include <X11/Xproto.h>
53 #include <X11/extensions/XI2proto.h>
54 #include "inputstr.h"
55 #include "windowstr.h"
56 #include "extinit.h" /* for XInputExtensionInit */
57 #include "scrnintstr.h"
58 #include "exglobals.h"
59 #include "xiselectev.h"
60
61 #include "protocol-common.h"
62
63 static unsigned char *data[4096 * 20]; /* the request data buffer */
64
65 extern ClientRec client_window;
66
67 int
68 __real_XISetEventMask(DeviceIntPtr dev, WindowPtr win, ClientPtr client,
69 int len, unsigned char *mask);
70
71 int
__wrap_XISetEventMask(DeviceIntPtr dev,WindowPtr win,ClientPtr client,int len,unsigned char * mask)72 __wrap_XISetEventMask(DeviceIntPtr dev, WindowPtr win, ClientPtr client,
73 int len, unsigned char *mask)
74 {
75 if (!enable_XISetEventMask_wrap)
76 return __real_XISetEventMask(dev, win, client, len, mask);
77
78 return Success;
79 }
80
81 static void
request_XISelectEvent(xXISelectEventsReq * req,int error)82 request_XISelectEvent(xXISelectEventsReq * req, int error)
83 {
84 int i;
85 int rc;
86 ClientRec client;
87 xXIEventMask *mask, *next;
88
89 req->length = (sz_xXISelectEventsReq / 4);
90 mask = (xXIEventMask *) &req[1];
91 for (i = 0; i < req->num_masks; i++) {
92 req->length += sizeof(xXIEventMask) / 4 + mask->mask_len;
93 mask = (xXIEventMask *) ((char *) &mask[1] + mask->mask_len * 4);
94 }
95
96 client = init_client(req->length, req);
97
98 rc = ProcXISelectEvents(&client);
99 assert(rc == error);
100
101 client.swapped = TRUE;
102
103 mask = (xXIEventMask *) &req[1];
104 for (i = 0; i < req->num_masks; i++) {
105 next = (xXIEventMask *) ((char *) &mask[1] + mask->mask_len * 4);
106 swaps(&mask->deviceid);
107 swaps(&mask->mask_len);
108 mask = next;
109 }
110
111 swapl(&req->win);
112 swaps(&req->length);
113 swaps(&req->num_masks);
114 rc = SProcXISelectEvents(&client);
115 assert(rc == error);
116 }
117
118 static void
_set_bit(unsigned char * bits,int bit)119 _set_bit(unsigned char *bits, int bit)
120 {
121 SetBit(bits, bit);
122 if (bit >= XI_TouchBegin && bit <= XI_TouchOwnership) {
123 SetBit(bits, XI_TouchBegin);
124 SetBit(bits, XI_TouchUpdate);
125 SetBit(bits, XI_TouchEnd);
126 }
127 }
128
129 static void
_clear_bit(unsigned char * bits,int bit)130 _clear_bit(unsigned char *bits, int bit)
131 {
132 ClearBit(bits, bit);
133 if (bit >= XI_TouchBegin && bit <= XI_TouchOwnership) {
134 ClearBit(bits, XI_TouchBegin);
135 ClearBit(bits, XI_TouchUpdate);
136 ClearBit(bits, XI_TouchEnd);
137 }
138 }
139
140 static void
request_XISelectEvents_masks(xXISelectEventsReq * req)141 request_XISelectEvents_masks(xXISelectEventsReq * req)
142 {
143 int i, j;
144 xXIEventMask *mask;
145 int nmasks = (XI2LASTEVENT + 7) / 8;
146 unsigned char *bits;
147
148 mask = (xXIEventMask *) &req[1];
149 req->win = ROOT_WINDOW_ID;
150
151 /* if a clients submits more than 100 masks, consider it insane and untested */
152 for (i = 1; i <= 1000; i++) {
153 req->num_masks = i;
154 mask->deviceid = XIAllDevices;
155
156 /* Test 0:
157 * mask_len is 0 -> Success
158 */
159 mask->mask_len = 0;
160 request_XISelectEvent(req, Success);
161
162 /* Test 1:
163 * mask may be larger than needed for XI2LASTEVENT.
164 * Test setting each valid mask bit, while leaving unneeded bits 0.
165 * -> Success
166 */
167 bits = (unsigned char *) &mask[1];
168 mask->mask_len = (nmasks + 3) / 4 * 10;
169 memset(bits, 0, mask->mask_len * 4);
170 for (j = 0; j <= XI2LASTEVENT; j++) {
171 _set_bit(bits, j);
172 request_XISelectEvent(req, Success);
173 _clear_bit(bits, j);
174 }
175
176 /* Test 2:
177 * mask may be larger than needed for XI2LASTEVENT.
178 * Test setting all valid mask bits, while leaving unneeded bits 0.
179 * -> Success
180 */
181 bits = (unsigned char *) &mask[1];
182 mask->mask_len = (nmasks + 3) / 4 * 10;
183 memset(bits, 0, mask->mask_len * 4);
184
185 for (j = 0; j <= XI2LASTEVENT; j++) {
186 _set_bit(bits, j);
187 request_XISelectEvent(req, Success);
188 }
189
190 /* Test 3:
191 * mask is larger than needed for XI2LASTEVENT. If any unneeded bit
192 * is set -> BadValue
193 */
194 bits = (unsigned char *) &mask[1];
195 mask->mask_len = (nmasks + 3) / 4 * 10;
196 memset(bits, 0, mask->mask_len * 4);
197
198 for (j = XI2LASTEVENT + 1; j < mask->mask_len * 4; j++) {
199 _set_bit(bits, j);
200 request_XISelectEvent(req, BadValue);
201 _clear_bit(bits, j);
202 }
203
204 /* Test 4:
205 * Mask len is a sensible length, only valid bits are set -> Success
206 */
207 bits = (unsigned char *) &mask[1];
208 mask->mask_len = (nmasks + 3) / 4;
209 memset(bits, 0, mask->mask_len * 4);
210 for (j = 0; j <= XI2LASTEVENT; j++) {
211 _set_bit(bits, j);
212 request_XISelectEvent(req, Success);
213 }
214
215 /* Test 5:
216 * HierarchyChanged bit is BadValue for devices other than
217 * XIAllDevices
218 */
219 bits = (unsigned char *) &mask[1];
220 mask->mask_len = (nmasks + 3) / 4;
221 memset(bits, 0, mask->mask_len * 4);
222 SetBit(bits, XI_HierarchyChanged);
223 mask->deviceid = XIAllDevices;
224 request_XISelectEvent(req, Success);
225 for (j = 1; j < devices.num_devices; j++) {
226 mask->deviceid = j;
227 request_XISelectEvent(req, BadValue);
228 }
229
230 /* Test 6:
231 * All bits set minus hierarchy changed bit -> Success
232 */
233 bits = (unsigned char *) &mask[1];
234 mask->mask_len = (nmasks + 3) / 4;
235 memset(bits, 0, mask->mask_len * 4);
236 for (j = 0; j <= XI2LASTEVENT; j++)
237 _set_bit(bits, j);
238 _clear_bit(bits, XI_HierarchyChanged);
239 for (j = 1; j < 6; j++) {
240 mask->deviceid = j;
241 request_XISelectEvent(req, Success);
242 }
243
244 mask =
245 (xXIEventMask *) ((char *) mask + sizeof(xXIEventMask) +
246 mask->mask_len * 4);
247 }
248 }
249
250 static void
test_XISelectEvents(void)251 test_XISelectEvents(void)
252 {
253 int i;
254 xXIEventMask *mask;
255 xXISelectEventsReq *req;
256
257 req = (xXISelectEventsReq *) data;
258
259 request_init(req, XISelectEvents);
260
261 printf("Testing for BadValue on zero-length masks\n");
262 /* zero masks are BadValue, regardless of the window */
263 req->num_masks = 0;
264
265 req->win = None;
266 request_XISelectEvent(req, BadValue);
267
268 req->win = ROOT_WINDOW_ID;
269 request_XISelectEvent(req, BadValue);
270
271 req->win = CLIENT_WINDOW_ID;
272 request_XISelectEvent(req, BadValue);
273
274 printf("Testing for BadWindow.\n");
275 /* None window is BadWindow, regardless of the masks.
276 * We don't actually need to set the masks here, BadWindow must occur
277 * before checking the masks.
278 */
279 req->win = None;
280 req->num_masks = 1;
281 request_XISelectEvent(req, BadWindow);
282
283 req->num_masks = 2;
284 request_XISelectEvent(req, BadWindow);
285
286 req->num_masks = 0xFF;
287 request_XISelectEvent(req, BadWindow);
288
289 /* request size is 3, so 0xFFFC is the highest num_mask that doesn't
290 * overflow req->length */
291 req->num_masks = 0xFFFC;
292 request_XISelectEvent(req, BadWindow);
293
294 printf("Triggering num_masks/length overflow\n");
295 req->win = ROOT_WINDOW_ID;
296 /* Integer overflow - req->length can't hold that much */
297 req->num_masks = 0xFFFF;
298 request_XISelectEvent(req, BadLength);
299
300 req->win = ROOT_WINDOW_ID;
301 req->num_masks = 1;
302
303 printf("Triggering bogus mask length error\n");
304 mask = (xXIEventMask *) &req[1];
305 mask->deviceid = 0;
306 mask->mask_len = 0xFFFF;
307 request_XISelectEvent(req, BadLength);
308
309 /* testing various device ids */
310 printf("Testing existing device ids.\n");
311 for (i = 0; i < 6; i++) {
312 mask = (xXIEventMask *) &req[1];
313 mask->deviceid = i;
314 mask->mask_len = 1;
315 req->win = ROOT_WINDOW_ID;
316 req->num_masks = 1;
317 request_XISelectEvent(req, Success);
318 }
319
320 printf("Testing non-existing device ids.\n");
321 for (i = 6; i <= 0xFFFF; i++) {
322 req->win = ROOT_WINDOW_ID;
323 req->num_masks = 1;
324 mask = (xXIEventMask *) &req[1];
325 mask->deviceid = i;
326 mask->mask_len = 1;
327 request_XISelectEvent(req, BadDevice);
328 }
329
330 request_XISelectEvents_masks(req);
331 }
332
333 int
protocol_xiselectevents_test(void)334 protocol_xiselectevents_test(void)
335 {
336 init_simple();
337
338 test_XISelectEvents();
339
340 return 0;
341 }
342