summaryrefslogtreecommitdiff
path: root/source/x/x11/patch/xorg-server/0002-dd8caf39e9e15d8f302e54045dd08d8ebf1025dc.patch
blob: 72d30f36b6769bd4e12bc55d5c1273e7d30393f7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
From dd8caf39e9e15d8f302e54045dd08d8ebf1025dc Mon Sep 17 00:00:00 2001
From: Peter Hutterer <peter.hutterer@who-t.net>
Date: Tue, 5 Jul 2022 09:50:41 +1000
Subject: [PATCH] xkb: swap XkbSetDeviceInfo and XkbSetDeviceInfoCheck

XKB often uses a FooCheck and Foo function pair, the former is supposed
to check all values in the request and error out on BadLength,
BadValue, etc. The latter is then called once we're confident the values
are good (they may still fail on an individual device, but that's a
different topic).

In the case of XkbSetDeviceInfo, those functions were incorrectly
named, with XkbSetDeviceInfo ending up as the checker function and
XkbSetDeviceInfoCheck as the setter function. As a result, the setter
function was called before the checker function, accessing request
data and modifying device state before we ensured that the data is
valid.

In particular, the setter function relied on values being already
byte-swapped. This in turn could lead to potential OOB memory access.

Fix this by correctly naming the functions and moving the length checks
over to the checker function. These were added in 87c64fc5b0 to the
wrong function, probably due to the incorrect naming.

Fixes ZDI-CAN 16070, CVE-2022-2320.

This vulnerability was discovered by:
Jan-Niklas Sohn working with Trend Micro Zero Day Initiative

Introduced in c06e27b2f6fd9f7b9f827623a48876a225264132

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
---
 xkb/xkb.c | 46 +++++++++++++++++++++++++---------------------
 1 file changed, 25 insertions(+), 21 deletions(-)

