Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 1991, 1992 Paul Kranenburg <pk@cs.few.eur.nl>
3 : : * Copyright (c) 1993 Branko Lankester <branko@hacktic.nl>
4 : : * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com>
5 : : * Copyright (c) 1996-2001 Wichert Akkerman <wichert@cistron.nl>
6 : : * Copyright (c) 1999-2017 The strace developers.
7 : : * All rights reserved.
8 : : *
9 : : * Redistribution and use in source and binary forms, with or without
10 : : * modification, are permitted provided that the following conditions
11 : : * are met:
12 : : * 1. Redistributions of source code must retain the above copyright
13 : : * notice, this list of conditions and the following disclaimer.
14 : : * 2. Redistributions in binary form must reproduce the above copyright
15 : : * notice, this list of conditions and the following disclaimer in the
16 : : * documentation and/or other materials provided with the distribution.
17 : : * 3. The name of the author may not be used to endorse or promote products
18 : : * derived from this software without specific prior written permission.
19 : : *
20 : : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 : : * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 : : * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 : : * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 : : * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 : : * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 : : * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 : : * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 : : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 : : * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 : : */
31 : :
32 : : #include "defs.h"
33 : : #include <linux/ioctl.h>
34 : : #include "xlat/ioctl_dirs.h"
35 : :
36 : : #ifdef HAVE_LINUX_INPUT_H
37 : : # include <linux/input.h>
38 : : #endif
39 : :
40 : : #include "xlat/evdev_abs.h"
41 : : #include "xlat/evdev_ev.h"
42 : :
43 : : static int
44 : 17299 : compare(const void *a, const void *b)
45 : : {
46 : 17299 : const unsigned int code1 = (const uintptr_t) a;
47 : 17299 : const unsigned int code2 = ((struct_ioctlent *) b)->code;
48 [ + + ][ + + ]: 17299 : return (code1 > code2) ? 1 : (code1 < code2) ? -1 : 0;
49 : : }
50 : :
51 : : static const struct_ioctlent *
52 : 1620 : ioctl_lookup(const unsigned int code)
53 : : {
54 : : struct_ioctlent *iop;
55 : :
56 : 3240 : iop = bsearch((const void *) (const uintptr_t) code, ioctlent,
57 : : nioctlents, sizeof(ioctlent[0]), compare);
58 [ + + ]: 1640 : while (iop > ioctlent) {
59 : 1482 : iop--;
60 [ + + ]: 1482 : if (iop->code != code) {
61 : : iop++;
62 : : break;
63 : : }
64 : : }
65 : 1620 : return iop;
66 : : }
67 : :
68 : : static const struct_ioctlent *
69 : : ioctl_next_match(const struct_ioctlent *iop)
70 : : {
71 : 1493 : const unsigned int code = iop->code;
72 : 1493 : iop++;
73 [ + - ][ + + ]: 1493 : if (iop < ioctlent + nioctlents && iop->code == code)
74 : : return iop;
75 : : return NULL;
76 : : }
77 : :
78 : : static void
79 : 58 : ioctl_print_code(const unsigned int code)
80 : : {
81 : 58 : tprints("_IOC(");
82 : 58 : printflags(ioctl_dirs, _IOC_DIR(code), "_IOC_???");
83 : 58 : tprintf(", %#x, %#x, %#x)",
84 : 116 : _IOC_TYPE(code), _IOC_NR(code), _IOC_SIZE(code));
85 : 58 : }
86 : :
87 : : static int
88 : 194 : evdev_decode_number(const unsigned int code)
89 : : {
90 : 194 : const unsigned int nr = _IOC_NR(code);
91 : :
92 [ + + ]: 194 : if (_IOC_DIR(code) == _IOC_WRITE) {
93 [ + + ]: 64 : if (nr >= 0xc0 && nr <= 0xc0 + 0x3f) {
94 : 4 : tprints("EVIOCSABS(");
95 : 4 : printxval(evdev_abs, nr - 0xc0, "ABS_???");
96 : 4 : tprints(")");
97 : 4 : return 1;
98 : : }
99 : : }
100 : :
101 [ + + ]: 190 : if (_IOC_DIR(code) != _IOC_READ)
102 : : return 0;
103 : :
104 [ + + ]: 122 : if (nr >= 0x20 && nr <= 0x20 + 0x1f) {
105 : 54 : tprints("EVIOCGBIT(");
106 : 54 : printxval(evdev_ev, nr - 0x20, "EV_???");
107 : 54 : tprintf(", %u)", _IOC_SIZE(code));
108 : 54 : return 1;
109 [ + + ]: 68 : } else if (nr >= 0x40 && nr <= 0x40 + 0x3f) {
110 : 4 : tprints("EVIOCGABS(");
111 : 4 : printxval(evdev_abs, nr - 0x40, "ABS_???");
112 : 4 : tprints(")");
113 : 4 : return 1;
114 : : }
115 : :
116 [ + + + + : 64 : switch (_IOC_NR(nr)) {
+ + + + +
+ ]
117 : : case 0x06:
118 : 4 : tprintf("EVIOCGNAME(%u)", _IOC_SIZE(code));
119 : 4 : return 1;
120 : : case 0x07:
121 : 4 : tprintf("EVIOCGPHYS(%u)", _IOC_SIZE(code));
122 : 4 : return 1;
123 : : case 0x08:
124 : 4 : tprintf("EVIOCGUNIQ(%u)", _IOC_SIZE(code));
125 : 4 : return 1;
126 : : case 0x09:
127 : 4 : tprintf("EVIOCGPROP(%u)", _IOC_SIZE(code));
128 : 4 : return 1;
129 : : case 0x0a:
130 : 4 : tprintf("EVIOCGMTSLOTS(%u)", _IOC_SIZE(code));
131 : 4 : return 1;
132 : : case 0x18:
133 : 4 : tprintf("EVIOCGKEY(%u)", _IOC_SIZE(code));
134 : 4 : return 1;
135 : : case 0x19:
136 : 4 : tprintf("EVIOCGLED(%u)", _IOC_SIZE(code));
137 : 4 : return 1;
138 : : case 0x1a:
139 : 4 : tprintf("EVIOCGSND(%u)", _IOC_SIZE(code));
140 : 4 : return 1;
141 : : case 0x1b:
142 : 4 : tprintf("EVIOCGSW(%u)", _IOC_SIZE(code));
143 : 4 : return 1;
144 : : default:
145 : : return 0;
146 : : }
147 : : }
148 : :
149 : : static int
150 : 4 : hiddev_decode_number(const unsigned int code)
151 : : {
152 [ + - ]: 4 : if (_IOC_DIR(code) == _IOC_READ) {
153 [ - - - + : 4 : switch (_IOC_NR(code)) {
+ ]
154 : : case 0x04:
155 : 0 : tprintf("HIDIOCGRAWNAME(%u)", _IOC_SIZE(code));
156 : 0 : return 1;
157 : : case 0x05:
158 : 0 : tprintf("HIDIOCGRAWPHYS(%u)", _IOC_SIZE(code));
159 : 0 : return 1;
160 : : case 0x06:
161 : 0 : tprintf("HIDIOCSFEATURE(%u)", _IOC_SIZE(code));
162 : 0 : return 1;
163 : : case 0x12:
164 : 2 : tprintf("HIDIOCGPHYS(%u)", _IOC_SIZE(code));
165 : 2 : return 1;
166 : : default:
167 : : return 0;
168 : : }
169 [ # # ]: 0 : } else if (_IOC_DIR(code) == (_IOC_READ | _IOC_WRITE)) {
170 [ # # # ]: 0 : switch (_IOC_NR(code)) {
171 : : case 0x06:
172 : 0 : tprintf("HIDIOCSFEATURE(%u)", _IOC_SIZE(code));
173 : 0 : return 1;
174 : : case 0x07:
175 : 0 : tprintf("HIDIOCGFEATURE(%u)", _IOC_SIZE(code));
176 : 0 : return 1;
177 : : default:
178 : : return 0;
179 : : }
180 : : }
181 : :
182 : : return 0;
183 : : }
184 : :
185 : : static int
186 : 3240 : ioctl_decode_command_number(struct tcb *tcp)
187 : : {
188 : 1620 : const unsigned int code = tcp->u_arg[1];
189 : :
190 [ + + + - : 1620 : switch (_IOC_TYPE(code)) {
- - + ]
191 : : case 'E':
192 : 194 : return evdev_decode_number(code);
193 : : case 'H':
194 : 4 : return hiddev_decode_number(code);
195 : : case 'M':
196 [ + + ]: 78 : if (_IOC_DIR(code) == _IOC_WRITE) {
197 : 28 : tprintf("MIXER_WRITE(%u)", _IOC_NR(code));
198 : : return 1;
199 [ + + ]: 50 : } else if (_IOC_DIR(code) == _IOC_READ) {
200 : 24 : tprintf("MIXER_READ(%u)", _IOC_NR(code));
201 : : return 1;
202 : : }
203 : : return 0;
204 : : case 'U':
205 [ # # ][ # # ]: 0 : if (_IOC_DIR(code) == _IOC_READ && _IOC_NR(code) == 0x2c) {
206 : 0 : tprintf("UI_GET_SYSNAME(%u)", _IOC_SIZE(code));
207 : : return 1;
208 : : }
209 : : return 0;
210 : : case 'j':
211 [ # # ][ # # ]: 0 : if (_IOC_DIR(code) == _IOC_READ && _IOC_NR(code) == 0x13) {
212 : 0 : tprintf("JSIOCGNAME(%u)", _IOC_SIZE(code));
213 : : return 1;
214 : : }
215 : : return 0;
216 : : case 'k':
217 [ # # ][ # # ]: 0 : if (_IOC_DIR(code) == _IOC_WRITE && _IOC_NR(code) == 0) {
218 : 0 : tprintf("SPI_IOC_MESSAGE(%u)", _IOC_SIZE(code));
219 : : return 1;
220 : : }
221 : : return 0;
222 : : default:
223 : : return 0;
224 : : }
225 : : }
226 : :
227 : : static int
228 : 2412 : ioctl_decode(struct tcb *tcp)
229 : : {
230 : 2412 : const unsigned int code = tcp->u_arg[1];
231 : 2412 : const kernel_ulong_t arg = tcp->u_arg[2];
232 : :
233 [ + + + + : 2412 : switch (_IOC_TYPE(code)) {
- + - + +
+ - + - +
+ + + + ]
234 : : #if defined(ALPHA) || defined(POWERPC)
235 : : case 'f': {
236 : : int ret = file_ioctl(tcp, code, arg);
237 : : if (ret != RVAL_DECODED)
238 : : return ret;
239 : : }
240 : : case 't':
241 : : case 'T':
242 : : return term_ioctl(tcp, code, arg);
243 : : #else /* !ALPHA */
244 : : case 'f':
245 : 4 : return file_ioctl(tcp, code, arg);
246 : : case 0x54:
247 : : #endif /* !ALPHA */
248 : 4 : return term_ioctl(tcp, code, arg);
249 : : case 0x89:
250 : 32 : return sock_ioctl(tcp, code, arg);
251 : : case 'p':
252 : 192 : return rtc_ioctl(tcp, code, arg);
253 : : case 0x03:
254 : 0 : return hdio_ioctl(tcp, code, arg);
255 : : case 0x12:
256 : 108 : return block_ioctl(tcp, code, arg);
257 : : case 'X':
258 : 0 : return fs_x_ioctl(tcp, code, arg);
259 : : case 0x22:
260 : 200 : return scsi_ioctl(tcp, code, arg);
261 : : case 'L':
262 : 162 : return loop_ioctl(tcp, code, arg);
263 : : case 'M':
264 : 94 : return mtd_ioctl(tcp, code, arg);
265 : : case 'o':
266 : : case 'O':
267 : 0 : return ubi_ioctl(tcp, code, arg);
268 : : case 'V':
269 : 296 : return v4l2_ioctl(tcp, code, arg);
270 : : case '=':
271 : 0 : return ptp_ioctl(tcp, code, arg);
272 : : #ifdef HAVE_LINUX_INPUT_H
273 : : case 'E':
274 : 316 : return evdev_ioctl(tcp, code, arg);
275 : : #endif
276 : : #ifdef HAVE_LINUX_USERFAULTFD_H
277 : : case 0xaa:
278 : : return uffdio_ioctl(tcp, code, arg);
279 : : #endif
280 : : #ifdef HAVE_LINUX_BTRFS_H
281 : : case 0x94:
282 : 616 : return btrfs_ioctl(tcp, code, arg);
283 : : #endif
284 : : case 0xb7:
285 : 24 : return nsfs_ioctl(tcp, code, arg);
286 : : #ifdef HAVE_LINUX_DM_IOCTL_H
287 : : case 0xfd:
288 : 344 : return dm_ioctl(tcp, code, arg);
289 : : #endif
290 : : default:
291 : : break;
292 : : }
293 : : return 0;
294 : : }
295 : :
296 : 2412 : SYS_FUNC(ioctl)
297 : : {
298 : : const struct_ioctlent *iop;
299 : : int ret;
300 : :
301 [ + + ]: 2412 : if (entering(tcp)) {
302 : 1620 : printfd(tcp, tcp->u_arg[0]);
303 : 1620 : tprints(", ");
304 : 1620 : ret = ioctl_decode_command_number(tcp);
305 [ + - ]: 1620 : if (!(ret & IOCTL_NUMBER_STOP_LOOKUP)) {
306 : 1620 : iop = ioctl_lookup(tcp->u_arg[1]);
307 [ + + ]: 1620 : if (iop) {
308 [ + + ]: 1462 : if (ret)
309 : 52 : tprints(" or ");
310 : 1462 : tprints(iop->symbol);
311 [ + + ]: 2955 : while ((iop = ioctl_next_match(iop)))
312 : 31 : tprintf(" or %s", iop->symbol);
313 [ + + ]: 158 : } else if (!ret) {
314 : 58 : ioctl_print_code(tcp->u_arg[1]);
315 : : }
316 : : }
317 : 1620 : ret = ioctl_decode(tcp);
318 : : } else {
319 : 792 : ret = ioctl_decode(tcp) | RVAL_DECODED;
320 : : }
321 : :
322 [ + + ]: 2412 : if (ret & RVAL_DECODED) {
323 : 1620 : ret &= ~RVAL_DECODED;
324 [ + + ]: 1620 : if (ret)
325 : 1544 : --ret;
326 : : else
327 : 76 : tprintf(", %#" PRI_klx, tcp->u_arg[2]);
328 : 1620 : ret |= RVAL_DECODED;
329 : : } else {
330 [ + + ]: 792 : if (ret)
331 : 238 : --ret;
332 : : }
333 : :
334 : 2412 : return ret;
335 : : }
|