diff options
author | Peter Hutterer <peter.hutterer@who-t.net> | 2024-08-27 11:01:06 +1000 |
---|---|---|
committer | Peter Hutterer <peter.hutterer@who-t.net> | 2024-08-27 11:11:22 +1000 |
commit | a5af26c654b4da5fd5eaaeaa2173c734ab9e63ec (patch) | |
tree | f0c35866a425fba205ae13ab8e9eb522da308ce8 | |
parent | dabce4dbe5eab35076e31fd0a628cbe11b858fa1 (diff) |
XGetFeedbackControl: skip over unknown feedback controls
If the server sends an unknown feedback control class we would allocate
the amount of *protocol* bytes for the client representation but then
later mess up the actual composition of the classes due to
Feedback->length never being initialized.
So while in theory it looks like this:
|-------------- allocated size -----------------|
[led feedback] [ ?unknown? ] [kbd feedback][....]
with unknown being the size of the class on the protocol,
in practice it looks like this:
|-------------- allocated size -----------------|
[led feedback] [ ?unknown? ] [kbd feedback][...]
with unknown being the size of whatever was in the Feeback->length
pointed to at the time. The content of unknown is never initialized.
Fix this by making unknown classes disappear so the above becomes:
|------- allocated size ---------|
[led feedback][kbd feedback][....]
Closes #16
Part-of: <https://gitlab.freedesktop.org/xorg/lib/libxi/-/merge_requests/18>
-rw-r--r-- | src/XGetFCtl.c | 20 |
1 files changed, 14 insertions, 6 deletions
diff --git a/src/XGetFCtl.c b/src/XGetFCtl.c index 82dcc64..b59ada5 100644 --- a/src/XGetFCtl.c +++ b/src/XGetFCtl.c @@ -67,7 +67,7 @@ XFeedbackState * XGetFeedbackControl( register Display *dpy, XDevice *dev, - int *num_feedbacks) + int *num_feedbacks_out) { XFeedbackState *Feedback = NULL; XFeedbackState *Sav = NULL; @@ -77,6 +77,8 @@ XGetFeedbackControl( xGetFeedbackControlReq *req; xGetFeedbackControlReply rep; XExtDisplayInfo *info = XInput_find_display(dpy); + int num_feedbacks = 0; + int known_feedbacks = 0; LockDisplay(dpy); if (_XiCheckExtInit(dpy, XInput_Initial_Release, info) == -1) @@ -95,7 +97,7 @@ XGetFeedbackControl( size_t size = 0; int i; - *num_feedbacks = rep.num_feedbacks; + num_feedbacks = rep.num_feedbacks; if (rep.length < (INT_MAX >> 2)) { nbytes = rep.length << 2; @@ -109,7 +111,7 @@ XGetFeedbackControl( end = (char *)f + nbytes; _XRead(dpy, (char *)f, nbytes); - for (i = 0; i < *num_feedbacks; i++) { + for (i = 0; i < num_feedbacks; i++) { if ((char *)f + sizeof(*f) > end || f->length == 0 || f->length > nbytes) goto out; @@ -141,7 +143,7 @@ XGetFeedbackControl( size += sizeof(XBellFeedbackState); break; default: - size += f->length; + /* unknown classes are skipped */ break; } if (size > INT_MAX) @@ -154,9 +156,11 @@ XGetFeedbackControl( goto out; Sav = Feedback; + known_feedbacks = num_feedbacks; f = sav; - for (i = 0; i < *num_feedbacks; i++) { + for (i = 0; i < num_feedbacks; i++) { + Bool skip = False; switch (f->class) { case KbdFeedbackClass: { @@ -262,14 +266,18 @@ XGetFeedbackControl( break; } default: + --known_feedbacks; + skip = True; break; } f = (xFeedbackState *) ((char *)f + f->length); - Feedback = (XFeedbackState *) ((char *)Feedback + Feedback->length); + if (!skip) + Feedback = (XFeedbackState *) ((char *)Feedback + Feedback->length); } } out: XFree((char *)sav); + *num_feedbacks_out = known_feedbacks; UnlockDisplay(dpy); SyncHandle(); |