diff --git a/test/bigreq/meson.build b/test/bigreq/meson.build new file mode 100644 index 000000000..9462ede31 --- /dev/null +++ b/test/bigreq/meson.build @@ -0,0 +1,8 @@ +xcb_dep = dependency('xcb', required: false) + +if get_option('xvfb') + if xcb_dep.found() + requestlength = executable('request-length', 'request-length.c', dependencies: xcb_dep) + test('request-length', simple_xinit, args: [requestlength, '--', xvfb_server]) + endif +endif diff --git a/test/bigreq/request-length.c b/test/bigreq/request-length.c new file mode 100644 index 000000000..8174813ae --- /dev/null +++ b/test/bigreq/request-length.c @@ -0,0 +1,101 @@ +/* + * Copyright © 2017 Broadcom + * + * 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. + */ + +#include +#include +#include +#include +#include +#include + +int main(int argc, char **argv) +{ + xcb_connection_t *c = xcb_connect(NULL, NULL); + int fd = xcb_get_file_descriptor(c); + + struct { + uint8_t extension; + uint8_t opcode; + uint16_t length; + uint32_t length_bigreq; + uint32_t win; + int num_masks; + uint16_t pad; + } xise_req = { + .extension = 0, + .opcode = XCB_INPUT_XI_SELECT_EVENTS, + /* The server triggers BadValue on a zero num_mask */ + .num_masks = 0, + .win = 0, + + /* This is the value that triggers the bug. */ + .length_bigreq = 0, + }; + + xcb_query_extension_cookie_t cookie; + xcb_query_extension_reply_t *rep; + + cookie = xcb_query_extension(c, 15, "XInputExtension"); + rep = xcb_query_extension_reply(c, cookie, NULL); + xise_req.extension = rep->major_opcode; + + free(xcb_big_requests_enable_reply(c, xcb_big_requests_enable(c), NULL)); + + /* Manually write out the bad request. XCB can't help us here.*/ + write(fd, &xise_req, sizeof(xise_req)); + + /* Block until the server has processed our mess and throws an + * error. If we get disconnected, then the server has noticed what we're + * up to. If we get an error back from the server, it looked at our fake + * request - which shouldn't happen. + */ + struct pollfd pfd = { + .fd = fd, + .events = POLLIN, + }; + poll(&pfd, 1, -1); + + if (pfd.revents & POLLHUP) { + /* We got killed by the server for being naughty. Yay! */ + return 0; + } + + /* We didn't get disconnected, that's bad. If we get a BadValue from our + * request, we at least know that the bug triggered. + * + * If we get anything else back, something else has gone wrong. + */ + xcb_generic_error_t error; + int r = read(fd, &error, sizeof(error)); + + if (r == sizeof(error) && + error.error_code == 2 /* BadValue */ && + error.major_code == xise_req.extension && + error.minor_code == XCB_INPUT_XI_SELECT_EVENTS) + return 1; /* Our request was processed, which shouldn't happen */ + + /* Something else bad happened. We got something back but it's not the + * error we expected. If this happens, it needs to be investigated. */ + + return 2; +} diff --git a/test/meson.build b/test/meson.build index 3e482d6f1..d413e9da5 100644 --- a/test/meson.build +++ b/test/meson.build @@ -23,4 +23,5 @@ if get_option('xvfb') endif endif +subdir('bigreq') subdir('sync')