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