summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Hutterer <peter.hutterer@who-t.net>2024-08-27 11:01:06 +1000
committerPeter Hutterer <peter.hutterer@who-t.net>2024-08-27 11:11:22 +1000
commita5af26c654b4da5fd5eaaeaa2173c734ab9e63ec (patch)
treef0c35866a425fba205ae13ab8e9eb522da308ce8
parentdabce4dbe5eab35076e31fd0a628cbe11b858fa1 (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.c20
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();