| 1 | //===-- sanitizer_common_interceptors_ioctl.inc -----------------*- C++ -*-===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | // |
| 9 | // Ioctl handling in common sanitizer interceptors. |
| 10 | //===----------------------------------------------------------------------===// |
| 11 | |
| 12 | #if !SANITIZER_NETBSD |
| 13 | |
| 14 | #include "sanitizer_flags.h" |
| 15 | |
| 16 | struct ioctl_desc { |
| 17 | unsigned req; |
| 18 | // FIXME: support read+write arguments. Currently READWRITE and WRITE do the |
| 19 | // same thing. |
| 20 | // XXX: The declarations below may use WRITE instead of READWRITE, unless |
| 21 | // explicitly noted. |
| 22 | enum { |
| 23 | NONE, |
| 24 | READ, |
| 25 | WRITE, |
| 26 | READWRITE, |
| 27 | CUSTOM |
| 28 | } type : 3; |
| 29 | unsigned size : 29; |
| 30 | const char* name; |
| 31 | }; |
| 32 | |
| 33 | const unsigned ioctl_table_max = 500; |
| 34 | static ioctl_desc ioctl_table[ioctl_table_max]; |
| 35 | static unsigned ioctl_table_size = 0; |
| 36 | |
| 37 | // This can not be declared as a global, because references to struct_*_sz |
| 38 | // require a global initializer. And this table must be available before global |
| 39 | // initializers are run. |
| 40 | static void ioctl_table_fill() { |
| 41 | #define _(rq, tp, sz) \ |
| 42 | if (IOCTL_##rq != IOCTL_NOT_PRESENT) { \ |
| 43 | CHECK(ioctl_table_size < ioctl_table_max); \ |
| 44 | ioctl_table[ioctl_table_size].req = IOCTL_##rq; \ |
| 45 | ioctl_table[ioctl_table_size].type = ioctl_desc::tp; \ |
| 46 | ioctl_table[ioctl_table_size].size = sz; \ |
| 47 | ioctl_table[ioctl_table_size].name = #rq; \ |
| 48 | ++ioctl_table_size; \ |
| 49 | } |
| 50 | |
| 51 | _(FIONBIO, READ, sizeof(int)); |
| 52 | #if !SANITIZER_HAIKU |
| 53 | _(FIOASYNC, READ, sizeof(int)); |
| 54 | _(FIOCLEX, NONE, 0); |
| 55 | _(FIOGETOWN, WRITE, sizeof(int)); |
| 56 | _(FIONCLEX, NONE, 0); |
| 57 | _(FIOSETOWN, READ, sizeof(int)); |
| 58 | #endif |
| 59 | _(SIOCATMARK, WRITE, sizeof(int)); |
| 60 | _(SIOCGIFCONF, CUSTOM, 0); |
| 61 | _(SIOCGPGRP, WRITE, sizeof(int)); |
| 62 | _(SIOCSPGRP, READ, sizeof(int)); |
| 63 | #if !SANITIZER_SOLARIS && !SANITIZER_HAIKU |
| 64 | _(TIOCCONS, NONE, 0); |
| 65 | #endif |
| 66 | #if !SANITIZER_HAIKU |
| 67 | _(TIOCGETD, WRITE, sizeof(int)); |
| 68 | _(TIOCNOTTY, NONE, 0); |
| 69 | _(TIOCPKT, READ, sizeof(int)); |
| 70 | _(TIOCSETD, READ, sizeof(int)); |
| 71 | _(TIOCSTI, READ, sizeof(char)); |
| 72 | #endif |
| 73 | _(TIOCEXCL, NONE, 0); |
| 74 | _(TIOCGPGRP, WRITE, pid_t_sz); |
| 75 | _(TIOCGWINSZ, WRITE, struct_winsize_sz); |
| 76 | _(TIOCMBIC, READ, sizeof(int)); |
| 77 | _(TIOCMBIS, READ, sizeof(int)); |
| 78 | _(TIOCMGET, WRITE, sizeof(int)); |
| 79 | _(TIOCMSET, READ, sizeof(int)); |
| 80 | _(TIOCNXCL, NONE, 0); |
| 81 | _(TIOCOUTQ, WRITE, sizeof(int)); |
| 82 | # if !SANITIZER_AIX |
| 83 | _(TIOCSCTTY, NONE, 0); |
| 84 | # endif |
| 85 | _(TIOCSPGRP, READ, pid_t_sz); |
| 86 | _(TIOCSWINSZ, READ, struct_winsize_sz); |
| 87 | |
| 88 | #if !SANITIZER_IOS |
| 89 | _(SIOCADDMULTI, READ, struct_ifreq_sz); |
| 90 | _(SIOCDELMULTI, READ, struct_ifreq_sz); |
| 91 | _(SIOCGIFADDR, WRITE, struct_ifreq_sz); |
| 92 | _(SIOCGIFBRDADDR, WRITE, struct_ifreq_sz); |
| 93 | _(SIOCGIFDSTADDR, WRITE, struct_ifreq_sz); |
| 94 | _(SIOCGIFFLAGS, WRITE, struct_ifreq_sz); |
| 95 | _(SIOCGIFMETRIC, WRITE, struct_ifreq_sz); |
| 96 | _(SIOCGIFMTU, WRITE, struct_ifreq_sz); |
| 97 | _(SIOCGIFNETMASK, WRITE, struct_ifreq_sz); |
| 98 | _(SIOCSIFADDR, READ, struct_ifreq_sz); |
| 99 | _(SIOCSIFBRDADDR, READ, struct_ifreq_sz); |
| 100 | _(SIOCSIFDSTADDR, READ, struct_ifreq_sz); |
| 101 | _(SIOCSIFFLAGS, READ, struct_ifreq_sz); |
| 102 | _(SIOCSIFMETRIC, READ, struct_ifreq_sz); |
| 103 | _(SIOCSIFMTU, READ, struct_ifreq_sz); |
| 104 | _(SIOCSIFNETMASK, READ, struct_ifreq_sz); |
| 105 | #endif |
| 106 | |
| 107 | #if (SANITIZER_LINUX && !SANITIZER_ANDROID) |
| 108 | _(SIOCGETSGCNT, WRITE, struct_sioc_sg_req_sz); |
| 109 | _(SIOCGETVIFCNT, WRITE, struct_sioc_vif_req_sz); |
| 110 | #endif |
| 111 | |
| 112 | #if SANITIZER_LINUX |
| 113 | // Conflicting request ids. |
| 114 | // _(CDROMAUDIOBUFSIZ, NONE, 0); |
| 115 | // _(SNDCTL_TMR_CONTINUE, NONE, 0); |
| 116 | // _(SNDCTL_TMR_START, NONE, 0); |
| 117 | // _(SNDCTL_TMR_STOP, NONE, 0); |
| 118 | // _(SOUND_MIXER_READ_LOUD, WRITE, sizeof(int)); // same as ...READ_ENHANCE |
| 119 | // _(SOUND_MIXER_READ_MUTE, WRITE, sizeof(int)); // same as ...READ_ENHANCE |
| 120 | // _(SOUND_MIXER_WRITE_LOUD, WRITE, sizeof(int)); // same as ...WRITE_ENHANCE |
| 121 | // _(SOUND_MIXER_WRITE_MUTE, WRITE, sizeof(int)); // same as ...WRITE_ENHANCE |
| 122 | _(BLKFLSBUF, NONE, 0); |
| 123 | _(BLKGETSIZE, WRITE, sizeof(uptr)); |
| 124 | _(BLKRAGET, WRITE, sizeof(uptr)); |
| 125 | _(BLKRASET, NONE, 0); |
| 126 | _(BLKROGET, WRITE, sizeof(int)); |
| 127 | _(BLKROSET, READ, sizeof(int)); |
| 128 | _(BLKRRPART, NONE, 0); |
| 129 | _(BLKFRASET, NONE, 0); |
| 130 | _(BLKFRAGET, WRITE, sizeof(uptr)); |
| 131 | _(BLKSECTSET, READ, sizeof(short)); |
| 132 | _(BLKSECTGET, WRITE, sizeof(short)); |
| 133 | _(BLKSSZGET, WRITE, sizeof(int)); |
| 134 | _(BLKBSZGET, WRITE, sizeof(int)); |
| 135 | _(BLKBSZSET, READ, sizeof(uptr)); |
| 136 | _(BLKGETSIZE64, WRITE, sizeof(u64)); |
| 137 | _(CDROMEJECT, NONE, 0); |
| 138 | _(CDROMEJECT_SW, NONE, 0); |
| 139 | _(CDROMMULTISESSION, WRITE, struct_cdrom_multisession_sz); |
| 140 | _(CDROMPAUSE, NONE, 0); |
| 141 | _(CDROMPLAYMSF, READ, struct_cdrom_msf_sz); |
| 142 | _(CDROMPLAYTRKIND, READ, struct_cdrom_ti_sz); |
| 143 | _(CDROMREADAUDIO, READ, struct_cdrom_read_audio_sz); |
| 144 | _(CDROMREADCOOKED, READ, struct_cdrom_msf_sz); |
| 145 | _(CDROMREADMODE1, READ, struct_cdrom_msf_sz); |
| 146 | _(CDROMREADMODE2, READ, struct_cdrom_msf_sz); |
| 147 | _(CDROMREADRAW, READ, struct_cdrom_msf_sz); |
| 148 | _(CDROMREADTOCENTRY, WRITE, struct_cdrom_tocentry_sz); |
| 149 | _(CDROMREADTOCHDR, WRITE, struct_cdrom_tochdr_sz); |
| 150 | _(CDROMRESET, NONE, 0); |
| 151 | _(CDROMRESUME, NONE, 0); |
| 152 | _(CDROMSEEK, READ, struct_cdrom_msf_sz); |
| 153 | _(CDROMSTART, NONE, 0); |
| 154 | _(CDROMSTOP, NONE, 0); |
| 155 | _(CDROMSUBCHNL, WRITE, struct_cdrom_subchnl_sz); |
| 156 | _(CDROMVOLCTRL, READ, struct_cdrom_volctrl_sz); |
| 157 | _(CDROMVOLREAD, WRITE, struct_cdrom_volctrl_sz); |
| 158 | _(CDROM_GET_UPC, WRITE, 8); |
| 159 | _(EVIOCGABS, WRITE, struct_input_absinfo_sz); // fixup |
| 160 | _(EVIOCGBIT, WRITE, struct_input_id_sz); // fixup |
| 161 | _(EVIOCGEFFECTS, WRITE, sizeof(int)); |
| 162 | _(EVIOCGID, WRITE, struct_input_id_sz); |
| 163 | _(EVIOCGKEY, WRITE, 0); |
| 164 | _(EVIOCGKEYCODE, WRITE, sizeof(int) * 2); |
| 165 | _(EVIOCGLED, WRITE, 0); |
| 166 | _(EVIOCGNAME, WRITE, 0); |
| 167 | _(EVIOCGPHYS, WRITE, 0); |
| 168 | _(EVIOCGRAB, READ, sizeof(int)); |
| 169 | _(EVIOCGREP, WRITE, sizeof(int) * 2); |
| 170 | _(EVIOCGSND, WRITE, 0); |
| 171 | _(EVIOCGSW, WRITE, 0); |
| 172 | _(EVIOCGUNIQ, WRITE, 0); |
| 173 | _(EVIOCGVERSION, WRITE, sizeof(int)); |
| 174 | _(EVIOCRMFF, READ, sizeof(int)); |
| 175 | _(EVIOCSABS, READ, struct_input_absinfo_sz); // fixup |
| 176 | _(EVIOCSFF, READ, struct_ff_effect_sz); |
| 177 | _(EVIOCSKEYCODE, READ, sizeof(int) * 2); |
| 178 | _(EVIOCSREP, READ, sizeof(int) * 2); |
| 179 | _(FDCLRPRM, NONE, 0); |
| 180 | _(FDDEFPRM, READ, struct_floppy_struct_sz); |
| 181 | _(FDFLUSH, NONE, 0); |
| 182 | _(FDFMTBEG, NONE, 0); |
| 183 | _(FDFMTEND, NONE, 0); |
| 184 | _(FDFMTTRK, READ, struct_format_descr_sz); |
| 185 | _(FDGETDRVPRM, WRITE, struct_floppy_drive_params_sz); |
| 186 | _(FDGETDRVSTAT, WRITE, struct_floppy_drive_struct_sz); |
| 187 | _(FDGETDRVTYP, WRITE, 16); |
| 188 | _(FDGETFDCSTAT, WRITE, struct_floppy_fdc_state_sz); |
| 189 | _(FDGETMAXERRS, WRITE, struct_floppy_max_errors_sz); |
| 190 | _(FDGETPRM, WRITE, struct_floppy_struct_sz); |
| 191 | _(FDMSGOFF, NONE, 0); |
| 192 | _(FDMSGON, NONE, 0); |
| 193 | _(FDPOLLDRVSTAT, WRITE, struct_floppy_drive_struct_sz); |
| 194 | _(FDRAWCMD, WRITE, struct_floppy_raw_cmd_sz); |
| 195 | _(FDRESET, NONE, 0); |
| 196 | _(FDSETDRVPRM, READ, struct_floppy_drive_params_sz); |
| 197 | _(FDSETEMSGTRESH, NONE, 0); |
| 198 | _(FDSETMAXERRS, READ, struct_floppy_max_errors_sz); |
| 199 | _(FDSETPRM, READ, struct_floppy_struct_sz); |
| 200 | _(FDTWADDLE, NONE, 0); |
| 201 | _(FDWERRORCLR, NONE, 0); |
| 202 | _(FDWERRORGET, WRITE, struct_floppy_write_errors_sz); |
| 203 | _(HDIO_DRIVE_CMD, WRITE, sizeof(int)); |
| 204 | _(HDIO_GETGEO, WRITE, struct_hd_geometry_sz); |
| 205 | _(HDIO_GET_32BIT, WRITE, sizeof(int)); |
| 206 | _(HDIO_GET_DMA, WRITE, sizeof(int)); |
| 207 | _(HDIO_GET_IDENTITY, WRITE, struct_hd_driveid_sz); |
| 208 | _(HDIO_GET_KEEPSETTINGS, WRITE, sizeof(int)); |
| 209 | _(HDIO_GET_MULTCOUNT, WRITE, sizeof(int)); |
| 210 | _(HDIO_GET_NOWERR, WRITE, sizeof(int)); |
| 211 | _(HDIO_GET_UNMASKINTR, WRITE, sizeof(int)); |
| 212 | _(HDIO_SET_32BIT, NONE, 0); |
| 213 | _(HDIO_SET_DMA, NONE, 0); |
| 214 | _(HDIO_SET_KEEPSETTINGS, NONE, 0); |
| 215 | _(HDIO_SET_MULTCOUNT, NONE, 0); |
| 216 | _(HDIO_SET_NOWERR, NONE, 0); |
| 217 | _(HDIO_SET_UNMASKINTR, NONE, 0); |
| 218 | _(MTIOCGET, WRITE, struct_mtget_sz); |
| 219 | _(MTIOCPOS, WRITE, struct_mtpos_sz); |
| 220 | _(MTIOCTOP, READ, struct_mtop_sz); |
| 221 | _(PPPIOCGASYNCMAP, WRITE, sizeof(int)); |
| 222 | _(PPPIOCGDEBUG, WRITE, sizeof(int)); |
| 223 | _(PPPIOCGFLAGS, WRITE, sizeof(int)); |
| 224 | _(PPPIOCGUNIT, WRITE, sizeof(int)); |
| 225 | _(PPPIOCGXASYNCMAP, WRITE, sizeof(int) * 8); |
| 226 | _(PPPIOCSASYNCMAP, READ, sizeof(int)); |
| 227 | _(PPPIOCSDEBUG, READ, sizeof(int)); |
| 228 | _(PPPIOCSFLAGS, READ, sizeof(int)); |
| 229 | _(PPPIOCSMAXCID, READ, sizeof(int)); |
| 230 | _(PPPIOCSMRU, READ, sizeof(int)); |
| 231 | _(PPPIOCSXASYNCMAP, READ, sizeof(int) * 8); |
| 232 | _(SIOCADDRT, READ, struct_rtentry_sz); |
| 233 | _(SIOCDARP, READ, struct_arpreq_sz); |
| 234 | _(SIOCDELRT, READ, struct_rtentry_sz); |
| 235 | _(SIOCDRARP, READ, struct_arpreq_sz); |
| 236 | _(SIOCGARP, WRITE, struct_arpreq_sz); |
| 237 | _(SIOCGIFENCAP, WRITE, sizeof(int)); |
| 238 | _(SIOCGIFHWADDR, WRITE, struct_ifreq_sz); |
| 239 | _(SIOCGIFMAP, WRITE, struct_ifreq_sz); |
| 240 | _(SIOCGIFMEM, WRITE, struct_ifreq_sz); |
| 241 | _(SIOCGIFNAME, NONE, 0); |
| 242 | _(SIOCGIFSLAVE, NONE, 0); |
| 243 | _(SIOCGRARP, WRITE, struct_arpreq_sz); |
| 244 | _(SIOCGSTAMP, WRITE, timeval_sz); |
| 245 | _(SIOCSARP, READ, struct_arpreq_sz); |
| 246 | _(SIOCSIFENCAP, READ, sizeof(int)); |
| 247 | _(SIOCSIFHWADDR, READ, struct_ifreq_sz); |
| 248 | _(SIOCSIFLINK, NONE, 0); |
| 249 | _(SIOCSIFMAP, READ, struct_ifreq_sz); |
| 250 | _(SIOCSIFMEM, READ, struct_ifreq_sz); |
| 251 | _(SIOCSIFSLAVE, NONE, 0); |
| 252 | _(SIOCSRARP, READ, struct_arpreq_sz); |
| 253 | _(SNDCTL_COPR_HALT, WRITE, struct_copr_debug_buf_sz); |
| 254 | _(SNDCTL_COPR_LOAD, READ, struct_copr_buffer_sz); |
| 255 | _(SNDCTL_COPR_RCODE, WRITE, struct_copr_debug_buf_sz); |
| 256 | _(SNDCTL_COPR_RCVMSG, WRITE, struct_copr_msg_sz); |
| 257 | _(SNDCTL_COPR_RDATA, WRITE, struct_copr_debug_buf_sz); |
| 258 | _(SNDCTL_COPR_RESET, NONE, 0); |
| 259 | _(SNDCTL_COPR_RUN, WRITE, struct_copr_debug_buf_sz); |
| 260 | _(SNDCTL_COPR_SENDMSG, READ, struct_copr_msg_sz); |
| 261 | _(SNDCTL_COPR_WCODE, READ, struct_copr_debug_buf_sz); |
| 262 | _(SNDCTL_COPR_WDATA, READ, struct_copr_debug_buf_sz); |
| 263 | _(SNDCTL_DSP_GETBLKSIZE, WRITE, sizeof(int)); |
| 264 | _(SNDCTL_DSP_GETFMTS, WRITE, sizeof(int)); |
| 265 | _(SNDCTL_DSP_NONBLOCK, NONE, 0); |
| 266 | _(SNDCTL_DSP_POST, NONE, 0); |
| 267 | _(SNDCTL_DSP_RESET, NONE, 0); |
| 268 | _(SNDCTL_DSP_SETFMT, WRITE, sizeof(int)); |
| 269 | _(SNDCTL_DSP_SETFRAGMENT, WRITE, sizeof(int)); |
| 270 | _(SNDCTL_DSP_SPEED, WRITE, sizeof(int)); |
| 271 | _(SNDCTL_DSP_STEREO, WRITE, sizeof(int)); |
| 272 | _(SNDCTL_DSP_SUBDIVIDE, WRITE, sizeof(int)); |
| 273 | _(SNDCTL_DSP_SYNC, NONE, 0); |
| 274 | _(SNDCTL_FM_4OP_ENABLE, READ, sizeof(int)); |
| 275 | _(SNDCTL_FM_LOAD_INSTR, READ, struct_sbi_instrument_sz); |
| 276 | _(SNDCTL_MIDI_INFO, WRITE, struct_midi_info_sz); |
| 277 | _(SNDCTL_MIDI_PRETIME, WRITE, sizeof(int)); |
| 278 | _(SNDCTL_SEQ_CTRLRATE, WRITE, sizeof(int)); |
| 279 | _(SNDCTL_SEQ_GETINCOUNT, WRITE, sizeof(int)); |
| 280 | _(SNDCTL_SEQ_GETOUTCOUNT, WRITE, sizeof(int)); |
| 281 | _(SNDCTL_SEQ_NRMIDIS, WRITE, sizeof(int)); |
| 282 | _(SNDCTL_SEQ_NRSYNTHS, WRITE, sizeof(int)); |
| 283 | _(SNDCTL_SEQ_OUTOFBAND, READ, struct_seq_event_rec_sz); |
| 284 | _(SNDCTL_SEQ_PANIC, NONE, 0); |
| 285 | _(SNDCTL_SEQ_PERCMODE, NONE, 0); |
| 286 | _(SNDCTL_SEQ_RESET, NONE, 0); |
| 287 | _(SNDCTL_SEQ_RESETSAMPLES, READ, sizeof(int)); |
| 288 | _(SNDCTL_SEQ_SYNC, NONE, 0); |
| 289 | _(SNDCTL_SEQ_TESTMIDI, READ, sizeof(int)); |
| 290 | _(SNDCTL_SEQ_THRESHOLD, READ, sizeof(int)); |
| 291 | _(SNDCTL_SYNTH_INFO, WRITE, struct_synth_info_sz); |
| 292 | _(SNDCTL_SYNTH_MEMAVL, WRITE, sizeof(int)); |
| 293 | _(SNDCTL_TMR_METRONOME, READ, sizeof(int)); |
| 294 | _(SNDCTL_TMR_SELECT, WRITE, sizeof(int)); |
| 295 | _(SNDCTL_TMR_SOURCE, WRITE, sizeof(int)); |
| 296 | _(SNDCTL_TMR_TEMPO, WRITE, sizeof(int)); |
| 297 | _(SNDCTL_TMR_TIMEBASE, WRITE, sizeof(int)); |
| 298 | _(SOUND_MIXER_READ_ALTPCM, WRITE, sizeof(int)); |
| 299 | _(SOUND_MIXER_READ_BASS, WRITE, sizeof(int)); |
| 300 | _(SOUND_MIXER_READ_CAPS, WRITE, sizeof(int)); |
| 301 | _(SOUND_MIXER_READ_CD, WRITE, sizeof(int)); |
| 302 | _(SOUND_MIXER_READ_DEVMASK, WRITE, sizeof(int)); |
| 303 | _(SOUND_MIXER_READ_ENHANCE, WRITE, sizeof(int)); |
| 304 | _(SOUND_MIXER_READ_IGAIN, WRITE, sizeof(int)); |
| 305 | _(SOUND_MIXER_READ_IMIX, WRITE, sizeof(int)); |
| 306 | _(SOUND_MIXER_READ_LINE, WRITE, sizeof(int)); |
| 307 | _(SOUND_MIXER_READ_LINE1, WRITE, sizeof(int)); |
| 308 | _(SOUND_MIXER_READ_LINE2, WRITE, sizeof(int)); |
| 309 | _(SOUND_MIXER_READ_LINE3, WRITE, sizeof(int)); |
| 310 | _(SOUND_MIXER_READ_MIC, WRITE, sizeof(int)); |
| 311 | _(SOUND_MIXER_READ_OGAIN, WRITE, sizeof(int)); |
| 312 | _(SOUND_MIXER_READ_PCM, WRITE, sizeof(int)); |
| 313 | _(SOUND_MIXER_READ_RECLEV, WRITE, sizeof(int)); |
| 314 | _(SOUND_MIXER_READ_RECMASK, WRITE, sizeof(int)); |
| 315 | _(SOUND_MIXER_READ_RECSRC, WRITE, sizeof(int)); |
| 316 | _(SOUND_MIXER_READ_SPEAKER, WRITE, sizeof(int)); |
| 317 | _(SOUND_MIXER_READ_STEREODEVS, WRITE, sizeof(int)); |
| 318 | _(SOUND_MIXER_READ_SYNTH, WRITE, sizeof(int)); |
| 319 | _(SOUND_MIXER_READ_TREBLE, WRITE, sizeof(int)); |
| 320 | _(SOUND_MIXER_READ_VOLUME, WRITE, sizeof(int)); |
| 321 | _(SOUND_MIXER_WRITE_ALTPCM, WRITE, sizeof(int)); |
| 322 | _(SOUND_MIXER_WRITE_BASS, WRITE, sizeof(int)); |
| 323 | _(SOUND_MIXER_WRITE_CD, WRITE, sizeof(int)); |
| 324 | _(SOUND_MIXER_WRITE_ENHANCE, WRITE, sizeof(int)); |
| 325 | _(SOUND_MIXER_WRITE_IGAIN, WRITE, sizeof(int)); |
| 326 | _(SOUND_MIXER_WRITE_IMIX, WRITE, sizeof(int)); |
| 327 | _(SOUND_MIXER_WRITE_LINE, WRITE, sizeof(int)); |
| 328 | _(SOUND_MIXER_WRITE_LINE1, WRITE, sizeof(int)); |
| 329 | _(SOUND_MIXER_WRITE_LINE2, WRITE, sizeof(int)); |
| 330 | _(SOUND_MIXER_WRITE_LINE3, WRITE, sizeof(int)); |
| 331 | _(SOUND_MIXER_WRITE_MIC, WRITE, sizeof(int)); |
| 332 | _(SOUND_MIXER_WRITE_OGAIN, WRITE, sizeof(int)); |
| 333 | _(SOUND_MIXER_WRITE_PCM, WRITE, sizeof(int)); |
| 334 | _(SOUND_MIXER_WRITE_RECLEV, WRITE, sizeof(int)); |
| 335 | _(SOUND_MIXER_WRITE_RECSRC, WRITE, sizeof(int)); |
| 336 | _(SOUND_MIXER_WRITE_SPEAKER, WRITE, sizeof(int)); |
| 337 | _(SOUND_MIXER_WRITE_SYNTH, WRITE, sizeof(int)); |
| 338 | _(SOUND_MIXER_WRITE_TREBLE, WRITE, sizeof(int)); |
| 339 | _(SOUND_MIXER_WRITE_VOLUME, WRITE, sizeof(int)); |
| 340 | _(SOUND_PCM_READ_BITS, WRITE, sizeof(int)); |
| 341 | _(SOUND_PCM_READ_CHANNELS, WRITE, sizeof(int)); |
| 342 | _(SOUND_PCM_READ_FILTER, WRITE, sizeof(int)); |
| 343 | _(SOUND_PCM_READ_RATE, WRITE, sizeof(int)); |
| 344 | _(SOUND_PCM_WRITE_CHANNELS, WRITE, sizeof(int)); |
| 345 | _(SOUND_PCM_WRITE_FILTER, WRITE, sizeof(int)); |
| 346 | _(TCFLSH, NONE, 0); |
| 347 | _(TCGETS, WRITE, struct_termios_sz); |
| 348 | _(TCSBRK, NONE, 0); |
| 349 | _(TCSBRKP, NONE, 0); |
| 350 | _(TCSETS, READ, struct_termios_sz); |
| 351 | _(TCSETSF, READ, struct_termios_sz); |
| 352 | _(TCSETSW, READ, struct_termios_sz); |
| 353 | _(TCXONC, NONE, 0); |
| 354 | _(TIOCGLCKTRMIOS, WRITE, struct_termios_sz); |
| 355 | _(TIOCGSOFTCAR, WRITE, sizeof(int)); |
| 356 | _(TIOCINQ, WRITE, sizeof(int)); |
| 357 | _(TIOCLINUX, READ, sizeof(char)); |
| 358 | _(TIOCSERCONFIG, NONE, 0); |
| 359 | _(TIOCSERGETLSR, WRITE, sizeof(int)); |
| 360 | _(TIOCSERGWILD, WRITE, sizeof(int)); |
| 361 | _(TIOCSERSWILD, READ, sizeof(int)); |
| 362 | _(TIOCSLCKTRMIOS, READ, struct_termios_sz); |
| 363 | _(TIOCSSOFTCAR, READ, sizeof(int)); |
| 364 | _(VT_ACTIVATE, NONE, 0); |
| 365 | _(VT_DISALLOCATE, NONE, 0); |
| 366 | _(VT_GETMODE, WRITE, struct_vt_mode_sz); |
| 367 | _(VT_GETSTATE, WRITE, struct_vt_stat_sz); |
| 368 | _(VT_OPENQRY, WRITE, sizeof(int)); |
| 369 | _(VT_RELDISP, NONE, 0); |
| 370 | _(VT_RESIZE, READ, struct_vt_sizes_sz); |
| 371 | _(VT_RESIZEX, READ, struct_vt_consize_sz); |
| 372 | _(VT_SENDSIG, NONE, 0); |
| 373 | _(VT_SETMODE, READ, struct_vt_mode_sz); |
| 374 | _(VT_WAITACTIVE, NONE, 0); |
| 375 | #endif |
| 376 | |
| 377 | #if SANITIZER_GLIBC |
| 378 | // _(SIOCDEVPLIP, WRITE, struct_ifreq_sz); // the same as EQL_ENSLAVE |
| 379 | _(EQL_EMANCIPATE, WRITE, struct_ifreq_sz); |
| 380 | _(EQL_ENSLAVE, WRITE, struct_ifreq_sz); |
| 381 | _(EQL_GETMASTRCFG, WRITE, struct_ifreq_sz); |
| 382 | _(EQL_GETSLAVECFG, WRITE, struct_ifreq_sz); |
| 383 | _(EQL_SETMASTRCFG, WRITE, struct_ifreq_sz); |
| 384 | _(EQL_SETSLAVECFG, WRITE, struct_ifreq_sz); |
| 385 | _(EVIOCGKEYCODE_V2, WRITE, struct_input_keymap_entry_sz); |
| 386 | _(EVIOCGPROP, WRITE, 0); |
| 387 | _(EVIOCSKEYCODE_V2, READ, struct_input_keymap_entry_sz); |
| 388 | _(FS_IOC_GETFLAGS, WRITE, sizeof(int)); |
| 389 | _(FS_IOC_GETVERSION, WRITE, sizeof(int)); |
| 390 | _(FS_IOC_SETFLAGS, READ, sizeof(int)); |
| 391 | _(FS_IOC_SETVERSION, READ, sizeof(int)); |
| 392 | _(GIO_CMAP, WRITE, 48); |
| 393 | _(GIO_FONT, WRITE, 8192); |
| 394 | _(GIO_SCRNMAP, WRITE, e_tabsz); |
| 395 | _(GIO_UNIMAP, WRITE, struct_unimapdesc_sz); |
| 396 | _(GIO_UNISCRNMAP, WRITE, sizeof(short) * e_tabsz); |
| 397 | _(KDADDIO, NONE, 0); |
| 398 | _(KDDELIO, NONE, 0); |
| 399 | _(KDDISABIO, NONE, 0); |
| 400 | _(KDENABIO, NONE, 0); |
| 401 | _(KDGETKEYCODE, WRITE, struct_kbkeycode_sz); |
| 402 | _(KDGETLED, WRITE, 1); |
| 403 | _(KDGETMODE, WRITE, sizeof(int)); |
| 404 | _(KDGKBDIACR, WRITE, struct_kbdiacrs_sz); |
| 405 | _(KDGKBENT, WRITE, struct_kbentry_sz); |
| 406 | _(KDGKBLED, WRITE, sizeof(int)); |
| 407 | _(KDGKBMETA, WRITE, sizeof(int)); |
| 408 | _(KDGKBMODE, WRITE, sizeof(int)); |
| 409 | _(KDGKBSENT, WRITE, struct_kbsentry_sz); |
| 410 | _(KDGKBTYPE, WRITE, 1); |
| 411 | _(KDMAPDISP, NONE, 0); |
| 412 | _(KDMKTONE, NONE, 0); |
| 413 | _(KDSETKEYCODE, READ, struct_kbkeycode_sz); |
| 414 | _(KDSETLED, NONE, 0); |
| 415 | _(KDSETMODE, NONE, 0); |
| 416 | _(KDSIGACCEPT, NONE, 0); |
| 417 | _(KDSKBDIACR, READ, struct_kbdiacrs_sz); |
| 418 | _(KDSKBENT, READ, struct_kbentry_sz); |
| 419 | _(KDSKBLED, NONE, 0); |
| 420 | _(KDSKBMETA, NONE, 0); |
| 421 | _(KDSKBMODE, NONE, 0); |
| 422 | _(KDSKBSENT, READ, struct_kbsentry_sz); |
| 423 | _(KDUNMAPDISP, NONE, 0); |
| 424 | _(KIOCSOUND, NONE, 0); |
| 425 | _(LPABORT, NONE, 0); |
| 426 | _(LPABORTOPEN, NONE, 0); |
| 427 | _(LPCAREFUL, NONE, 0); |
| 428 | _(LPCHAR, NONE, 0); |
| 429 | _(LPGETIRQ, WRITE, sizeof(int)); |
| 430 | _(LPGETSTATUS, WRITE, sizeof(int)); |
| 431 | _(LPRESET, NONE, 0); |
| 432 | _(LPSETIRQ, NONE, 0); |
| 433 | _(LPTIME, NONE, 0); |
| 434 | _(LPWAIT, NONE, 0); |
| 435 | _(MTIOCGETCONFIG, WRITE, struct_mtconfiginfo_sz); |
| 436 | _(MTIOCSETCONFIG, READ, struct_mtconfiginfo_sz); |
| 437 | _(PIO_CMAP, NONE, 0); |
| 438 | _(PIO_FONT, READ, 8192); |
| 439 | _(PIO_SCRNMAP, READ, e_tabsz); |
| 440 | _(PIO_UNIMAP, READ, struct_unimapdesc_sz); |
| 441 | _(PIO_UNIMAPCLR, READ, struct_unimapinit_sz); |
| 442 | _(PIO_UNISCRNMAP, READ, sizeof(short) * e_tabsz); |
| 443 | _(SCSI_IOCTL_PROBE_HOST, READ, sizeof(int)); |
| 444 | _(SCSI_IOCTL_TAGGED_DISABLE, NONE, 0); |
| 445 | _(SCSI_IOCTL_TAGGED_ENABLE, NONE, 0); |
| 446 | _(SNDCTL_DSP_GETISPACE, WRITE, struct_audio_buf_info_sz); |
| 447 | _(SNDCTL_DSP_GETOSPACE, WRITE, struct_audio_buf_info_sz); |
| 448 | _(TIOCGSERIAL, WRITE, struct_serial_struct_sz); |
| 449 | _(TIOCSERGETMULTI, WRITE, struct_serial_multiport_struct_sz); |
| 450 | _(TIOCSERSETMULTI, READ, struct_serial_multiport_struct_sz); |
| 451 | _(TIOCSSERIAL, READ, struct_serial_struct_sz); |
| 452 | |
| 453 | // The following ioctl requests are shared between AX25, IPX, netrom and |
| 454 | // mrouted. |
| 455 | // _(SIOCAIPXITFCRT, READ, sizeof(char)); |
| 456 | // _(SIOCAX25GETUID, READ, struct_sockaddr_ax25_sz); |
| 457 | // _(SIOCNRGETPARMS, WRITE, struct_nr_parms_struct_sz); |
| 458 | // _(SIOCAIPXPRISLT, READ, sizeof(char)); |
| 459 | // _(SIOCNRSETPARMS, READ, struct_nr_parms_struct_sz); |
| 460 | // _(SIOCAX25ADDUID, READ, struct_sockaddr_ax25_sz); |
| 461 | // _(SIOCNRDECOBS, NONE, 0); |
| 462 | // _(SIOCAX25DELUID, READ, struct_sockaddr_ax25_sz); |
| 463 | // _(SIOCIPXCFGDATA, WRITE, struct_ipx_config_data_sz); |
| 464 | // _(SIOCAX25NOUID, READ, sizeof(int)); |
| 465 | // _(SIOCNRRTCTL, READ, sizeof(int)); |
| 466 | // _(SIOCAX25DIGCTL, READ, sizeof(int)); |
| 467 | // _(SIOCAX25GETPARMS, WRITE, struct_ax25_parms_struct_sz); |
| 468 | // _(SIOCAX25SETPARMS, READ, struct_ax25_parms_struct_sz); |
| 469 | #endif |
| 470 | #undef _ |
| 471 | } |
| 472 | |
| 473 | static bool ioctl_initialized = false; |
| 474 | |
| 475 | struct ioctl_desc_compare { |
| 476 | bool operator()(const ioctl_desc& left, const ioctl_desc& right) const { |
| 477 | return left.req < right.req; |
| 478 | } |
| 479 | }; |
| 480 | |
| 481 | static void ioctl_init() { |
| 482 | ioctl_table_fill(); |
| 483 | Sort(v: ioctl_table, size: ioctl_table_size, comp: ioctl_desc_compare()); |
| 484 | |
| 485 | bool bad = false; |
| 486 | for (unsigned i = 0; i < ioctl_table_size - 1; ++i) { |
| 487 | if (ioctl_table[i].req >= ioctl_table[i + 1].req) { |
| 488 | Printf(format: "Duplicate or unsorted ioctl request id %x >= %x (%s vs %s)\n" , |
| 489 | ioctl_table[i].req, ioctl_table[i + 1].req, ioctl_table[i].name, |
| 490 | ioctl_table[i + 1].name); |
| 491 | bad = true; |
| 492 | } |
| 493 | } |
| 494 | |
| 495 | if (bad) Die(); |
| 496 | |
| 497 | ioctl_initialized = true; |
| 498 | } |
| 499 | |
| 500 | // Handle the most evil ioctls that encode argument value as part of request id. |
| 501 | static unsigned ioctl_request_fixup(unsigned req) { |
| 502 | #if SANITIZER_LINUX |
| 503 | // Strip size and event number. |
| 504 | const unsigned kEviocgbitMask = |
| 505 | (IOC_SIZEMASK << IOC_SIZESHIFT) | EVIOC_EV_MAX; |
| 506 | if ((req & ~kEviocgbitMask) == IOCTL_EVIOCGBIT) |
| 507 | return IOCTL_EVIOCGBIT; |
| 508 | // Strip absolute axis number. |
| 509 | if ((req & ~EVIOC_ABS_MAX) == IOCTL_EVIOCGABS) |
| 510 | return IOCTL_EVIOCGABS; |
| 511 | if ((req & ~EVIOC_ABS_MAX) == IOCTL_EVIOCSABS) |
| 512 | return IOCTL_EVIOCSABS; |
| 513 | #endif |
| 514 | return req; |
| 515 | } |
| 516 | |
| 517 | static const ioctl_desc *ioctl_table_lookup(unsigned req) { |
| 518 | int left = 0; |
| 519 | int right = ioctl_table_size; |
| 520 | while (left < right) { |
| 521 | int mid = (left + right) / 2; |
| 522 | if (ioctl_table[mid].req < req) |
| 523 | left = mid + 1; |
| 524 | else |
| 525 | right = mid; |
| 526 | } |
| 527 | if (left == right && ioctl_table[left].req == req) |
| 528 | return ioctl_table + left; |
| 529 | else |
| 530 | return nullptr; |
| 531 | } |
| 532 | |
| 533 | static bool ioctl_decode(unsigned req, ioctl_desc *desc) { |
| 534 | CHECK(desc); |
| 535 | desc->req = req; |
| 536 | desc->name = "<DECODED_IOCTL>" ; |
| 537 | desc->size = IOC_SIZE(req); |
| 538 | // Sanity check. |
| 539 | if (desc->size > 0xFFFF) return false; |
| 540 | unsigned dir = IOC_DIR(req); |
| 541 | switch (dir) { |
| 542 | case IOC_NONE: |
| 543 | desc->type = ioctl_desc::NONE; |
| 544 | break; |
| 545 | case IOC_READ | IOC_WRITE: |
| 546 | desc->type = ioctl_desc::READWRITE; |
| 547 | break; |
| 548 | case IOC_READ: |
| 549 | desc->type = ioctl_desc::WRITE; |
| 550 | break; |
| 551 | case IOC_WRITE: |
| 552 | desc->type = ioctl_desc::READ; |
| 553 | break; |
| 554 | default: |
| 555 | return false; |
| 556 | } |
| 557 | // Size can be 0 iff type is NONE. |
| 558 | if ((desc->type == IOC_NONE) != (desc->size == 0)) return false; |
| 559 | // Sanity check. |
| 560 | if (IOC_TYPE(req) == 0) return false; |
| 561 | return true; |
| 562 | } |
| 563 | |
| 564 | static const ioctl_desc *ioctl_lookup(unsigned req) { |
| 565 | req = ioctl_request_fixup(req); |
| 566 | const ioctl_desc *desc = ioctl_table_lookup(req); |
| 567 | if (desc) return desc; |
| 568 | |
| 569 | // Try stripping access size from the request id. |
| 570 | desc = ioctl_table_lookup(req: req & ~(IOC_SIZEMASK << IOC_SIZESHIFT)); |
| 571 | // Sanity check: requests that encode access size are either read or write and |
| 572 | // have size of 0 in the table. |
| 573 | if (desc && desc->size == 0 && |
| 574 | (desc->type == ioctl_desc::READWRITE || desc->type == ioctl_desc::WRITE || |
| 575 | desc->type == ioctl_desc::READ)) |
| 576 | return desc; |
| 577 | return nullptr; |
| 578 | } |
| 579 | |
| 580 | static void ioctl_common_pre(void *ctx, const ioctl_desc *desc, int d, |
| 581 | unsigned request, void *arg) { |
| 582 | if (desc->type == ioctl_desc::READ || desc->type == ioctl_desc::READWRITE) { |
| 583 | unsigned size = desc->size ? desc->size : IOC_SIZE(request); |
| 584 | COMMON_INTERCEPTOR_READ_RANGE(ctx, arg, size); |
| 585 | } |
| 586 | if (desc->type != ioctl_desc::CUSTOM) |
| 587 | return; |
| 588 | if (request == IOCTL_SIOCGIFCONF) { |
| 589 | struct __sanitizer_ifconf *ifc = (__sanitizer_ifconf *)arg; |
| 590 | COMMON_INTERCEPTOR_READ_RANGE(ctx, (char*)&ifc->ifc_len, |
| 591 | sizeof(ifc->ifc_len)); |
| 592 | } |
| 593 | } |
| 594 | |
| 595 | static void ioctl_common_post(void *ctx, const ioctl_desc *desc, int res, int d, |
| 596 | unsigned request, void *arg) { |
| 597 | if (desc->type == ioctl_desc::WRITE || desc->type == ioctl_desc::READWRITE) { |
| 598 | // FIXME: add verbose output |
| 599 | unsigned size = desc->size ? desc->size : IOC_SIZE(request); |
| 600 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, arg, size); |
| 601 | } |
| 602 | if (desc->type != ioctl_desc::CUSTOM) |
| 603 | return; |
| 604 | if (request == IOCTL_SIOCGIFCONF) { |
| 605 | struct __sanitizer_ifconf *ifc = (__sanitizer_ifconf *)arg; |
| 606 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ifc->ifc_ifcu.ifcu_req, ifc->ifc_len); |
| 607 | } |
| 608 | } |
| 609 | |
| 610 | #endif |
| 611 | |