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/* Test relies on assert() */
25#undef NDEBUG
26
27#ifdef HAVE_DIX_CONFIG_H
28#include <dix-config.h>
29#endif
30
31/*
32 * Protocol testing for XISelectEvents request.
33 *
34 * Test approach:
35 *
36 * Wrap XISetEventMask to intercept when the server tries to apply the event
37 * mask. Ensure that the mask passed in is equivalent to the one supplied by
38 * the client. Ensure that invalid devices and invalid masks return errors
39 * as appropriate.
40 *
41 * Tests included:
42 * BadValue for num_masks < 0
43 * BadWindow for invalid windows
44 * BadDevice for non-existing devices
45 * BadImplemenation for devices >= 0xFF
46 * BadValue if HierarchyChanged bit is set for devices other than
47 *          XIAllDevices
48 * BadValue for invalid mask bits
49 * Sucecss for excessive mask lengths
50 *
51 */
52
53#include <stdint.h>
54#include <X11/X.h>
55#include <X11/Xproto.h>
56#include <X11/extensions/XI2proto.h>
57#include "inputstr.h"
58#include "windowstr.h"
59#include "extinit.h"            /* for XInputExtensionInit */
60#include "scrnintstr.h"
61#include "exglobals.h"
62#include "xiselectev.h"
63
64#include "protocol-common.h"
65
66static unsigned char *data[4096 * 20];  /* the request data buffer */
67
68extern ClientRec client_window;
69
70int
71__real_XISetEventMask(DeviceIntPtr dev, WindowPtr win, ClientPtr client,
72                      int len, unsigned char *mask);
73
74int
75__wrap_XISetEventMask(DeviceIntPtr dev, WindowPtr win, ClientPtr client,
76                      int len, unsigned char *mask)
77{
78    if (!enable_XISetEventMask_wrap)
79        return __real_XISetEventMask(dev, win, client, len, mask);
80
81    return Success;
82}
83
84static void
85request_XISelectEvent(xXISelectEventsReq * req, int error)
86{
87    int i;
88    int rc;
89    ClientRec client;
90    xXIEventMask *mask, *next;
91
92    req->length = (sz_xXISelectEventsReq / 4);
93    mask = (xXIEventMask *) &req[1];
94    for (i = 0; i < req->num_masks; i++) {
95        req->length += sizeof(xXIEventMask) / 4 + mask->mask_len;
96        mask = (xXIEventMask *) ((char *) &mask[1] + mask->mask_len * 4);
97    }
98
99    client = init_client(req->length, req);
100
101    rc = ProcXISelectEvents(&client);
102    assert(rc == error);
103
104    client.swapped = TRUE;
105
106    mask = (xXIEventMask *) &req[1];
107    for (i = 0; i < req->num_masks; i++) {
108        next = (xXIEventMask *) ((char *) &mask[1] + mask->mask_len * 4);
109        swaps(&mask->deviceid);
110        swaps(&mask->mask_len);
111        mask = next;
112    }
113
114    swapl(&req->win);
115    swaps(&req->length);
116    swaps(&req->num_masks);
117    rc = SProcXISelectEvents(&client);
118    assert(rc == error);
119}
120
121static void
122_set_bit(unsigned char *bits, int bit)
123{
124    SetBit(bits, bit);
125    if (bit >= XI_TouchBegin && bit <= XI_TouchOwnership) {
126        SetBit(bits, XI_TouchBegin);
127        SetBit(bits, XI_TouchUpdate);
128        SetBit(bits, XI_TouchEnd);
129    }
130    if (bit >= XI_GesturePinchBegin && bit <= XI_GesturePinchEnd) {
131        SetBit(bits, XI_GesturePinchBegin);
132        SetBit(bits, XI_GesturePinchUpdate);
133        SetBit(bits, XI_GesturePinchEnd);
134    }
135    if (bit >= XI_GestureSwipeBegin && bit <= XI_GestureSwipeEnd) {
136        SetBit(bits, XI_GestureSwipeBegin);
137        SetBit(bits, XI_GestureSwipeUpdate);
138        SetBit(bits, XI_GestureSwipeEnd);
139    }
140}
141
142static void
143_clear_bit(unsigned char *bits, int bit)
144{
145    ClearBit(bits, bit);
146    if (bit >= XI_TouchBegin && bit <= XI_TouchOwnership) {
147        ClearBit(bits, XI_TouchBegin);
148        ClearBit(bits, XI_TouchUpdate);
149        ClearBit(bits, XI_TouchEnd);
150    }
151    if (bit >= XI_GesturePinchBegin && bit <= XI_GesturePinchEnd) {
152        ClearBit(bits, XI_GesturePinchBegin);
153        ClearBit(bits, XI_GesturePinchUpdate);
154        ClearBit(bits, XI_GesturePinchEnd);
155    }
156    if (bit >= XI_GestureSwipeBegin && bit <= XI_GestureSwipeEnd) {
157        ClearBit(bits, XI_GestureSwipeBegin);
158        ClearBit(bits, XI_GestureSwipeUpdate);
159        ClearBit(bits, XI_GestureSwipeEnd);
160    }
161}
162
163static void
164request_XISelectEvents_masks(xXISelectEventsReq * req)
165{
166    int i, j;
167    xXIEventMask *mask;
168    int nmasks = XI2MASKSIZE;
169    unsigned char *bits;
170
171    mask = (xXIEventMask *) &req[1];
172    req->win = ROOT_WINDOW_ID;
173
174    /* if a clients submits more than 100 masks, consider it insane and untested */
175    for (i = 1; i <= 1000; i++) {
176        req->num_masks = i;
177        mask->deviceid = XIAllDevices;
178
179        /* Test 0:
180         * mask_len is 0 -> Success
181         */
182        mask->mask_len = 0;
183        request_XISelectEvent(req, Success);
184
185        /* Test 1:
186         * mask may be larger than needed for XI2LASTEVENT.
187         * Test setting each valid mask bit, while leaving unneeded bits 0.
188         * -> Success
189         */
190        bits = (unsigned char *) &mask[1];
191        mask->mask_len = (nmasks + 3) / 4 * 10;
192        memset(bits, 0, mask->mask_len * 4);
193        for (j = 0; j <= XI2LASTEVENT; j++) {
194            _set_bit(bits, j);
195            request_XISelectEvent(req, Success);
196            _clear_bit(bits, j);
197        }
198
199        /* Test 2:
200         * mask may be larger than needed for XI2LASTEVENT.
201         * Test setting all valid mask bits, while leaving unneeded bits 0.
202         * -> Success
203         */
204        bits = (unsigned char *) &mask[1];
205        mask->mask_len = (nmasks + 3) / 4 * 10;
206        memset(bits, 0, mask->mask_len * 4);
207
208        for (j = 0; j <= XI2LASTEVENT; j++) {
209            _set_bit(bits, j);
210            request_XISelectEvent(req, Success);
211        }
212
213        /* Test 3:
214         * mask is larger than needed for XI2LASTEVENT. If any unneeded bit
215         * is set -> BadValue
216         */
217        bits = (unsigned char *) &mask[1];
218        mask->mask_len = (nmasks + 3) / 4 * 10;
219        memset(bits, 0, mask->mask_len * 4);
220
221        for (j = XI2LASTEVENT + 1; j < mask->mask_len * 4; j++) {
222            _set_bit(bits, j);
223            request_XISelectEvent(req, BadValue);
224            _clear_bit(bits, j);
225        }
226
227        /* Test 4:
228         * Mask len is a sensible length, only valid bits are set -> Success
229         */
230        bits = (unsigned char *) &mask[1];
231        mask->mask_len = (nmasks + 3) / 4;
232        memset(bits, 0, mask->mask_len * 4);
233        for (j = 0; j <= XI2LASTEVENT; j++) {
234            _set_bit(bits, j);
235            request_XISelectEvent(req, Success);
236        }
237
238        /* Test 5:
239         * Mask len is 1 and XI_GestureSwipeEnd is set outside the mask.
240         * That bit should be ignored -> Success
241         */
242        bits = (unsigned char *) &mask[1];
243        mask->mask_len = 1;
244        memset(bits, 0, 5);
245        SetBit(bits, XI_ButtonPress); // does not matter which one
246        SetBit(bits, XI_GestureSwipeEnd);
247        request_XISelectEvent(req, Success);
248
249        /* Test 6:
250         * HierarchyChanged bit is BadValue for devices other than
251         * XIAllDevices
252         */
253        bits = (unsigned char *) &mask[1];
254        mask->mask_len = (nmasks + 3) / 4;
255        memset(bits, 0, mask->mask_len * 4);
256        SetBit(bits, XI_HierarchyChanged);
257        mask->deviceid = XIAllDevices;
258        request_XISelectEvent(req, Success);
259        for (j = 1; j < devices.num_devices; j++) {
260            mask->deviceid = j;
261            request_XISelectEvent(req, BadValue);
262        }
263
264        /* Test 7:
265         * All bits set minus hierarchy changed bit -> Success
266         */
267        bits = (unsigned char *) &mask[1];
268        mask->mask_len = (nmasks + 3) / 4;
269        memset(bits, 0, mask->mask_len * 4);
270        for (j = 0; j <= XI2LASTEVENT; j++)
271            _set_bit(bits, j);
272        _clear_bit(bits, XI_HierarchyChanged);
273        for (j = 1; j < 6; j++) {
274            mask->deviceid = j;
275            request_XISelectEvent(req, Success);
276        }
277
278        mask =
279            (xXIEventMask *) ((char *) mask + sizeof(xXIEventMask) +
280                              mask->mask_len * 4);
281    }
282}
283
284static void
285test_XISelectEvents(void)
286{
287    int i;
288    xXIEventMask *mask;
289    xXISelectEventsReq *req;
290
291    req = (xXISelectEventsReq *) data;
292
293    request_init(req, XISelectEvents);
294
295    printf("Testing for BadValue on zero-length masks\n");
296    /* zero masks are BadValue, regardless of the window */
297    req->num_masks = 0;
298
299    req->win = None;
300    request_XISelectEvent(req, BadValue);
301
302    req->win = ROOT_WINDOW_ID;
303    request_XISelectEvent(req, BadValue);
304
305    req->win = CLIENT_WINDOW_ID;
306    request_XISelectEvent(req, BadValue);
307
308    printf("Testing for BadWindow.\n");
309    /* None window is BadWindow, regardless of the masks.
310     * We don't actually need to set the masks here, BadWindow must occur
311     * before checking the masks.
312     */
313    req->win = None;
314    req->num_masks = 1;
315    request_XISelectEvent(req, BadWindow);
316
317    req->num_masks = 2;
318    request_XISelectEvent(req, BadWindow);
319
320    req->num_masks = 0xFF;
321    request_XISelectEvent(req, BadWindow);
322
323    /* request size is 3, so 0xFFFC is the highest num_mask that doesn't
324     * overflow req->length */
325    req->num_masks = 0xFFFC;
326    request_XISelectEvent(req, BadWindow);
327
328    printf("Triggering num_masks/length overflow\n");
329    req->win = ROOT_WINDOW_ID;
330    /* Integer overflow - req->length can't hold that much */
331    req->num_masks = 0xFFFF;
332    request_XISelectEvent(req, BadLength);
333
334    req->win = ROOT_WINDOW_ID;
335    req->num_masks = 1;
336
337    printf("Triggering bogus mask length error\n");
338    mask = (xXIEventMask *) &req[1];
339    mask->deviceid = 0;
340    mask->mask_len = 0xFFFF;
341    request_XISelectEvent(req, BadLength);
342
343    /* testing various device ids */
344    printf("Testing existing device ids.\n");
345    for (i = 0; i < 6; i++) {
346        mask = (xXIEventMask *) &req[1];
347        mask->deviceid = i;
348        mask->mask_len = 1;
349        req->win = ROOT_WINDOW_ID;
350        req->num_masks = 1;
351        request_XISelectEvent(req, Success);
352    }
353
354    printf("Testing non-existing device ids.\n");
355    for (i = 6; i <= 0xFFFF; i++) {
356        req->win = ROOT_WINDOW_ID;
357        req->num_masks = 1;
358        mask = (xXIEventMask *) &req[1];
359        mask->deviceid = i;
360        mask->mask_len = 1;
361        request_XISelectEvent(req, BadDevice);
362    }
363
364    request_XISelectEvents_masks(req);
365}
366
367int
368protocol_xiselectevents_test(void)
369{
370    init_simple();
371
372    test_XISelectEvents();
373
374    return 0;
375}
376