diff options
Diffstat (limited to 'xorg-server/test/xi2/protocol-xiselectevents.c')
-rw-r--r-- | xorg-server/test/xi2/protocol-xiselectevents.c | 337 |
1 files changed, 337 insertions, 0 deletions
diff --git a/xorg-server/test/xi2/protocol-xiselectevents.c b/xorg-server/test/xi2/protocol-xiselectevents.c new file mode 100644 index 000000000..f314462b5 --- /dev/null +++ b/xorg-server/test/xi2/protocol-xiselectevents.c @@ -0,0 +1,337 @@ +/** + * Copyright © 2009 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +/* + * Protocol testing for XISelectEvents request. + * + * Test approach: + * + * Wrap XISetEventMask to intercept when the server tries to apply the event + * mask. Ensure that the mask passed in is equivalent to the one supplied by + * the client. Ensure that invalid devices and invalid masks return errors + * as appropriate. + * + * Tests included: + * BadValue for num_masks < 0 + * BadWindow for invalid windows + * BadDevice for non-existing devices + * BadImplemenation for devices >= 0xFF + * BadValue if HierarchyChanged bit is set for devices other than + * XIAllDevices + * BadValue for invalid mask bits + * Sucecss for excessive mask lengths + * + */ + +#include <stdint.h> +#include <X11/X.h> +#include <X11/Xproto.h> +#include <X11/extensions/XI2proto.h> +#include "inputstr.h" +#include "windowstr.h" +#include "extinit.h" /* for XInputExtensionInit */ +#include "scrnintstr.h" +#include "xiselectev.h" + +#include "protocol-common.h" +#include <glib.h> + +static unsigned char *data[4096 * 16]; /* the request data buffer */ + +int __wrap_XISetEventMask(DeviceIntPtr dev, WindowPtr win, int len, unsigned char* mask) +{ + return Success; +} + +/* dixLookupWindow requires a lot of setup not necessary for this test. + * Simple wrapper that returns either one of the fake root window or the + * fake client window. If the requested ID is neither of those wanted, + * return whatever the real dixLookupWindow does. + */ +int __wrap_dixLookupWindow(WindowPtr *win, XID id, ClientPtr client, Mask access) +{ + if (id == root.drawable.id) + { + *win = &root; + return Success; + } else if (id == window.drawable.id) + { + *win = &window; + return Success; + } + + return __real_dixLookupWindow(win, id, client, access); +} + + +static void request_XISelectEvent(xXISelectEventsReq *req, int error) +{ + char n; + int i; + int rc; + ClientRec client; + xXIEventMask *mask, *next; + + req->length = (sz_xXISelectEventsReq/4); + mask = (xXIEventMask*)&req[1]; + for (i = 0; i < req->num_masks; i++) + { + req->length += sizeof(xXIEventMask)/4 + mask->mask_len; + mask = (xXIEventMask*)((char*)&mask[1] + mask->mask_len * 4); + } + + client = init_client(req->length, req); + + rc = ProcXISelectEvents(&client); + g_assert(rc == error); + + client.swapped = TRUE; + + mask = (xXIEventMask*)&req[1]; + for (i = 0; i < req->num_masks; i++) + { + next = (xXIEventMask*)((char*)&mask[1] + mask->mask_len * 4); + swaps(&mask->deviceid, n); + swaps(&mask->mask_len, n); + mask = next; + } + + swapl(&req->win, n); + swaps(&req->length, n); + swaps(&req->num_masks, n); + rc = SProcXISelectEvents(&client); + g_assert(rc == error); +} + +static void request_XISelectEvents_masks(xXISelectEventsReq *req) +{ + int i, j; + xXIEventMask *mask; + int nmasks = (XI_LASTEVENT + 7)/8; + unsigned char *bits; + + mask = (xXIEventMask*)&req[1]; + req->win = ROOT_WINDOW_ID; + + /* if a clients submits more than 100 masks, consider it insane and untested */ + for (i = 1; i <= 1000; i++) + { + req->num_masks = i; + mask->deviceid = XIAllDevices; + + /* Test 0: + * mask_len is 0 -> Success + */ + mask->mask_len = 0; + request_XISelectEvent(req, Success); + + /* Test 1: + * mask may be larger than needed for XI_LASTEVENT. + * Test setting each valid mask bit, while leaving unneeded bits 0. + * -> Success + */ + bits = (unsigned char*)&mask[1]; + mask->mask_len = (nmasks + 3)/4 * 10; + memset(bits, 0, mask->mask_len * 4); + for (j = 0; j <= XI_LASTEVENT; j++) + { + SetBit(bits, j); + request_XISelectEvent(req, Success); + ClearBit(bits, j); + } + + /* Test 2: + * mask may be larger than needed for XI_LASTEVENT. + * Test setting all valid mask bits, while leaving unneeded bits 0. + * -> Success + */ + bits = (unsigned char*)&mask[1]; + mask->mask_len = (nmasks + 3)/4 * 10; + memset(bits, 0, mask->mask_len * 4); + + for (j = 0; j <= XI_LASTEVENT; j++) + { + SetBit(bits, j); + request_XISelectEvent(req, Success); + } + + /* Test 3: + * mask is larger than needed for XI_LASTEVENT. If any unneeded bit + * is set -> BadValue + */ + bits = (unsigned char*)&mask[1]; + mask->mask_len = (nmasks + 3)/4 * 10; + memset(bits, 0, mask->mask_len * 4); + + for (j = XI_LASTEVENT + 1; j < mask->mask_len * 4; j++) + { + SetBit(bits, j); + request_XISelectEvent(req, BadValue); + ClearBit(bits, j); + } + + /* Test 4: + * Mask len is a sensible length, only valid bits are set -> Success + */ + bits = (unsigned char*)&mask[1]; + mask->mask_len = (nmasks + 3)/4; + memset(bits, 0, mask->mask_len * 4); + for (j = 0; j <= XI_LASTEVENT; j++) + { + SetBit(bits, j); + request_XISelectEvent(req, Success); + } + + /* Test 5: + * HierarchyChanged bit is BadValue for devices other than + * XIAllDevices + */ + bits = (unsigned char*)&mask[1]; + mask->mask_len = (nmasks + 3)/4; + memset(bits, 0, mask->mask_len * 4); + SetBit(bits, XI_HierarchyChanged); + mask->deviceid = XIAllDevices; + request_XISelectEvent(req, Success); + for (j = 1; j < devices.num_devices; j++) + { + mask->deviceid = j; + request_XISelectEvent(req, BadValue); + } + + /* Test 6: + * All bits set minus hierarchy changed bit -> Success + */ + bits = (unsigned char*)&mask[1]; + mask->mask_len = (nmasks + 3)/4; + memset(bits, 0, mask->mask_len * 4); + for (j = 0; j <= XI_LASTEVENT; j++) + SetBit(bits, j); + ClearBit(bits, XI_HierarchyChanged); + for (j = 1; j < 6; j++) + { + mask->deviceid = j; + request_XISelectEvent(req, Success); + } + + mask = (xXIEventMask*)((char*)mask + sizeof(xXIEventMask) + mask->mask_len * 4); + } +} + +static void test_XISelectEvents(void) +{ + int i; + xXIEventMask *mask; + xXISelectEventsReq *req; + req = (xXISelectEventsReq*)data; + + request_init(req, XISelectEvents); + + g_test_message("Testing for BadValue on zero-length masks"); + /* zero masks are BadValue, regardless of the window */ + req->num_masks = 0; + + req->win = None; + request_XISelectEvent(req, BadValue); + + req->win = ROOT_WINDOW_ID; + request_XISelectEvent(req, BadValue); + + req->win = CLIENT_WINDOW_ID; + request_XISelectEvent(req, BadValue); + + g_test_message("Testing for BadWindow."); + /* None window is BadWindow, regardless of the masks. + * We don't actually need to set the masks here, BadWindow must occur + * before checking the masks. + */ + req->win = None; + req->num_masks = 1; + request_XISelectEvent(req, BadWindow); + + req->num_masks = 2; + request_XISelectEvent(req, BadWindow); + + req->num_masks = 0xFF; + request_XISelectEvent(req, BadWindow); + + /* request size is 3, so 0xFFFC is the highest num_mask that doesn't + * overflow req->length */ + req->num_masks = 0xFFFC; + request_XISelectEvent(req, BadWindow); + + g_test_message("Triggering num_masks/length overflow"); + /* Integer overflow - req->length can't hold that much */ + req->num_masks = 0xFFFF; + request_XISelectEvent(req, BadLength); + + req->win = ROOT_WINDOW_ID; + req->num_masks = 1; + + g_test_message("Triggering bogus mask length error"); + mask = (xXIEventMask*)&req[1]; + mask->deviceid = 0; + mask->mask_len = 0xFFFF; + request_XISelectEvent(req, BadLength); + + /* testing various device ids */ + g_test_message("Testing existing device ids."); + for (i = 0; i < 6; i++) + { + mask = (xXIEventMask*)&req[1]; + mask->deviceid = i; + mask->mask_len = 1; + req->win = ROOT_WINDOW_ID; + req->num_masks = 1; + request_XISelectEvent(req, Success); + } + + g_test_message("Testing non-existing device ids."); + for (i = 6; i <= 0xFFFF; i++) + { + req->win = ROOT_WINDOW_ID; + req->num_masks = 1; + mask = (xXIEventMask*)&req[1]; + mask->deviceid = i; + mask->mask_len = 1; + request_XISelectEvent(req, BadDevice); + } + + request_XISelectEvents_masks(req); +} + +int main(int argc, char** argv) +{ + g_test_init(&argc, &argv,NULL); + g_test_bug_base("https://bugzilla.freedesktop.org/show_bug.cgi?id="); + + init_simple(); + + g_test_add_func("/xi2/protocol/XISelectEvents", test_XISelectEvents); + + return g_test_run(); +} + |