Home | History | Annotate | Download | only in strace
      1 /*
      2  * Copyright (c) 1991, 1992 Paul Kranenburg <pk (at) cs.few.eur.nl>
      3  * Copyright (c) 1993 Branko Lankester <branko (at) hacktic.nl>
      4  * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs (at) world.std.com>
      5  * Copyright (c) 1996-2001 Wichert Akkerman <wichert (at) 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 compare(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 
     51 static const struct_ioctlent *
     52 ioctl_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 
     68 static const struct_ioctlent *
     69 ioctl_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 
     78 static void
     79 ioctl_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 
     87 static int
     88 evdev_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 
    149 static int
    150 hiddev_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 
    185 static int
    186 ioctl_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 
    227 static int
    228 ioctl_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 
    296 SYS_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