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 "xiselectev.h" 59 60#include "protocol-common.h" 61#include <glib.h> 62 63static unsigned char *data[4096 * 20]; /* the request data buffer */ 64 65int __wrap_XISetEventMask(DeviceIntPtr dev, WindowPtr win, int len, unsigned char* mask) 66{ 67 return Success; 68} 69 70/* dixLookupWindow requires a lot of setup not necessary for this test. 71 * Simple wrapper that returns either one of the fake root window or the 72 * fake client window. If the requested ID is neither of those wanted, 73 * return whatever the real dixLookupWindow does. 74 */ 75int __wrap_dixLookupWindow(WindowPtr *win, XID id, ClientPtr client, Mask access) 76{ 77 if (id == root.drawable.id) 78 { 79 *win = &root; 80 return Success; 81 } else if (id == window.drawable.id) 82 { 83 *win = &window; 84 return Success; 85 } 86 87 return __real_dixLookupWindow(win, id, client, access); 88} 89 90 91static void request_XISelectEvent(xXISelectEventsReq *req, int error) 92{ 93 char n; 94 int i; 95 int rc; 96 ClientRec client; 97 xXIEventMask *mask, *next; 98 99 req->length = (sz_xXISelectEventsReq/4); 100 mask = (xXIEventMask*)&req[1]; 101 for (i = 0; i < req->num_masks; i++) 102 { 103 req->length += sizeof(xXIEventMask)/4 + mask->mask_len; 104 mask = (xXIEventMask*)((char*)&mask[1] + mask->mask_len * 4); 105 } 106 107 client = init_client(req->length, req); 108 109 rc = ProcXISelectEvents(&client); 110 g_assert(rc == error); 111 112 client.swapped = TRUE; 113 114 mask = (xXIEventMask*)&req[1]; 115 for (i = 0; i < req->num_masks; i++) 116 { 117 next = (xXIEventMask*)((char*)&mask[1] + mask->mask_len * 4); 118 swaps(&mask->deviceid, n); 119 swaps(&mask->mask_len, n); 120 mask = next; 121 } 122 123 swapl(&req->win, n); 124 swaps(&req->length, n); 125 swaps(&req->num_masks, n); 126 rc = SProcXISelectEvents(&client); 127 g_assert(rc == error); 128} 129 130static void request_XISelectEvents_masks(xXISelectEventsReq *req) 131{ 132 int i, j; 133 xXIEventMask *mask; 134 int nmasks = (XI2LASTEVENT + 7)/8; 135 unsigned char *bits; 136 137 mask = (xXIEventMask*)&req[1]; 138 req->win = ROOT_WINDOW_ID; 139 140 /* if a clients submits more than 100 masks, consider it insane and untested */ 141 for (i = 1; i <= 1000; i++) 142 { 143 req->num_masks = i; 144 mask->deviceid = XIAllDevices; 145 146 /* Test 0: 147 * mask_len is 0 -> Success 148 */ 149 mask->mask_len = 0; 150 request_XISelectEvent(req, Success); 151 152 /* Test 1: 153 * mask may be larger than needed for XI2LASTEVENT. 154 * Test setting each valid mask bit, while leaving unneeded bits 0. 155 * -> Success 156 */ 157 bits = (unsigned char*)&mask[1]; 158 mask->mask_len = (nmasks + 3)/4 * 10; 159 memset(bits, 0, mask->mask_len * 4); 160 for (j = 0; j <= XI2LASTEVENT; j++) 161 { 162 SetBit(bits, j); 163 request_XISelectEvent(req, Success); 164 ClearBit(bits, j); 165 } 166 167 /* Test 2: 168 * mask may be larger than needed for XI2LASTEVENT. 169 * Test setting all valid mask bits, while leaving unneeded bits 0. 170 * -> Success 171 */ 172 bits = (unsigned char*)&mask[1]; 173 mask->mask_len = (nmasks + 3)/4 * 10; 174 memset(bits, 0, mask->mask_len * 4); 175 176 for (j = 0; j <= XI2LASTEVENT; j++) 177 { 178 SetBit(bits, j); 179 request_XISelectEvent(req, Success); 180 } 181 182 /* Test 3: 183 * mask is larger than needed for XI2LASTEVENT. If any unneeded bit 184 * is set -> BadValue 185 */ 186 bits = (unsigned char*)&mask[1]; 187 mask->mask_len = (nmasks + 3)/4 * 10; 188 memset(bits, 0, mask->mask_len * 4); 189 190 for (j = XI2LASTEVENT + 1; j < mask->mask_len * 4; j++) 191 { 192 SetBit(bits, j); 193 request_XISelectEvent(req, BadValue); 194 ClearBit(bits, j); 195 } 196 197 /* Test 4: 198 * Mask len is a sensible length, only valid bits are set -> Success 199 */ 200 bits = (unsigned char*)&mask[1]; 201 mask->mask_len = (nmasks + 3)/4; 202 memset(bits, 0, mask->mask_len * 4); 203 for (j = 0; j <= XI2LASTEVENT; j++) 204 { 205 SetBit(bits, j); 206 request_XISelectEvent(req, Success); 207 } 208 209 /* Test 5: 210 * HierarchyChanged bit is BadValue for devices other than 211 * XIAllDevices 212 */ 213 bits = (unsigned char*)&mask[1]; 214 mask->mask_len = (nmasks + 3)/4; 215 memset(bits, 0, mask->mask_len * 4); 216 SetBit(bits, XI_HierarchyChanged); 217 mask->deviceid = XIAllDevices; 218 request_XISelectEvent(req, Success); 219 for (j = 1; j < devices.num_devices; j++) 220 { 221 mask->deviceid = j; 222 request_XISelectEvent(req, BadValue); 223 } 224 225 /* Test 6: 226 * All bits set minus hierarchy changed bit -> Success 227 */ 228 bits = (unsigned char*)&mask[1]; 229 mask->mask_len = (nmasks + 3)/4; 230 memset(bits, 0, mask->mask_len * 4); 231 for (j = 0; j <= XI2LASTEVENT; j++) 232 SetBit(bits, j); 233 ClearBit(bits, XI_HierarchyChanged); 234 for (j = 1; j < 6; j++) 235 { 236 mask->deviceid = j; 237 request_XISelectEvent(req, Success); 238 } 239 240 mask = (xXIEventMask*)((char*)mask + sizeof(xXIEventMask) + mask->mask_len * 4); 241 } 242} 243 244static void test_XISelectEvents(void) 245{ 246 int i; 247 xXIEventMask *mask; 248 xXISelectEventsReq *req; 249 req = (xXISelectEventsReq*)data; 250 251 request_init(req, XISelectEvents); 252 253 g_test_message("Testing for BadValue on zero-length masks"); 254 /* zero masks are BadValue, regardless of the window */ 255 req->num_masks = 0; 256 257 req->win = None; 258 request_XISelectEvent(req, BadValue); 259 260 req->win = ROOT_WINDOW_ID; 261 request_XISelectEvent(req, BadValue); 262 263 req->win = CLIENT_WINDOW_ID; 264 request_XISelectEvent(req, BadValue); 265 266 g_test_message("Testing for BadWindow."); 267 /* None window is BadWindow, regardless of the masks. 268 * We don't actually need to set the masks here, BadWindow must occur 269 * before checking the masks. 270 */ 271 req->win = None; 272 req->num_masks = 1; 273 request_XISelectEvent(req, BadWindow); 274 275 req->num_masks = 2; 276 request_XISelectEvent(req, BadWindow); 277 278 req->num_masks = 0xFF; 279 request_XISelectEvent(req, BadWindow); 280 281 /* request size is 3, so 0xFFFC is the highest num_mask that doesn't 282 * overflow req->length */ 283 req->num_masks = 0xFFFC; 284 request_XISelectEvent(req, BadWindow); 285 286 g_test_message("Triggering num_masks/length overflow"); 287 req->win = ROOT_WINDOW_ID; 288 /* Integer overflow - req->length can't hold that much */ 289 req->num_masks = 0xFFFF; 290 request_XISelectEvent(req, BadLength); 291 292 req->win = ROOT_WINDOW_ID; 293 req->num_masks = 1; 294 295 g_test_message("Triggering bogus mask length error"); 296 mask = (xXIEventMask*)&req[1]; 297 mask->deviceid = 0; 298 mask->mask_len = 0xFFFF; 299 request_XISelectEvent(req, BadLength); 300 301 /* testing various device ids */ 302 g_test_message("Testing existing device ids."); 303 for (i = 0; i < 6; i++) 304 { 305 mask = (xXIEventMask*)&req[1]; 306 mask->deviceid = i; 307 mask->mask_len = 1; 308 req->win = ROOT_WINDOW_ID; 309 req->num_masks = 1; 310 request_XISelectEvent(req, Success); 311 } 312 313 g_test_message("Testing non-existing device ids."); 314 for (i = 6; i <= 0xFFFF; i++) 315 { 316 req->win = ROOT_WINDOW_ID; 317 req->num_masks = 1; 318 mask = (xXIEventMask*)&req[1]; 319 mask->deviceid = i; 320 mask->mask_len = 1; 321 request_XISelectEvent(req, BadDevice); 322 } 323 324 request_XISelectEvents_masks(req); 325} 326 327int main(int argc, char** argv) 328{ 329 g_test_init(&argc, &argv,NULL); 330 g_test_bug_base("https://bugzilla.freedesktop.org/show_bug.cgi?id="); 331 332 init_simple(); 333 334 g_test_add_func("/xi2/protocol/XISelectEvents", test_XISelectEvents); 335 336 return g_test_run(); 337} 338 339