]> granicus.if.org Git - strace/blob - ioctl.c
rtnl_link: print pad field in the struct ifla_port_vsi decoder
[strace] / ioctl.c
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-2019 The strace developers.
7  * All rights reserved.
8  *
9  * SPDX-License-Identifier: LGPL-2.1-or-later
10  */
11
12 #include "defs.h"
13 #include <linux/ioctl.h>
14 #include "xlat/ioctl_dirs.h"
15
16 static int
17 compare(const void *a, const void *b)
18 {
19         const unsigned int code1 = (const uintptr_t) a;
20         const unsigned int code2 = ((struct_ioctlent *) b)->code;
21         return (code1 > code2) ? 1 : (code1 < code2) ? -1 : 0;
22 }
23
24 static const struct_ioctlent *
25 ioctl_lookup(const unsigned int code)
26 {
27         struct_ioctlent *iop;
28
29         iop = bsearch((const void *) (const uintptr_t) code, ioctlent,
30                         nioctlents, sizeof(ioctlent[0]), compare);
31         while (iop > ioctlent) {
32                 iop--;
33                 if (iop->code != code) {
34                         iop++;
35                         break;
36                 }
37         }
38         return iop;
39 }
40
41 static const struct_ioctlent *
42 ioctl_next_match(const struct_ioctlent *iop)
43 {
44         const unsigned int code = iop->code;
45         iop++;
46         if (iop < ioctlent + nioctlents && iop->code == code)
47                 return iop;
48         return NULL;
49 }
50
51 static void
52 ioctl_print_code(const unsigned int code)
53 {
54         const bool abbrev = xlat_verbose(xlat_verbosity) != XLAT_STYLE_VERBOSE;
55
56         tprints("_IOC(");
57         printflags_ex(_IOC_DIR(code), abbrev ? "_IOC_???" : NULL,
58                       abbrev ? XLAT_STYLE_DEFAULT : XLAT_STYLE_ABBREV,
59                       ioctl_dirs, NULL);
60         tprintf(", %#x, %#x, %#x)",
61                 _IOC_TYPE(code), _IOC_NR(code), _IOC_SIZE(code));
62 }
63
64 static int
65 evdev_decode_number(const unsigned int code)
66 {
67         const unsigned int nr = _IOC_NR(code);
68         const bool abbrev = xlat_verbose(xlat_verbosity) != XLAT_STYLE_VERBOSE;
69
70         if (_IOC_DIR(code) == _IOC_WRITE) {
71                 if (nr >= 0xc0 && nr <= 0xc0 + 0x3f) {
72                         tprints("EVIOCSABS(");
73                         printxval_ex(evdev_abs, nr - 0xc0,
74                                      abbrev ? "ABS_???" : NULL,
75                                      abbrev ? XLAT_STYLE_DEFAULT
76                                             : XLAT_STYLE_ABBREV);
77                         tprints(")");
78                         return 1;
79                 }
80         }
81
82         if (_IOC_DIR(code) != _IOC_READ)
83                 return 0;
84
85         if (nr >= 0x20 && nr <= 0x20 + 0x1f) {
86                 tprints("EVIOCGBIT(");
87                 if (nr == 0x20)
88                         tprintf("0");
89                 else
90                         printxval_ex(evdev_ev, nr - 0x20,
91                                      abbrev ? "EV_???" : NULL,
92                                      abbrev ? XLAT_STYLE_DEFAULT
93                                             : XLAT_STYLE_ABBREV);
94                 tprintf(", %u)", _IOC_SIZE(code));
95                 return 1;
96         } else if (nr >= 0x40 && nr <= 0x40 + 0x3f) {
97                 tprints("EVIOCGABS(");
98                 printxval_ex(evdev_abs, nr - 0x40, abbrev ? "ABS_???" : NULL,
99                              abbrev ? XLAT_STYLE_DEFAULT : XLAT_STYLE_ABBREV);
100                 tprints(")");
101                 return 1;
102         }
103
104         switch (nr) {
105                 case 0x06:
106                         tprintf("EVIOCGNAME(%u)", _IOC_SIZE(code));
107                         return 1;
108                 case 0x07:
109                         tprintf("EVIOCGPHYS(%u)", _IOC_SIZE(code));
110                         return 1;
111                 case 0x08:
112                         tprintf("EVIOCGUNIQ(%u)", _IOC_SIZE(code));
113                         return 1;
114                 case 0x09:
115                         tprintf("EVIOCGPROP(%u)", _IOC_SIZE(code));
116                         return 1;
117                 case 0x0a:
118                         tprintf("EVIOCGMTSLOTS(%u)", _IOC_SIZE(code));
119                         return 1;
120                 case 0x18:
121                         tprintf("EVIOCGKEY(%u)", _IOC_SIZE(code));
122                         return 1;
123                 case 0x19:
124                         tprintf("EVIOCGLED(%u)", _IOC_SIZE(code));
125                         return 1;
126                 case 0x1a:
127                         tprintf("EVIOCGSND(%u)", _IOC_SIZE(code));
128                         return 1;
129                 case 0x1b:
130                         tprintf("EVIOCGSW(%u)", _IOC_SIZE(code));
131                         return 1;
132                 default:
133                         return 0;
134         }
135 }
136
137 static int
138 hiddev_decode_number(const unsigned int code)
139 {
140         if (_IOC_DIR(code) == _IOC_READ) {
141                 switch (_IOC_NR(code)) {
142                         case 0x04:
143                                 tprintf("HIDIOCGRAWNAME(%u)", _IOC_SIZE(code));
144                                 return 1;
145                         case 0x05:
146                                 tprintf("HIDIOCGRAWPHYS(%u)", _IOC_SIZE(code));
147                                 return 1;
148                         case 0x06:
149                                 tprintf("HIDIOCSFEATURE(%u)", _IOC_SIZE(code));
150                                 return 1;
151                         case 0x12:
152                                 tprintf("HIDIOCGPHYS(%u)", _IOC_SIZE(code));
153                                 return 1;
154                         default:
155                                 return 0;
156                 }
157         } else if (_IOC_DIR(code) == (_IOC_READ | _IOC_WRITE)) {
158                 switch (_IOC_NR(code)) {
159                         case 0x06:
160                                 tprintf("HIDIOCSFEATURE(%u)", _IOC_SIZE(code));
161                                 return 1;
162                         case 0x07:
163                                 tprintf("HIDIOCGFEATURE(%u)", _IOC_SIZE(code));
164                                 return 1;
165                         default:
166                                 return 0;
167                 }
168         }
169
170         return 0;
171 }
172
173 static int
174 ioctl_decode_command_number(struct tcb *tcp)
175 {
176         const unsigned int code = tcp->u_arg[1];
177
178         switch (_IOC_TYPE(code)) {
179                 case 'E':
180                         return evdev_decode_number(code);
181                 case 'H':
182                         return hiddev_decode_number(code);
183                 case 'M':
184                         if (_IOC_DIR(code) == _IOC_WRITE) {
185                                 tprintf("MIXER_WRITE(%u)", _IOC_NR(code));
186                                 return 1;
187                         } else if (_IOC_DIR(code) == _IOC_READ) {
188                                 tprintf("MIXER_READ(%u)", _IOC_NR(code));
189                                 return 1;
190                         }
191                         return 0;
192                 case 'U':
193                         if (_IOC_DIR(code) == _IOC_READ && _IOC_NR(code) == 0x2c) {
194                                 tprintf("UI_GET_SYSNAME(%u)", _IOC_SIZE(code));
195                                 return 1;
196                         }
197                         return 0;
198                 case 'j':
199                         if (_IOC_DIR(code) == _IOC_READ && _IOC_NR(code) == 0x13) {
200                                 tprintf("JSIOCGNAME(%u)", _IOC_SIZE(code));
201                                 return 1;
202                         }
203                         return 0;
204                 case 'k':
205                         if (_IOC_DIR(code) == _IOC_WRITE && _IOC_NR(code) == 0) {
206                                 tprintf("SPI_IOC_MESSAGE(%u)", _IOC_SIZE(code));
207                                 return 1;
208                         }
209                         return 0;
210                 default:
211                         return 0;
212         }
213 }
214
215 /**
216  * Decode arg parameter of the ioctl call.
217  *
218  * @return There are two flags of the return value important for the purposes of
219  *         processing by SYS_FUNC(ioctl):
220  *          - RVAL_IOCTL_DECODED: indicates that ioctl decoder code
221  *                                has printed arg parameter;
222  *          - RVAL_DECODED: indicates that decoding is done.
223  *         As a result, the following behaviour is expected:
224  *          - on entering:
225  *            - 0: decoding should be continued on exiting;
226  *            - RVAL_IOCTL_DECODED: decoding on exiting is not needed
227  *                                  and decoder has printed arg value;
228  *            - RVAL_DECODED: decoding on exiting is not needed
229  *                            and generic handler should print arg value.
230  *          - on exiting:
231  *            - 0: generic handler should print arg value;
232  *            - RVAL_IOCTL_DECODED: decoder has printed arg value.
233  *
234  *         Note that it makes no sense to return just RVAL_DECODED on exiting,
235  *         but, of course, it is not prohibited (for example, it may be useful
236  *         in cases where the return path is common on entering and on exiting
237  *         the syscall).
238  *
239  *         SYS_FUNC(ioctl) converts RVAL_IOCTL_DECODED flag to RVAL_DECODED,
240  *         and passes all other bits of ioctl_decode return value unchanged.
241  */
242 static int
243 ioctl_decode(struct tcb *tcp)
244 {
245         const unsigned int code = tcp->u_arg[1];
246         const kernel_ulong_t arg = tcp->u_arg[2];
247
248         switch (_IOC_TYPE(code)) {
249         case 0x03:
250                 return hdio_ioctl(tcp, code, arg);
251         case 0x12:
252                 return block_ioctl(tcp, code, arg);
253         case '"': /* 0x22 */
254                 return scsi_ioctl(tcp, code, arg);
255         case '$': /* 0x24 */
256                 return perf_ioctl(tcp, code, arg);
257 #ifdef HAVE_STRUCT_PTP_SYS_OFFSET
258         case '=': /* 0x3d */
259                 return ptp_ioctl(tcp, code, arg);
260 #endif
261 #ifdef HAVE_LINUX_INPUT_H
262         case 'E':
263                 return evdev_ioctl(tcp, code, arg);
264 #endif
265         case 'I':
266                 return inotify_ioctl(tcp, code, arg);
267         case 'L':
268                 return loop_ioctl(tcp, code, arg);
269 #ifdef HAVE_STRUCT_MTD_WRITE_REQ
270         case 'M':
271                 return mtd_ioctl(tcp, code, arg);
272 #endif
273 #ifdef HAVE_STRUCT_UBI_ATTACH_REQ_MAX_BEB_PER1024
274         case 'O':
275                 return ubi_ioctl(tcp, code, arg);
276 #endif
277         case 'R':
278                 return random_ioctl(tcp, code, arg);
279         case 'T':
280                 return term_ioctl(tcp, code, arg);
281         case 'V':
282                 return v4l2_ioctl(tcp, code, arg);
283         case 'W':
284                 return watchdog_ioctl(tcp, code, arg);
285         case 'X':
286                 return fs_x_ioctl(tcp, code, arg);
287         case 'f': {
288 #if defined(ALPHA) || defined(POWERPC)
289                 int ret = file_ioctl(tcp, code, arg);
290                 if (ret != RVAL_DECODED)
291                         return ret;
292                 return term_ioctl(tcp, code, arg);
293 #else /* !(ALPHA || POWERPC) */
294                 return file_ioctl(tcp, code, arg);
295 #endif /* (ALPHA || POWERPC) */
296         }
297 #ifdef HAVE_STRUCT_UBI_ATTACH_REQ_MAX_BEB_PER1024
298         case 'o':
299                 return ubi_ioctl(tcp, code, arg);
300 #endif
301         case 'p':
302                 return rtc_ioctl(tcp, code, arg);
303 #if defined(ALPHA) || defined(POWERPC)
304         case 't':
305                 return term_ioctl(tcp, code, arg);
306 #endif /* !ALPHA */
307         case 0x89:
308                 return sock_ioctl(tcp, code, arg);
309 #ifdef HAVE_LINUX_BTRFS_H
310         case 0x94:
311                 return btrfs_ioctl(tcp, code, arg);
312 #endif
313 #ifdef HAVE_LINUX_USERFAULTFD_H
314         case 0xaa:
315                 return uffdio_ioctl(tcp, code, arg);
316 #endif
317         case 0xab:
318                 return nbd_ioctl(tcp, code, arg);
319 #ifdef HAVE_LINUX_KVM_H
320         case 0xae:
321                 return kvm_ioctl(tcp, code, arg);
322 #endif
323         case 0xb7:
324                 return nsfs_ioctl(tcp, code, arg);
325 #ifdef HAVE_LINUX_DM_IOCTL_H
326         case 0xfd:
327                 return dm_ioctl(tcp, code, arg);
328 #endif
329         default:
330                 break;
331         }
332         return 0;
333 }
334
335 SYS_FUNC(ioctl)
336 {
337         const struct_ioctlent *iop;
338         int ret;
339
340         if (entering(tcp)) {
341                 printfd(tcp, tcp->u_arg[0]);
342                 tprints(", ");
343
344                 if (xlat_verbosity != XLAT_STYLE_ABBREV)
345                         tprintf("%#x", (unsigned int) tcp->u_arg[1]);
346                 if (xlat_verbosity == XLAT_STYLE_VERBOSE)
347                         tprints(" /* ");
348                 if (xlat_verbosity != XLAT_STYLE_RAW) {
349                         ret = ioctl_decode_command_number(tcp);
350                         if (!(ret & IOCTL_NUMBER_STOP_LOOKUP)) {
351                                 iop = ioctl_lookup(tcp->u_arg[1]);
352                                 if (iop) {
353                                         if (ret)
354                                                 tprints(" or ");
355                                         tprints(iop->symbol);
356                                         while ((iop = ioctl_next_match(iop)))
357                                                 tprintf(" or %s", iop->symbol);
358                                 } else if (!ret) {
359                                         ioctl_print_code(tcp->u_arg[1]);
360                                 }
361                         }
362                 }
363                 if (xlat_verbosity == XLAT_STYLE_VERBOSE)
364                         tprints(" */");
365
366                 ret = ioctl_decode(tcp);
367         } else {
368                 ret = ioctl_decode(tcp) | RVAL_DECODED;
369         }
370
371         if (ret & RVAL_IOCTL_DECODED) {
372                 ret &= ~RVAL_IOCTL_DECODED;
373                 ret |= RVAL_DECODED;
374         } else if (ret & RVAL_DECODED) {
375                 tprintf(", %#" PRI_klx, tcp->u_arg[2]);
376         }
377
378         return ret;
379 }