diff --git a/xkb/xkb.c b/xkb/xkb.c
index 64e52611e..34b2c290b 100644
--- a/xkb/xkb.c
+++ b/xkb/xkb.c
@@ -6550,7 +6550,8 @@ ProcXkbGetDeviceInfo(ClientPtr client)
 static char *
 CheckSetDeviceIndicators(char *wire,
                          DeviceIntPtr dev,
-                         int num, int *status_rtrn, ClientPtr client)
+                         int num, int *status_rtrn, ClientPtr client,
+                         xkbSetDeviceInfoReq * stuff)
 {
     xkbDeviceLedsWireDesc *ledWire;
     int i;
@@ -6558,6 +6559,11 @@ CheckSetDeviceIndicators(char *wire,
 
     ledWire = (xkbDeviceLedsWireDesc *) wire;
     for (i = 0; i < num; i++) {
+        if (!_XkbCheckRequestBounds(client, stuff, ledWire, ledWire + 1)) {
+            *status_rtrn = BadLength;
+            return (char *) ledWire;
+        }
+
         if (client->swapped) {
             swaps(&ledWire->ledClass);
             swaps(&ledWire->ledID);
@@ -6585,6 +6591,11 @@ CheckSetDeviceIndicators(char *wire,
             atomWire = (CARD32 *) &ledWire[1];
             if (nNames > 0) {
                 for (n = 0; n < nNames; n++) {
+                    if (!_XkbCheckRequestBounds(client, stuff, atomWire, atomWire + 1)) {
+                        *status_rtrn = BadLength;
+                        return (char *) atomWire;
+                    }
+
                     if (client->swapped) {
                         swapl(atomWire);
                     }
@@ -6596,6 +6607,10 @@ CheckSetDeviceIndicators(char *wire,
             mapWire = (xkbIndicatorMapWireDesc *) atomWire;
             if (nMaps > 0) {
                 for (n = 0; n < nMaps; n++) {
+                    if (!_XkbCheckRequestBounds(client, stuff, mapWire, mapWire + 1)) {
+                        *status_rtrn = BadLength;
+                        return (char *) mapWire;
+                    }
                     if (client->swapped) {
                         swaps(&mapWire->virtualMods);
                         swapl(&mapWire->ctrls);
@@ -6647,11 +6662,6 @@ SetDeviceIndicators(char *wire,
         xkbIndicatorMapWireDesc *mapWire;
         XkbSrvLedInfoPtr sli;
 
-        if (!_XkbCheckRequestBounds(client, stuff, ledWire, ledWire + 1)) {
-            *status_rtrn = BadLength;
-            return (char *) ledWire;
-        }
-
         namec = mapc = statec = 0;
         sli = XkbFindSrvLedInfo(dev, ledWire->ledClass, ledWire->ledID,
                                 XkbXI_IndicatorMapsMask);
@@ -6670,10 +6680,6 @@ SetDeviceIndicators(char *wire,
             memset((char *) sli->names, 0, XkbNumIndicators * sizeof(Atom));
             for (n = 0, bit = 1; n < XkbNumIndicators; n++, bit <<= 1) {
                 if (ledWire->namesPresent & bit) {
-                    if (!_XkbCheckRequestBounds(client, stuff, atomWire, atomWire + 1)) {
-                        *status_rtrn = BadLength;
-                        return (char *) atomWire;
-                    }
                     sli->names[n] = (Atom) *atomWire;
                     if (sli->names[n] == None)
                         ledWire->namesPresent &= ~bit;
@@ -6691,10 +6697,6 @@ SetDeviceIndicators(char *wire,
         if (ledWire->mapsPresent) {
             for (n = 0, bit = 1; n < XkbNumIndicators; n++, bit <<= 1) {
                 if (ledWire->mapsPresent & bit) {
-                    if (!_XkbCheckRequestBounds(client, stuff, mapWire, mapWire + 1)) {
-                        *status_rtrn = BadLength;
-                        return (char *) mapWire;
-                    }
                     sli->maps[n].flags = mapWire->flags;
                     sli->maps[n].which_groups = mapWire->whichGroups;
                     sli->maps[n].groups = mapWire->groups;
@@ -6730,13 +6732,17 @@ SetDeviceIndicators(char *wire,
 }
 
 static int
-_XkbSetDeviceInfo(ClientPtr client, DeviceIntPtr dev,
+_XkbSetDeviceInfoCheck(ClientPtr client, DeviceIntPtr dev,
                   xkbSetDeviceInfoReq * stuff)
 {
     char *wire;
 
     wire = (char *) &stuff[1];
     if (stuff->change & XkbXI_ButtonActionsMask) {
+        int sz = stuff->nBtns * SIZEOF(xkbActionWireDesc);
+        if (!_XkbCheckRequestBounds(client, stuff, wire, (char *) wire + sz))
+            return BadLength;
+
         if (!dev->button) {
             client->errorValue = _XkbErrCode2(XkbErr_BadClass, ButtonClass);
             return XkbKeyboardErrorCode;
@@ -6747,13 +6753,13 @@ _XkbSetDeviceInfo(ClientPtr client, DeviceIntPtr dev,
                              dev->button->numButtons);
             return BadMatch;
         }
-        wire += (stuff->nBtns * SIZEOF(xkbActionWireDesc));
+        wire += sz;
     }
     if (stuff->change & XkbXI_IndicatorsMask) {
         int status = Success;
 
         wire = CheckSetDeviceIndicators(wire, dev, stuff->nDeviceLedFBs,
-                                        &status, client);
+                                        &status, client, stuff);
         if (status != Success)
             return status;
     }
@@ -6764,8 +6770,8 @@ _XkbSetDeviceInfo(ClientPtr client, DeviceIntPtr dev,
 }
 
 static int
-_XkbSetDeviceInfoCheck(ClientPtr client, DeviceIntPtr dev,
-                       xkbSetDeviceInfoReq * stuff)
+_XkbSetDeviceInfo(ClientPtr client, DeviceIntPtr dev,
+                  xkbSetDeviceInfoReq * stuff)
 {
     char *wire;
     xkbExtensionDeviceNotify ed;
@@ -6789,8 +6795,6 @@ _XkbSetDeviceInfoCheck(ClientPtr client, DeviceIntPtr dev,
         if (stuff->firstBtn + stuff->nBtns > nBtns)
             return BadValue;
         sz = stuff->nBtns * SIZEOF(xkbActionWireDesc);
-        if (!_XkbCheckRequestBounds(client, stuff, wire, (char *) wire + sz))
-            return BadLength;
         memcpy((char *) &acts[stuff->firstBtn], (char *) wire, sz);
         wire += sz;
         ed.reason |= XkbXI_ButtonActionsMask;
-- 
GitLab