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 43static int 44compare(const void *a, const void *b) 45{ 46 const unsigned int code1 = (const uintptr_t) a; 47 const unsigned int code2 = ((struct_ioctlent *) b)->code; 48 return (code1 > code2) ? 1 : (code1 < code2) ? -1 : 0; 49} 50 51static const struct_ioctlent * 52ioctl_lookup(const unsigned int code) 53{ 54 struct_ioctlent *iop; 55 56 iop = bsearch((const void *) (const uintptr_t) code, ioctlent, 57 nioctlents, sizeof(ioctlent[0]), compare); 58 while (iop > ioctlent) { 59 iop--; 60 if (iop->code != code) { 61 iop++; 62 break; 63 } 64 } 65 return iop; 66} 67 68static const struct_ioctlent * 69ioctl_next_match(const struct_ioctlent *iop) 70{ 71 const unsigned int code = iop->code; 72 iop++; 73 if (iop < ioctlent + nioctlents && iop->code == code) 74 return iop; 75 return NULL; 76} 77 78static void 79ioctl_print_code(const unsigned int code) 80{ 81 tprints("_IOC("); 82 printflags(ioctl_dirs, _IOC_DIR(code), "_IOC_???"); 83 tprintf(", %#x, %#x, %#x)", 84 _IOC_TYPE(code), _IOC_NR(code), _IOC_SIZE(code)); 85} 86 87static int 88evdev_decode_number(const unsigned int code) 89{ 90 const unsigned int nr = _IOC_NR(code); 91 92 if (_IOC_DIR(code) == _IOC_WRITE) { 93 if (nr >= 0xc0 && nr <= 0xc0 + 0x3f) { 94 tprints("EVIOCSABS("); 95 printxval(evdev_abs, nr - 0xc0, "ABS_???"); 96 tprints(")"); 97 return 1; 98 } 99 } 100 101 if (_IOC_DIR(code) != _IOC_READ) 102 return 0; 103 104 if (nr >= 0x20 && nr <= 0x20 + 0x1f) { 105 tprints("EVIOCGBIT("); 106 printxval(evdev_ev, nr - 0x20, "EV_???"); 107 tprintf(", %u)", _IOC_SIZE(code)); 108 return 1; 109 } else if (nr >= 0x40 && nr <= 0x40 + 0x3f) { 110 tprints("EVIOCGABS("); 111 printxval(evdev_abs, nr - 0x40, "ABS_???"); 112 tprints(")"); 113 return 1; 114 } 115 116 switch (_IOC_NR(nr)) { 117 case 0x06: 118 tprintf("EVIOCGNAME(%u)", _IOC_SIZE(code)); 119 return 1; 120 case 0x07: 121 tprintf("EVIOCGPHYS(%u)", _IOC_SIZE(code)); 122 return 1; 123 case 0x08: 124 tprintf("EVIOCGUNIQ(%u)", _IOC_SIZE(code)); 125 return 1; 126 case 0x09: 127 tprintf("EVIOCGPROP(%u)", _IOC_SIZE(code)); 128 return 1; 129 case 0x0a: 130 tprintf("EVIOCGMTSLOTS(%u)", _IOC_SIZE(code)); 131 return 1; 132 case 0x18: 133 tprintf("EVIOCGKEY(%u)", _IOC_SIZE(code)); 134 return 1; 135 case 0x19: 136 tprintf("EVIOCGLED(%u)", _IOC_SIZE(code)); 137 return 1; 138 case 0x1a: 139 tprintf("EVIOCGSND(%u)", _IOC_SIZE(code)); 140 return 1; 141 case 0x1b: 142 tprintf("EVIOCGSW(%u)", _IOC_SIZE(code)); 143 return 1; 144 default: 145 return 0; 146 } 147} 148 149static int 150hiddev_decode_number(const unsigned int code) 151{ 152 if (_IOC_DIR(code) == _IOC_READ) { 153 switch (_IOC_NR(code)) { 154 case 0x04: 155 tprintf("HIDIOCGRAWNAME(%u)", _IOC_SIZE(code)); 156 return 1; 157 case 0x05: 158 tprintf("HIDIOCGRAWPHYS(%u)", _IOC_SIZE(code)); 159 return 1; 160 case 0x06: 161 tprintf("HIDIOCSFEATURE(%u)", _IOC_SIZE(code)); 162 return 1; 163 case 0x12: 164 tprintf("HIDIOCGPHYS(%u)", _IOC_SIZE(code)); 165 return 1; 166 default: 167 return 0; 168 } 169 } else if (_IOC_DIR(code) == (_IOC_READ | _IOC_WRITE)) { 170 switch (_IOC_NR(code)) { 171 case 0x06: 172 tprintf("HIDIOCSFEATURE(%u)", _IOC_SIZE(code)); 173 return 1; 174 case 0x07: 175 tprintf("HIDIOCGFEATURE(%u)", _IOC_SIZE(code)); 176 return 1; 177 default: 178 return 0; 179 } 180 } 181 182 return 0; 183} 184 185static int 186ioctl_decode_command_number(struct tcb *tcp) 187{ 188 const unsigned int code = tcp->u_arg[1]; 189 190 switch (_IOC_TYPE(code)) { 191 case 'E': 192 return evdev_decode_number(code); 193 case 'H': 194 return hiddev_decode_number(code); 195 case 'M': 196 if (_IOC_DIR(code) == _IOC_WRITE) { 197 tprintf("MIXER_WRITE(%u)", _IOC_NR(code)); 198 return 1; 199 } else if (_IOC_DIR(code) == _IOC_READ) { 200 tprintf("MIXER_READ(%u)", _IOC_NR(code)); 201 return 1; 202 } 203 return 0; 204 case 'U': 205 if (_IOC_DIR(code) == _IOC_READ && _IOC_NR(code) == 0x2c) { 206 tprintf("UI_GET_SYSNAME(%u)", _IOC_SIZE(code)); 207 return 1; 208 } 209 return 0; 210 case 'j': 211 if (_IOC_DIR(code) == _IOC_READ && _IOC_NR(code) == 0x13) { 212 tprintf("JSIOCGNAME(%u)", _IOC_SIZE(code)); 213 return 1; 214 } 215 return 0; 216 case 'k': 217 if (_IOC_DIR(code) == _IOC_WRITE && _IOC_NR(code) == 0) { 218 tprintf("SPI_IOC_MESSAGE(%u)", _IOC_SIZE(code)); 219 return 1; 220 } 221 return 0; 222 default: 223 return 0; 224 } 225} 226 227static int 228ioctl_decode(struct tcb *tcp) 229{ 230 const unsigned int code = tcp->u_arg[1]; 231 const kernel_ulong_t arg = tcp->u_arg[2]; 232 233 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 return file_ioctl(tcp, code, arg); 246 case 0x54: 247#endif /* !ALPHA */ 248 return term_ioctl(tcp, code, arg); 249 case 0x89: 250 return sock_ioctl(tcp, code, arg); 251 case 'p': 252 return rtc_ioctl(tcp, code, arg); 253 case 0x03: 254 return hdio_ioctl(tcp, code, arg); 255 case 0x12: 256 return block_ioctl(tcp, code, arg); 257 case 'X': 258 return fs_x_ioctl(tcp, code, arg); 259 case 0x22: 260 return scsi_ioctl(tcp, code, arg); 261 case 'L': 262 return loop_ioctl(tcp, code, arg); 263 case 'M': 264 return mtd_ioctl(tcp, code, arg); 265 case 'o': 266 case 'O': 267 return ubi_ioctl(tcp, code, arg); 268 case 'V': 269 return v4l2_ioctl(tcp, code, arg); 270 case '=': 271 return ptp_ioctl(tcp, code, arg); 272#ifdef HAVE_LINUX_INPUT_H 273 case 'E': 274 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 return btrfs_ioctl(tcp, code, arg); 283#endif 284 case 0xb7: 285 return nsfs_ioctl(tcp, code, arg); 286#ifdef HAVE_LINUX_DM_IOCTL_H 287 case 0xfd: 288 return dm_ioctl(tcp, code, arg); 289#endif 290 default: 291 break; 292 } 293 return 0; 294} 295 296SYS_FUNC(ioctl) 297{ 298 const struct_ioctlent *iop; 299 int ret; 300 301 if (entering(tcp)) { 302 printfd(tcp, tcp->u_arg[0]); 303 tprints(", "); 304 ret = ioctl_decode_command_number(tcp); 305 if (!(ret & IOCTL_NUMBER_STOP_LOOKUP)) { 306 iop = ioctl_lookup(tcp->u_arg[1]); 307 if (iop) { 308 if (ret) 309 tprints(" or "); 310 tprints(iop->symbol); 311 while ((iop = ioctl_next_match(iop))) 312 tprintf(" or %s", iop->symbol); 313 } else if (!ret) { 314 ioctl_print_code(tcp->u_arg[1]); 315 } 316 } 317 ret = ioctl_decode(tcp); 318 } else { 319 ret = ioctl_decode(tcp) | RVAL_DECODED; 320 } 321 322 if (ret & RVAL_DECODED) { 323 ret &= ~RVAL_DECODED; 324 if (ret) 325 --ret; 326 else 327 tprintf(", %#" PRI_klx, tcp->u_arg[2]); 328 ret |= RVAL_DECODED; 329 } else { 330 if (ret) 331 --ret; 332 } 333 334 return ret; 335} 336