File: | Xi/listdev.c |
Location: | line 128, column 9 |
Description: | String copy function overflows destination buffer |
1 | /************************************************************ | |||||
2 | ||||||
3 | Copyright 1989, 1998 The Open Group | |||||
4 | ||||||
5 | Permission to use, copy, modify, distribute, and sell this software and its | |||||
6 | documentation for any purpose is hereby granted without fee, provided that | |||||
7 | the above copyright notice appear in all copies and that both that | |||||
8 | copyright notice and this permission notice appear in supporting | |||||
9 | documentation. | |||||
10 | ||||||
11 | The above copyright notice and this permission notice shall be included in | |||||
12 | all copies or substantial portions of the Software. | |||||
13 | ||||||
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||||
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||||
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||||
17 | OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN | |||||
18 | AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |||||
19 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |||||
20 | ||||||
21 | Except as contained in this notice, the name of The Open Group shall not be | |||||
22 | used in advertising or otherwise to promote the sale, use or other dealings | |||||
23 | in this Software without prior written authorization from The Open Group. | |||||
24 | ||||||
25 | Copyright 1989 by Hewlett-Packard Company, Palo Alto, California. | |||||
26 | ||||||
27 | All Rights Reserved | |||||
28 | ||||||
29 | Permission to use, copy, modify, and distribute this software and its | |||||
30 | documentation for any purpose and without fee is hereby granted, | |||||
31 | provided that the above copyright notice appear in all copies and that | |||||
32 | both that copyright notice and this permission notice appear in | |||||
33 | supporting documentation, and that the name of Hewlett-Packard not be | |||||
34 | used in advertising or publicity pertaining to distribution of the | |||||
35 | software without specific, written prior permission. | |||||
36 | ||||||
37 | HEWLETT-PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING | |||||
38 | ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL | |||||
39 | HEWLETT-PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR | |||||
40 | ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, | |||||
41 | WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, | |||||
42 | ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS | |||||
43 | SOFTWARE. | |||||
44 | ||||||
45 | ********************************************************/ | |||||
46 | ||||||
47 | /*********************************************************************** | |||||
48 | * | |||||
49 | * Extension function to list the available input devices. | |||||
50 | * | |||||
51 | */ | |||||
52 | ||||||
53 | #ifdef HAVE_DIX_CONFIG_H1 | |||||
54 | #include <dix-config.h> | |||||
55 | #endif | |||||
56 | ||||||
57 | #include <X11/X.h> /* for inputstr.h */ | |||||
58 | #include <X11/Xproto.h> /* Request macro */ | |||||
59 | #include "inputstr.h" /* DeviceIntPtr */ | |||||
60 | #include <X11/extensions/XI.h> | |||||
61 | #include <X11/extensions/XIproto.h> | |||||
62 | #include "XIstubs.h" | |||||
63 | #include "extnsionst.h" | |||||
64 | #include "exevents.h" | |||||
65 | #include "xace.h" | |||||
66 | #include "xkbsrv.h" | |||||
67 | #include "xkbstr.h" | |||||
68 | ||||||
69 | #include "listdev.h" | |||||
70 | ||||||
71 | /*********************************************************************** | |||||
72 | * | |||||
73 | * This procedure lists the input devices available to the server. | |||||
74 | * | |||||
75 | */ | |||||
76 | ||||||
77 | int | |||||
78 | SProcXListInputDevices(ClientPtr client) | |||||
79 | { | |||||
80 | REQUEST(xListInputDevicesReq)xListInputDevicesReq *stuff = (xListInputDevicesReq *)client-> requestBuffer; | |||||
81 | swaps(&stuff->length)do { if (sizeof(*(&stuff->length)) != 2) wrong_size(); if (__builtin_constant_p((uintptr_t)(&stuff->length) & 1) && ((uintptr_t)(&stuff->length) & 1) == 0) *(&stuff->length) = lswaps(*(&stuff->length )); else swap_uint16((uint16_t *)(&stuff->length)); } while (0); | |||||
82 | return (ProcXListInputDevices(client)); | |||||
| ||||||
83 | } | |||||
84 | ||||||
85 | /*********************************************************************** | |||||
86 | * | |||||
87 | * This procedure calculates the size of the information to be returned | |||||
88 | * for an input device. | |||||
89 | * | |||||
90 | */ | |||||
91 | ||||||
92 | static void | |||||
93 | SizeDeviceInfo(DeviceIntPtr d, int *namesize, int *size) | |||||
94 | { | |||||
95 | int chunks; | |||||
96 | ||||||
97 | *namesize += 1; | |||||
98 | if (d->name) | |||||
99 | *namesize += strlen(d->name); | |||||
100 | if (d->key != NULL((void*)0)) | |||||
101 | *size += sizeof(xKeyInfo); | |||||
102 | if (d->button != NULL((void*)0)) | |||||
103 | *size += sizeof(xButtonInfo); | |||||
104 | if (d->valuator != NULL((void*)0)) { | |||||
105 | chunks = ((int) d->valuator->numAxes + 19) / VPC20; | |||||
106 | *size += (chunks * sizeof(xValuatorInfo) + | |||||
107 | d->valuator->numAxes * sizeof(xAxisInfo)); | |||||
108 | } | |||||
109 | } | |||||
110 | ||||||
111 | /*********************************************************************** | |||||
112 | * | |||||
113 | * This procedure copies data to the DeviceInfo struct, swapping if necessary. | |||||
114 | * | |||||
115 | * We need the extra byte in the allocated buffer, because the trailing null | |||||
116 | * hammers one extra byte, which is overwritten by the next name except for | |||||
117 | * the last name copied. | |||||
118 | * | |||||
119 | */ | |||||
120 | ||||||
121 | static void | |||||
122 | CopyDeviceName(char **namebuf, const char *name) | |||||
123 | { | |||||
124 | char *nameptr = *namebuf; | |||||
125 | ||||||
126 | if (name) { | |||||
127 | *nameptr++ = strlen(name); | |||||
128 | strcpy(nameptr, name)__builtin___strcpy_chk (nameptr, name, __builtin_object_size ( nameptr, 2 > 1 ? 1 : 0)); | |||||
| ||||||
129 | *namebuf += (strlen(name) + 1); | |||||
130 | } | |||||
131 | else { | |||||
132 | *nameptr++ = 0; | |||||
133 | *namebuf += 1; | |||||
134 | } | |||||
135 | } | |||||
136 | ||||||
137 | /*********************************************************************** | |||||
138 | * | |||||
139 | * This procedure copies ButtonClass information, swapping if necessary. | |||||
140 | * | |||||
141 | */ | |||||
142 | ||||||
143 | static void | |||||
144 | CopySwapButtonClass(ClientPtr client, ButtonClassPtr b, char **buf) | |||||
145 | { | |||||
146 | xButtonInfoPtr b2; | |||||
147 | ||||||
148 | b2 = (xButtonInfoPtr) * buf; | |||||
149 | b2->class = ButtonClass1; | |||||
150 | b2->length = sizeof(xButtonInfo); | |||||
151 | b2->num_buttons = b->numButtons; | |||||
152 | if (client && client->swapped) { | |||||
153 | swaps(&b2->num_buttons)do { if (sizeof(*(&b2->num_buttons)) != 2) wrong_size( ); if (__builtin_constant_p((uintptr_t)(&b2->num_buttons ) & 1) && ((uintptr_t)(&b2->num_buttons) & 1) == 0) *(&b2->num_buttons) = lswaps(*(&b2->num_buttons )); else swap_uint16((uint16_t *)(&b2->num_buttons)); } while (0); | |||||
154 | } | |||||
155 | *buf += sizeof(xButtonInfo); | |||||
156 | } | |||||
157 | ||||||
158 | /*********************************************************************** | |||||
159 | * | |||||
160 | * This procedure copies data to the DeviceInfo struct, swapping if necessary. | |||||
161 | * | |||||
162 | */ | |||||
163 | ||||||
164 | static void | |||||
165 | CopySwapDevice(ClientPtr client, DeviceIntPtr d, int num_classes, char **buf) | |||||
166 | { | |||||
167 | xDeviceInfoPtr dev; | |||||
168 | ||||||
169 | dev = (xDeviceInfoPtr) * buf; | |||||
170 | ||||||
171 | dev->id = d->id; | |||||
172 | dev->type = d->xinput_type; | |||||
173 | dev->num_classes = num_classes; | |||||
174 | if (IsMaster(d) && IsKeyboardDevice(d)) | |||||
175 | dev->use = IsXKeyboard1; | |||||
176 | else if (IsMaster(d) && IsPointerDevice(d)) | |||||
177 | dev->use = IsXPointer0; | |||||
178 | else if (d->valuator && d->button) | |||||
179 | dev->use = IsXExtensionPointer4; | |||||
180 | else if (d->key && d->kbdfeed) | |||||
181 | dev->use = IsXExtensionKeyboard3; | |||||
182 | else | |||||
183 | dev->use = IsXExtensionDevice2; | |||||
184 | ||||||
185 | if (client->swapped) { | |||||
186 | swapl(&dev->type)do { if (sizeof(*(&dev->type)) != 4) wrong_size(); if ( __builtin_constant_p((uintptr_t)(&dev->type) & 3) && ((uintptr_t)(&dev->type) & 3) == 0) *(&dev-> type) = lswapl(*(&dev->type)); else swap_uint32((uint32_t *)(&dev->type)); } while (0); | |||||
187 | } | |||||
188 | *buf += sizeof(xDeviceInfo); | |||||
189 | } | |||||
190 | ||||||
191 | /*********************************************************************** | |||||
192 | * | |||||
193 | * This procedure copies KeyClass information, swapping if necessary. | |||||
194 | * | |||||
195 | */ | |||||
196 | ||||||
197 | static void | |||||
198 | CopySwapKeyClass(ClientPtr client, KeyClassPtr k, char **buf) | |||||
199 | { | |||||
200 | xKeyInfoPtr k2; | |||||
201 | ||||||
202 | k2 = (xKeyInfoPtr) * buf; | |||||
203 | k2->class = KeyClass0; | |||||
204 | k2->length = sizeof(xKeyInfo); | |||||
205 | k2->min_keycode = k->xkbInfo->desc->min_key_code; | |||||
206 | k2->max_keycode = k->xkbInfo->desc->max_key_code; | |||||
207 | k2->num_keys = k2->max_keycode - k2->min_keycode + 1; | |||||
208 | if (client && client->swapped) { | |||||
209 | swaps(&k2->num_keys)do { if (sizeof(*(&k2->num_keys)) != 2) wrong_size(); if (__builtin_constant_p((uintptr_t)(&k2->num_keys) & 1) && ((uintptr_t)(&k2->num_keys) & 1) == 0) *(&k2->num_keys) = lswaps(*(&k2->num_keys)) ; else swap_uint16((uint16_t *)(&k2->num_keys)); } while (0); | |||||
210 | } | |||||
211 | *buf += sizeof(xKeyInfo); | |||||
212 | } | |||||
213 | ||||||
214 | /*********************************************************************** | |||||
215 | * | |||||
216 | * This procedure copies ValuatorClass information, swapping if necessary. | |||||
217 | * | |||||
218 | * Devices may have up to 255 valuators. The length of a ValuatorClass is | |||||
219 | * defined to be sizeof(ValuatorClassInfo) + num_axes * sizeof (xAxisInfo). | |||||
220 | * The maximum length is therefore (8 + 255 * 12) = 3068. However, the | |||||
221 | * length field is one byte. If a device has more than 20 valuators, we | |||||
222 | * must therefore return multiple valuator classes to the client. | |||||
223 | * | |||||
224 | */ | |||||
225 | ||||||
226 | static int | |||||
227 | CopySwapValuatorClass(ClientPtr client, DeviceIntPtr dev, char **buf) | |||||
228 | { | |||||
229 | int i, j, axes, t_axes; | |||||
230 | ValuatorClassPtr v = dev->valuator; | |||||
231 | xValuatorInfoPtr v2; | |||||
232 | AxisInfo *a; | |||||
233 | xAxisInfoPtr a2; | |||||
234 | ||||||
235 | for (i = 0, axes = v->numAxes; i < ((v->numAxes + 19) / VPC20); | |||||
236 | i++, axes -= VPC20) { | |||||
237 | t_axes = axes < VPC20 ? axes : VPC20; | |||||
238 | if (t_axes < 0) | |||||
239 | t_axes = v->numAxes % VPC20; | |||||
240 | v2 = (xValuatorInfoPtr) * buf; | |||||
241 | v2->class = ValuatorClass2; | |||||
242 | v2->length = sizeof(xValuatorInfo) + t_axes * sizeof(xAxisInfo); | |||||
243 | v2->num_axes = t_axes; | |||||
244 | v2->mode = valuator_get_mode(dev, 0); | |||||
245 | v2->motion_buffer_size = v->numMotionEvents; | |||||
246 | if (client && client->swapped) { | |||||
247 | swapl(&v2->motion_buffer_size)do { if (sizeof(*(&v2->motion_buffer_size)) != 4) wrong_size (); if (__builtin_constant_p((uintptr_t)(&v2->motion_buffer_size ) & 3) && ((uintptr_t)(&v2->motion_buffer_size ) & 3) == 0) *(&v2->motion_buffer_size) = lswapl(* (&v2->motion_buffer_size)); else swap_uint32((uint32_t *)(&v2->motion_buffer_size)); } while (0); | |||||
248 | } | |||||
249 | *buf += sizeof(xValuatorInfo); | |||||
250 | a = v->axes + (VPC20 * i); | |||||
251 | a2 = (xAxisInfoPtr) * buf; | |||||
252 | for (j = 0; j < t_axes; j++) { | |||||
253 | a2->min_value = a->min_value; | |||||
254 | a2->max_value = a->max_value; | |||||
255 | a2->resolution = a->resolution; | |||||
256 | if (client && client->swapped) { | |||||
257 | swapl(&a2->min_value)do { if (sizeof(*(&a2->min_value)) != 4) wrong_size(); if (__builtin_constant_p((uintptr_t)(&a2->min_value) & 3) && ((uintptr_t)(&a2->min_value) & 3) == 0) *(&a2->min_value) = lswapl(*(&a2->min_value )); else swap_uint32((uint32_t *)(&a2->min_value)); } while (0); | |||||
258 | swapl(&a2->max_value)do { if (sizeof(*(&a2->max_value)) != 4) wrong_size(); if (__builtin_constant_p((uintptr_t)(&a2->max_value) & 3) && ((uintptr_t)(&a2->max_value) & 3) == 0) *(&a2->max_value) = lswapl(*(&a2->max_value )); else swap_uint32((uint32_t *)(&a2->max_value)); } while (0); | |||||
259 | swapl(&a2->resolution)do { if (sizeof(*(&a2->resolution)) != 4) wrong_size() ; if (__builtin_constant_p((uintptr_t)(&a2->resolution ) & 3) && ((uintptr_t)(&a2->resolution) & 3) == 0) *(&a2->resolution) = lswapl(*(&a2->resolution )); else swap_uint32((uint32_t *)(&a2->resolution)); } while (0); | |||||
260 | } | |||||
261 | a2++; | |||||
262 | a++; | |||||
263 | *buf += sizeof(xAxisInfo); | |||||
264 | } | |||||
265 | } | |||||
266 | return i; | |||||
267 | } | |||||
268 | ||||||
269 | static void | |||||
270 | CopySwapClasses(ClientPtr client, DeviceIntPtr dev, CARD8 *num_classes, | |||||
271 | char **classbuf) | |||||
272 | { | |||||
273 | if (dev->key != NULL((void*)0)) { | |||||
274 | CopySwapKeyClass(client, dev->key, classbuf); | |||||
275 | (*num_classes)++; | |||||
276 | } | |||||
277 | if (dev->button != NULL((void*)0)) { | |||||
278 | CopySwapButtonClass(client, dev->button, classbuf); | |||||
279 | (*num_classes)++; | |||||
280 | } | |||||
281 | if (dev->valuator != NULL((void*)0)) { | |||||
282 | (*num_classes) += CopySwapValuatorClass(client, dev, classbuf); | |||||
283 | } | |||||
284 | } | |||||
285 | ||||||
286 | /*********************************************************************** | |||||
287 | * | |||||
288 | * This procedure lists information to be returned for an input device. | |||||
289 | * | |||||
290 | */ | |||||
291 | ||||||
292 | static void | |||||
293 | ListDeviceInfo(ClientPtr client, DeviceIntPtr d, xDeviceInfoPtr dev, | |||||
294 | char **devbuf, char **classbuf, char **namebuf) | |||||
295 | { | |||||
296 | CopyDeviceName(namebuf, d->name); | |||||
297 | CopySwapDevice(client, d, 0, devbuf); | |||||
298 | CopySwapClasses(client, d, &dev->num_classes, classbuf); | |||||
299 | } | |||||
300 | ||||||
301 | /*********************************************************************** | |||||
302 | * | |||||
303 | * This procedure checks if a device should be left off the list. | |||||
304 | * | |||||
305 | */ | |||||
306 | ||||||
307 | static Bool | |||||
308 | ShouldSkipDevice(ClientPtr client, DeviceIntPtr d) | |||||
309 | { | |||||
310 | /* don't send master devices other than VCP/VCK */ | |||||
311 | if (!IsMaster(d) || d == inputInfo.pointer ||d == inputInfo.keyboard) { | |||||
312 | int rc = XaceHook(XACE_DEVICE_ACCESS3, client, d, DixGetAttrAccess(1<<4)); | |||||
313 | ||||||
314 | if (rc == Success0) | |||||
315 | return FALSE0; | |||||
316 | } | |||||
317 | return TRUE1; | |||||
318 | } | |||||
319 | ||||||
320 | /*********************************************************************** | |||||
321 | * | |||||
322 | * This procedure lists the input devices available to the server. | |||||
323 | * | |||||
324 | * If this request is called by a client that has not issued a | |||||
325 | * GetExtensionVersion request with major/minor version set, we don't send the | |||||
326 | * complete device list. Instead, we only send the VCP, the VCK and floating | |||||
327 | * SDs. This resembles the setup found on XI 1.x machines. | |||||
328 | */ | |||||
329 | ||||||
330 | int | |||||
331 | ProcXListInputDevices(ClientPtr client) | |||||
332 | { | |||||
333 | xListInputDevicesReply rep; | |||||
334 | int numdevs = 0; | |||||
335 | int namesize = 1; /* need 1 extra byte for strcpy */ | |||||
336 | int i = 0, size = 0; | |||||
337 | int total_length; | |||||
338 | char *devbuf, *classbuf, *namebuf, *savbuf; | |||||
339 | Bool *skip; | |||||
340 | xDeviceInfo *dev; | |||||
341 | DeviceIntPtr d; | |||||
342 | ||||||
343 | REQUEST_SIZE_MATCH(xListInputDevicesReq)if ((sizeof(xListInputDevicesReq) >> 2) != client->req_len ) return(16); | |||||
344 | ||||||
345 | rep = (xListInputDevicesReply) { | |||||
346 | .repType = X_Reply1, | |||||
347 | .RepType = X_ListInputDevices2, | |||||
348 | .sequenceNumber = client->sequence, | |||||
349 | .length = 0 | |||||
350 | }; | |||||
351 | ||||||
352 | /* allocate space for saving skip value */ | |||||
353 | skip = calloc(sizeof(Bool), inputInfo.numDevices); | |||||
354 | if (!skip) | |||||
355 | return BadAlloc11; | |||||
356 | ||||||
357 | /* figure out which devices to skip */ | |||||
358 | numdevs = 0; | |||||
359 | for (d = inputInfo.devices; d; d = d->next, i++) { | |||||
360 | skip[i] = ShouldSkipDevice(client, d); | |||||
361 | if (skip[i]) | |||||
362 | continue; | |||||
363 | ||||||
364 | SizeDeviceInfo(d, &namesize, &size); | |||||
365 | numdevs++; | |||||
366 | } | |||||
367 | ||||||
368 | for (d = inputInfo.off_devices; d; d = d->next, i++) { | |||||
369 | skip[i] = ShouldSkipDevice(client, d); | |||||
370 | if (skip[i]) | |||||
371 | continue; | |||||
372 | ||||||
373 | SizeDeviceInfo(d, &namesize, &size); | |||||
374 | numdevs++; | |||||
375 | } | |||||
376 | ||||||
377 | /* allocate space for reply */ | |||||
378 | total_length = numdevs * sizeof(xDeviceInfo) + size + namesize; | |||||
379 | devbuf = (char *) calloc(1, total_length); | |||||
380 | classbuf = devbuf + (numdevs * sizeof(xDeviceInfo)); | |||||
381 | namebuf = classbuf + size; | |||||
382 | savbuf = devbuf; | |||||
383 | ||||||
384 | /* fill in and send reply */ | |||||
385 | i = 0; | |||||
386 | dev = (xDeviceInfoPtr) devbuf; | |||||
387 | for (d = inputInfo.devices; d; d = d->next, i++) { | |||||
388 | if (skip[i]) | |||||
389 | continue; | |||||
390 | ||||||
391 | ListDeviceInfo(client, d, dev++, &devbuf, &classbuf, &namebuf); | |||||
392 | } | |||||
393 | ||||||
394 | for (d = inputInfo.off_devices; d; d = d->next, i++) { | |||||
395 | if (skip[i]) | |||||
396 | continue; | |||||
397 | ||||||
398 | ListDeviceInfo(client, d, dev++, &devbuf, &classbuf, &namebuf); | |||||
399 | } | |||||
400 | rep.ndevices = numdevs; | |||||
401 | rep.length = bytes_to_int32(total_length); | |||||
402 | WriteReplyToClient(client, sizeof(xListInputDevicesReply), &rep){ if ((client)->swapped) (*ReplySwapVector[((xReq *)(client )->requestBuffer)->reqType]) (client, (int)(sizeof(xListInputDevicesReply )), &rep); else WriteToClient(client, (int)(sizeof(xListInputDevicesReply )), (&rep)); }; | |||||
403 | WriteToClient(client, total_length, savbuf); | |||||
404 | free(savbuf); | |||||
405 | free(skip); | |||||
406 | return Success0; | |||||
407 | } | |||||
408 | ||||||
409 | /*********************************************************************** | |||||
410 | * | |||||
411 | * This procedure writes the reply for the XListInputDevices function, | |||||
412 | * if the client and server have a different byte ordering. | |||||
413 | * | |||||
414 | */ | |||||
415 | ||||||
416 | void | |||||
417 | SRepXListInputDevices(ClientPtr client, int size, xListInputDevicesReply * rep) | |||||
418 | { | |||||
419 | swaps(&rep->sequenceNumber)do { if (sizeof(*(&rep->sequenceNumber)) != 2) wrong_size (); if (__builtin_constant_p((uintptr_t)(&rep->sequenceNumber ) & 1) && ((uintptr_t)(&rep->sequenceNumber ) & 1) == 0) *(&rep->sequenceNumber) = lswaps(*(& rep->sequenceNumber)); else swap_uint16((uint16_t *)(& rep->sequenceNumber)); } while (0); | |||||
420 | swapl(&rep->length)do { if (sizeof(*(&rep->length)) != 4) wrong_size(); if (__builtin_constant_p((uintptr_t)(&rep->length) & 3) && ((uintptr_t)(&rep->length) & 3) == 0 ) *(&rep->length) = lswapl(*(&rep->length)); else swap_uint32((uint32_t *)(&rep->length)); } while (0); | |||||
421 | WriteToClient(client, size, rep); | |||||
422 | } |