1274201Sdim//===-- sanitizer_common_interceptors_ioctl.inc -----------------*- C++ -*-===//
2274201Sdim//
3274201Sdim//                     The LLVM Compiler Infrastructure
4274201Sdim//
5274201Sdim// This file is distributed under the University of Illinois Open Source
6274201Sdim// License. See LICENSE.TXT for details.
7274201Sdim//
8274201Sdim//===----------------------------------------------------------------------===//
9274201Sdim//
10274201Sdim// Ioctl handling in common sanitizer interceptors.
11274201Sdim//===----------------------------------------------------------------------===//
12274201Sdim
13274201Sdim#include "sanitizer_flags.h"
14274201Sdim
15274201Sdimstruct ioctl_desc {
16274201Sdim  unsigned req;
17276789Sdim  // FIXME: support read+write arguments. Currently READWRITE and WRITE do the
18276789Sdim  // same thing.
19276789Sdim  // XXX: The declarations below may use WRITE instead of READWRITE, unless
20276789Sdim  // explicitly noted.
21274201Sdim  enum {
22274201Sdim    NONE,
23274201Sdim    READ,
24274201Sdim    WRITE,
25276789Sdim    READWRITE,
26274201Sdim    CUSTOM
27276789Sdim  } type : 3;
28276789Sdim  unsigned size : 29;
29274201Sdim  const char* name;
30274201Sdim};
31274201Sdim
32274201Sdimconst unsigned ioctl_table_max = 500;
33274201Sdimstatic ioctl_desc ioctl_table[ioctl_table_max];
34274201Sdimstatic unsigned ioctl_table_size = 0;
35274201Sdim
36274201Sdim// This can not be declared as a global, because references to struct_*_sz
37274201Sdim// require a global initializer. And this table must be available before global
38274201Sdim// initializers are run.
39274201Sdimstatic void ioctl_table_fill() {
40274201Sdim#define _(rq, tp, sz)                                    \
41274201Sdim  if (IOCTL_##rq != IOCTL_NOT_PRESENT) {                 \
42274201Sdim    CHECK(ioctl_table_size < ioctl_table_max);           \
43274201Sdim    ioctl_table[ioctl_table_size].req = IOCTL_##rq;      \
44274201Sdim    ioctl_table[ioctl_table_size].type = ioctl_desc::tp; \
45274201Sdim    ioctl_table[ioctl_table_size].size = sz;             \
46274201Sdim    ioctl_table[ioctl_table_size].name = #rq;            \
47274201Sdim    ++ioctl_table_size;                                  \
48274201Sdim  }
49274201Sdim
50274201Sdim  _(FIOASYNC, READ, sizeof(int));
51274201Sdim  _(FIOCLEX, NONE, 0);
52274201Sdim  _(FIOGETOWN, WRITE, sizeof(int));
53274201Sdim  _(FIONBIO, READ, sizeof(int));
54274201Sdim  _(FIONCLEX, NONE, 0);
55274201Sdim  _(FIOSETOWN, READ, sizeof(int));
56274201Sdim  _(SIOCADDMULTI, READ, struct_ifreq_sz);
57274201Sdim  _(SIOCATMARK, WRITE, sizeof(int));
58274201Sdim  _(SIOCDELMULTI, READ, struct_ifreq_sz);
59274201Sdim  _(SIOCGIFADDR, WRITE, struct_ifreq_sz);
60274201Sdim  _(SIOCGIFBRDADDR, WRITE, struct_ifreq_sz);
61274201Sdim  _(SIOCGIFCONF, CUSTOM, 0);
62274201Sdim  _(SIOCGIFDSTADDR, WRITE, struct_ifreq_sz);
63274201Sdim  _(SIOCGIFFLAGS, WRITE, struct_ifreq_sz);
64274201Sdim  _(SIOCGIFMETRIC, WRITE, struct_ifreq_sz);
65274201Sdim  _(SIOCGIFMTU, WRITE, struct_ifreq_sz);
66274201Sdim  _(SIOCGIFNETMASK, WRITE, struct_ifreq_sz);
67274201Sdim  _(SIOCGPGRP, WRITE, sizeof(int));
68274201Sdim  _(SIOCSIFADDR, READ, struct_ifreq_sz);
69274201Sdim  _(SIOCSIFBRDADDR, READ, struct_ifreq_sz);
70274201Sdim  _(SIOCSIFDSTADDR, READ, struct_ifreq_sz);
71274201Sdim  _(SIOCSIFFLAGS, READ, struct_ifreq_sz);
72274201Sdim  _(SIOCSIFMETRIC, READ, struct_ifreq_sz);
73274201Sdim  _(SIOCSIFMTU, READ, struct_ifreq_sz);
74274201Sdim  _(SIOCSIFNETMASK, READ, struct_ifreq_sz);
75274201Sdim  _(SIOCSPGRP, READ, sizeof(int));
76274201Sdim  _(TIOCCONS, NONE, 0);
77274201Sdim  _(TIOCEXCL, NONE, 0);
78274201Sdim  _(TIOCGETD, WRITE, sizeof(int));
79274201Sdim  _(TIOCGPGRP, WRITE, pid_t_sz);
80274201Sdim  _(TIOCGWINSZ, WRITE, struct_winsize_sz);
81274201Sdim  _(TIOCMBIC, READ, sizeof(int));
82274201Sdim  _(TIOCMBIS, READ, sizeof(int));
83274201Sdim  _(TIOCMGET, WRITE, sizeof(int));
84274201Sdim  _(TIOCMSET, READ, sizeof(int));
85274201Sdim  _(TIOCNOTTY, NONE, 0);
86274201Sdim  _(TIOCNXCL, NONE, 0);
87274201Sdim  _(TIOCOUTQ, WRITE, sizeof(int));
88274201Sdim  _(TIOCPKT, READ, sizeof(int));
89274201Sdim  _(TIOCSCTTY, NONE, 0);
90274201Sdim  _(TIOCSETD, READ, sizeof(int));
91274201Sdim  _(TIOCSPGRP, READ, pid_t_sz);
92274201Sdim  _(TIOCSTI, READ, sizeof(char));
93274201Sdim  _(TIOCSWINSZ, READ, struct_winsize_sz);
94274201Sdim
95274201Sdim#if (SANITIZER_LINUX && !SANITIZER_ANDROID)
96274201Sdim  _(SIOCGETSGCNT, WRITE, struct_sioc_sg_req_sz);
97274201Sdim  _(SIOCGETVIFCNT, WRITE, struct_sioc_vif_req_sz);
98274201Sdim#endif
99274201Sdim
100274201Sdim#if SANITIZER_LINUX
101274201Sdim  // Conflicting request ids.
102274201Sdim  // _(CDROMAUDIOBUFSIZ, NONE, 0);
103274201Sdim  // _(SNDCTL_TMR_CONTINUE, NONE, 0);
104274201Sdim  // _(SNDCTL_TMR_START, NONE, 0);
105274201Sdim  // _(SNDCTL_TMR_STOP, NONE, 0);
106274201Sdim  // _(SOUND_MIXER_READ_LOUD, WRITE, sizeof(int)); // same as ...READ_ENHANCE
107274201Sdim  // _(SOUND_MIXER_READ_MUTE, WRITE, sizeof(int)); // same as ...READ_ENHANCE
108274201Sdim  // _(SOUND_MIXER_WRITE_LOUD, WRITE, sizeof(int)); // same as ...WRITE_ENHANCE
109274201Sdim  // _(SOUND_MIXER_WRITE_MUTE, WRITE, sizeof(int)); // same as ...WRITE_ENHANCE
110274201Sdim  _(BLKFLSBUF, NONE, 0);
111274201Sdim  _(BLKGETSIZE, WRITE, sizeof(uptr));
112274201Sdim  _(BLKRAGET, WRITE, sizeof(int));
113274201Sdim  _(BLKRASET, NONE, 0);
114274201Sdim  _(BLKROGET, WRITE, sizeof(int));
115274201Sdim  _(BLKROSET, READ, sizeof(int));
116274201Sdim  _(BLKRRPART, NONE, 0);
117274201Sdim  _(CDROMEJECT, NONE, 0);
118274201Sdim  _(CDROMEJECT_SW, NONE, 0);
119274201Sdim  _(CDROMMULTISESSION, WRITE, struct_cdrom_multisession_sz);
120274201Sdim  _(CDROMPAUSE, NONE, 0);
121274201Sdim  _(CDROMPLAYMSF, READ, struct_cdrom_msf_sz);
122274201Sdim  _(CDROMPLAYTRKIND, READ, struct_cdrom_ti_sz);
123274201Sdim  _(CDROMREADAUDIO, READ, struct_cdrom_read_audio_sz);
124274201Sdim  _(CDROMREADCOOKED, READ, struct_cdrom_msf_sz);
125274201Sdim  _(CDROMREADMODE1, READ, struct_cdrom_msf_sz);
126274201Sdim  _(CDROMREADMODE2, READ, struct_cdrom_msf_sz);
127274201Sdim  _(CDROMREADRAW, READ, struct_cdrom_msf_sz);
128274201Sdim  _(CDROMREADTOCENTRY, WRITE, struct_cdrom_tocentry_sz);
129274201Sdim  _(CDROMREADTOCHDR, WRITE, struct_cdrom_tochdr_sz);
130274201Sdim  _(CDROMRESET, NONE, 0);
131274201Sdim  _(CDROMRESUME, NONE, 0);
132274201Sdim  _(CDROMSEEK, READ, struct_cdrom_msf_sz);
133274201Sdim  _(CDROMSTART, NONE, 0);
134274201Sdim  _(CDROMSTOP, NONE, 0);
135274201Sdim  _(CDROMSUBCHNL, WRITE, struct_cdrom_subchnl_sz);
136274201Sdim  _(CDROMVOLCTRL, READ, struct_cdrom_volctrl_sz);
137274201Sdim  _(CDROMVOLREAD, WRITE, struct_cdrom_volctrl_sz);
138274201Sdim  _(CDROM_GET_UPC, WRITE, 8);
139274201Sdim  _(EVIOCGABS, WRITE, struct_input_absinfo_sz); // fixup
140274201Sdim  _(EVIOCGBIT, WRITE, struct_input_id_sz); // fixup
141274201Sdim  _(EVIOCGEFFECTS, WRITE, sizeof(int));
142274201Sdim  _(EVIOCGID, WRITE, struct_input_id_sz);
143274201Sdim  _(EVIOCGKEY, WRITE, 0);
144274201Sdim  _(EVIOCGKEYCODE, WRITE, sizeof(int) * 2);
145274201Sdim  _(EVIOCGLED, WRITE, 0);
146274201Sdim  _(EVIOCGNAME, WRITE, 0);
147274201Sdim  _(EVIOCGPHYS, WRITE, 0);
148274201Sdim  _(EVIOCGRAB, READ, sizeof(int));
149274201Sdim  _(EVIOCGREP, WRITE, sizeof(int) * 2);
150274201Sdim  _(EVIOCGSND, WRITE, 0);
151274201Sdim  _(EVIOCGSW, WRITE, 0);
152274201Sdim  _(EVIOCGUNIQ, WRITE, 0);
153274201Sdim  _(EVIOCGVERSION, WRITE, sizeof(int));
154274201Sdim  _(EVIOCRMFF, READ, sizeof(int));
155274201Sdim  _(EVIOCSABS, READ, struct_input_absinfo_sz); // fixup
156274201Sdim  _(EVIOCSFF, READ, struct_ff_effect_sz);
157274201Sdim  _(EVIOCSKEYCODE, READ, sizeof(int) * 2);
158274201Sdim  _(EVIOCSREP, READ, sizeof(int) * 2);
159274201Sdim  _(FDCLRPRM, NONE, 0);
160274201Sdim  _(FDDEFPRM, READ, struct_floppy_struct_sz);
161274201Sdim  _(FDFLUSH, NONE, 0);
162274201Sdim  _(FDFMTBEG, NONE, 0);
163274201Sdim  _(FDFMTEND, NONE, 0);
164274201Sdim  _(FDFMTTRK, READ, struct_format_descr_sz);
165274201Sdim  _(FDGETDRVPRM, WRITE, struct_floppy_drive_params_sz);
166274201Sdim  _(FDGETDRVSTAT, WRITE, struct_floppy_drive_struct_sz);
167274201Sdim  _(FDGETDRVTYP, WRITE, 16);
168274201Sdim  _(FDGETFDCSTAT, WRITE, struct_floppy_fdc_state_sz);
169274201Sdim  _(FDGETMAXERRS, WRITE, struct_floppy_max_errors_sz);
170274201Sdim  _(FDGETPRM, WRITE, struct_floppy_struct_sz);
171274201Sdim  _(FDMSGOFF, NONE, 0);
172274201Sdim  _(FDMSGON, NONE, 0);
173274201Sdim  _(FDPOLLDRVSTAT, WRITE, struct_floppy_drive_struct_sz);
174274201Sdim  _(FDRAWCMD, WRITE, struct_floppy_raw_cmd_sz);
175274201Sdim  _(FDRESET, NONE, 0);
176274201Sdim  _(FDSETDRVPRM, READ, struct_floppy_drive_params_sz);
177274201Sdim  _(FDSETEMSGTRESH, NONE, 0);
178274201Sdim  _(FDSETMAXERRS, READ, struct_floppy_max_errors_sz);
179274201Sdim  _(FDSETPRM, READ, struct_floppy_struct_sz);
180274201Sdim  _(FDTWADDLE, NONE, 0);
181274201Sdim  _(FDWERRORCLR, NONE, 0);
182274201Sdim  _(FDWERRORGET, WRITE, struct_floppy_write_errors_sz);
183274201Sdim  _(HDIO_DRIVE_CMD, WRITE, sizeof(int));
184274201Sdim  _(HDIO_GETGEO, WRITE, struct_hd_geometry_sz);
185274201Sdim  _(HDIO_GET_32BIT, WRITE, sizeof(int));
186274201Sdim  _(HDIO_GET_DMA, WRITE, sizeof(int));
187274201Sdim  _(HDIO_GET_IDENTITY, WRITE, struct_hd_driveid_sz);
188274201Sdim  _(HDIO_GET_KEEPSETTINGS, WRITE, sizeof(int));
189274201Sdim  _(HDIO_GET_MULTCOUNT, WRITE, sizeof(int));
190274201Sdim  _(HDIO_GET_NOWERR, WRITE, sizeof(int));
191274201Sdim  _(HDIO_GET_UNMASKINTR, WRITE, sizeof(int));
192274201Sdim  _(HDIO_SET_32BIT, NONE, 0);
193274201Sdim  _(HDIO_SET_DMA, NONE, 0);
194274201Sdim  _(HDIO_SET_KEEPSETTINGS, NONE, 0);
195274201Sdim  _(HDIO_SET_MULTCOUNT, NONE, 0);
196274201Sdim  _(HDIO_SET_NOWERR, NONE, 0);
197274201Sdim  _(HDIO_SET_UNMASKINTR, NONE, 0);
198274201Sdim  _(MTIOCGET, WRITE, struct_mtget_sz);
199274201Sdim  _(MTIOCPOS, WRITE, struct_mtpos_sz);
200274201Sdim  _(MTIOCTOP, READ, struct_mtop_sz);
201274201Sdim  _(PPPIOCGASYNCMAP, WRITE, sizeof(int));
202274201Sdim  _(PPPIOCGDEBUG, WRITE, sizeof(int));
203274201Sdim  _(PPPIOCGFLAGS, WRITE, sizeof(int));
204274201Sdim  _(PPPIOCGUNIT, WRITE, sizeof(int));
205274201Sdim  _(PPPIOCGXASYNCMAP, WRITE, sizeof(int) * 8);
206274201Sdim  _(PPPIOCSASYNCMAP, READ, sizeof(int));
207274201Sdim  _(PPPIOCSDEBUG, READ, sizeof(int));
208274201Sdim  _(PPPIOCSFLAGS, READ, sizeof(int));
209274201Sdim  _(PPPIOCSMAXCID, READ, sizeof(int));
210274201Sdim  _(PPPIOCSMRU, READ, sizeof(int));
211274201Sdim  _(PPPIOCSXASYNCMAP, READ, sizeof(int) * 8);
212274201Sdim  _(SIOCADDRT, READ, struct_rtentry_sz);
213274201Sdim  _(SIOCDARP, READ, struct_arpreq_sz);
214274201Sdim  _(SIOCDELRT, READ, struct_rtentry_sz);
215274201Sdim  _(SIOCDRARP, READ, struct_arpreq_sz);
216274201Sdim  _(SIOCGARP, WRITE, struct_arpreq_sz);
217274201Sdim  _(SIOCGIFENCAP, WRITE, sizeof(int));
218274201Sdim  _(SIOCGIFHWADDR, WRITE, struct_ifreq_sz);
219274201Sdim  _(SIOCGIFMAP, WRITE, struct_ifreq_sz);
220274201Sdim  _(SIOCGIFMEM, WRITE, struct_ifreq_sz);
221274201Sdim  _(SIOCGIFNAME, NONE, 0);
222274201Sdim  _(SIOCGIFSLAVE, NONE, 0);
223274201Sdim  _(SIOCGRARP, WRITE, struct_arpreq_sz);
224274201Sdim  _(SIOCGSTAMP, WRITE, timeval_sz);
225274201Sdim  _(SIOCSARP, READ, struct_arpreq_sz);
226274201Sdim  _(SIOCSIFENCAP, READ, sizeof(int));
227274201Sdim  _(SIOCSIFHWADDR, READ, struct_ifreq_sz);
228274201Sdim  _(SIOCSIFLINK, NONE, 0);
229274201Sdim  _(SIOCSIFMAP, READ, struct_ifreq_sz);
230274201Sdim  _(SIOCSIFMEM, READ, struct_ifreq_sz);
231274201Sdim  _(SIOCSIFSLAVE, NONE, 0);
232274201Sdim  _(SIOCSRARP, READ, struct_arpreq_sz);
233274201Sdim  _(SNDCTL_COPR_HALT, WRITE, struct_copr_debug_buf_sz);
234274201Sdim  _(SNDCTL_COPR_LOAD, READ, struct_copr_buffer_sz);
235274201Sdim  _(SNDCTL_COPR_RCODE, WRITE, struct_copr_debug_buf_sz);
236274201Sdim  _(SNDCTL_COPR_RCVMSG, WRITE, struct_copr_msg_sz);
237274201Sdim  _(SNDCTL_COPR_RDATA, WRITE, struct_copr_debug_buf_sz);
238274201Sdim  _(SNDCTL_COPR_RESET, NONE, 0);
239274201Sdim  _(SNDCTL_COPR_RUN, WRITE, struct_copr_debug_buf_sz);
240274201Sdim  _(SNDCTL_COPR_SENDMSG, READ, struct_copr_msg_sz);
241274201Sdim  _(SNDCTL_COPR_WCODE, READ, struct_copr_debug_buf_sz);
242274201Sdim  _(SNDCTL_COPR_WDATA, READ, struct_copr_debug_buf_sz);
243274201Sdim  _(SNDCTL_DSP_GETBLKSIZE, WRITE, sizeof(int));
244274201Sdim  _(SNDCTL_DSP_GETFMTS, WRITE, sizeof(int));
245274201Sdim  _(SNDCTL_DSP_NONBLOCK, NONE, 0);
246274201Sdim  _(SNDCTL_DSP_POST, NONE, 0);
247274201Sdim  _(SNDCTL_DSP_RESET, NONE, 0);
248274201Sdim  _(SNDCTL_DSP_SETFMT, WRITE, sizeof(int));
249274201Sdim  _(SNDCTL_DSP_SETFRAGMENT, WRITE, sizeof(int));
250274201Sdim  _(SNDCTL_DSP_SPEED, WRITE, sizeof(int));
251274201Sdim  _(SNDCTL_DSP_STEREO, WRITE, sizeof(int));
252274201Sdim  _(SNDCTL_DSP_SUBDIVIDE, WRITE, sizeof(int));
253274201Sdim  _(SNDCTL_DSP_SYNC, NONE, 0);
254274201Sdim  _(SNDCTL_FM_4OP_ENABLE, READ, sizeof(int));
255274201Sdim  _(SNDCTL_FM_LOAD_INSTR, READ, struct_sbi_instrument_sz);
256274201Sdim  _(SNDCTL_MIDI_INFO, WRITE, struct_midi_info_sz);
257274201Sdim  _(SNDCTL_MIDI_PRETIME, WRITE, sizeof(int));
258274201Sdim  _(SNDCTL_SEQ_CTRLRATE, WRITE, sizeof(int));
259274201Sdim  _(SNDCTL_SEQ_GETINCOUNT, WRITE, sizeof(int));
260274201Sdim  _(SNDCTL_SEQ_GETOUTCOUNT, WRITE, sizeof(int));
261274201Sdim  _(SNDCTL_SEQ_NRMIDIS, WRITE, sizeof(int));
262274201Sdim  _(SNDCTL_SEQ_NRSYNTHS, WRITE, sizeof(int));
263274201Sdim  _(SNDCTL_SEQ_OUTOFBAND, READ, struct_seq_event_rec_sz);
264274201Sdim  _(SNDCTL_SEQ_PANIC, NONE, 0);
265274201Sdim  _(SNDCTL_SEQ_PERCMODE, NONE, 0);
266274201Sdim  _(SNDCTL_SEQ_RESET, NONE, 0);
267274201Sdim  _(SNDCTL_SEQ_RESETSAMPLES, READ, sizeof(int));
268274201Sdim  _(SNDCTL_SEQ_SYNC, NONE, 0);
269274201Sdim  _(SNDCTL_SEQ_TESTMIDI, READ, sizeof(int));
270274201Sdim  _(SNDCTL_SEQ_THRESHOLD, READ, sizeof(int));
271274201Sdim  _(SNDCTL_SYNTH_INFO, WRITE, struct_synth_info_sz);
272274201Sdim  _(SNDCTL_SYNTH_MEMAVL, WRITE, sizeof(int));
273274201Sdim  _(SNDCTL_TMR_METRONOME, READ, sizeof(int));
274274201Sdim  _(SNDCTL_TMR_SELECT, WRITE, sizeof(int));
275274201Sdim  _(SNDCTL_TMR_SOURCE, WRITE, sizeof(int));
276274201Sdim  _(SNDCTL_TMR_TEMPO, WRITE, sizeof(int));
277274201Sdim  _(SNDCTL_TMR_TIMEBASE, WRITE, sizeof(int));
278274201Sdim  _(SOUND_MIXER_READ_ALTPCM, WRITE, sizeof(int));
279274201Sdim  _(SOUND_MIXER_READ_BASS, WRITE, sizeof(int));
280274201Sdim  _(SOUND_MIXER_READ_CAPS, WRITE, sizeof(int));
281274201Sdim  _(SOUND_MIXER_READ_CD, WRITE, sizeof(int));
282274201Sdim  _(SOUND_MIXER_READ_DEVMASK, WRITE, sizeof(int));
283274201Sdim  _(SOUND_MIXER_READ_ENHANCE, WRITE, sizeof(int));
284274201Sdim  _(SOUND_MIXER_READ_IGAIN, WRITE, sizeof(int));
285274201Sdim  _(SOUND_MIXER_READ_IMIX, WRITE, sizeof(int));
286274201Sdim  _(SOUND_MIXER_READ_LINE, WRITE, sizeof(int));
287274201Sdim  _(SOUND_MIXER_READ_LINE1, WRITE, sizeof(int));
288274201Sdim  _(SOUND_MIXER_READ_LINE2, WRITE, sizeof(int));
289274201Sdim  _(SOUND_MIXER_READ_LINE3, WRITE, sizeof(int));
290274201Sdim  _(SOUND_MIXER_READ_MIC, WRITE, sizeof(int));
291274201Sdim  _(SOUND_MIXER_READ_OGAIN, WRITE, sizeof(int));
292274201Sdim  _(SOUND_MIXER_READ_PCM, WRITE, sizeof(int));
293274201Sdim  _(SOUND_MIXER_READ_RECLEV, WRITE, sizeof(int));
294274201Sdim  _(SOUND_MIXER_READ_RECMASK, WRITE, sizeof(int));
295274201Sdim  _(SOUND_MIXER_READ_RECSRC, WRITE, sizeof(int));
296274201Sdim  _(SOUND_MIXER_READ_SPEAKER, WRITE, sizeof(int));
297274201Sdim  _(SOUND_MIXER_READ_STEREODEVS, WRITE, sizeof(int));
298274201Sdim  _(SOUND_MIXER_READ_SYNTH, WRITE, sizeof(int));
299274201Sdim  _(SOUND_MIXER_READ_TREBLE, WRITE, sizeof(int));
300274201Sdim  _(SOUND_MIXER_READ_VOLUME, WRITE, sizeof(int));
301274201Sdim  _(SOUND_MIXER_WRITE_ALTPCM, WRITE, sizeof(int));
302274201Sdim  _(SOUND_MIXER_WRITE_BASS, WRITE, sizeof(int));
303274201Sdim  _(SOUND_MIXER_WRITE_CD, WRITE, sizeof(int));
304274201Sdim  _(SOUND_MIXER_WRITE_ENHANCE, WRITE, sizeof(int));
305274201Sdim  _(SOUND_MIXER_WRITE_IGAIN, WRITE, sizeof(int));
306274201Sdim  _(SOUND_MIXER_WRITE_IMIX, WRITE, sizeof(int));
307274201Sdim  _(SOUND_MIXER_WRITE_LINE, WRITE, sizeof(int));
308274201Sdim  _(SOUND_MIXER_WRITE_LINE1, WRITE, sizeof(int));
309274201Sdim  _(SOUND_MIXER_WRITE_LINE2, WRITE, sizeof(int));
310274201Sdim  _(SOUND_MIXER_WRITE_LINE3, WRITE, sizeof(int));
311274201Sdim  _(SOUND_MIXER_WRITE_MIC, WRITE, sizeof(int));
312274201Sdim  _(SOUND_MIXER_WRITE_OGAIN, WRITE, sizeof(int));
313274201Sdim  _(SOUND_MIXER_WRITE_PCM, WRITE, sizeof(int));
314274201Sdim  _(SOUND_MIXER_WRITE_RECLEV, WRITE, sizeof(int));
315274201Sdim  _(SOUND_MIXER_WRITE_RECSRC, WRITE, sizeof(int));
316274201Sdim  _(SOUND_MIXER_WRITE_SPEAKER, WRITE, sizeof(int));
317274201Sdim  _(SOUND_MIXER_WRITE_SYNTH, WRITE, sizeof(int));
318274201Sdim  _(SOUND_MIXER_WRITE_TREBLE, WRITE, sizeof(int));
319274201Sdim  _(SOUND_MIXER_WRITE_VOLUME, WRITE, sizeof(int));
320274201Sdim  _(SOUND_PCM_READ_BITS, WRITE, sizeof(int));
321274201Sdim  _(SOUND_PCM_READ_CHANNELS, WRITE, sizeof(int));
322274201Sdim  _(SOUND_PCM_READ_FILTER, WRITE, sizeof(int));
323274201Sdim  _(SOUND_PCM_READ_RATE, WRITE, sizeof(int));
324274201Sdim  _(SOUND_PCM_WRITE_CHANNELS, WRITE, sizeof(int));
325274201Sdim  _(SOUND_PCM_WRITE_FILTER, WRITE, sizeof(int));
326274201Sdim  _(TCFLSH, NONE, 0);
327274201Sdim  _(TCGETA, WRITE, struct_termio_sz);
328274201Sdim  _(TCGETS, WRITE, struct_termios_sz);
329274201Sdim  _(TCSBRK, NONE, 0);
330274201Sdim  _(TCSBRKP, NONE, 0);
331274201Sdim  _(TCSETA, READ, struct_termio_sz);
332274201Sdim  _(TCSETAF, READ, struct_termio_sz);
333274201Sdim  _(TCSETAW, READ, struct_termio_sz);
334274201Sdim  _(TCSETS, READ, struct_termios_sz);
335274201Sdim  _(TCSETSF, READ, struct_termios_sz);
336274201Sdim  _(TCSETSW, READ, struct_termios_sz);
337274201Sdim  _(TCXONC, NONE, 0);
338274201Sdim  _(TIOCGLCKTRMIOS, WRITE, struct_termios_sz);
339274201Sdim  _(TIOCGSOFTCAR, WRITE, sizeof(int));
340274201Sdim  _(TIOCINQ, WRITE, sizeof(int));
341274201Sdim  _(TIOCLINUX, READ, sizeof(char));
342274201Sdim  _(TIOCSERCONFIG, NONE, 0);
343274201Sdim  _(TIOCSERGETLSR, WRITE, sizeof(int));
344274201Sdim  _(TIOCSERGWILD, WRITE, sizeof(int));
345274201Sdim  _(TIOCSERSWILD, READ, sizeof(int));
346274201Sdim  _(TIOCSLCKTRMIOS, READ, struct_termios_sz);
347274201Sdim  _(TIOCSSOFTCAR, READ, sizeof(int));
348274201Sdim  _(VT_ACTIVATE, NONE, 0);
349274201Sdim  _(VT_DISALLOCATE, NONE, 0);
350274201Sdim  _(VT_GETMODE, WRITE, struct_vt_mode_sz);
351274201Sdim  _(VT_GETSTATE, WRITE, struct_vt_stat_sz);
352274201Sdim  _(VT_OPENQRY, WRITE, sizeof(int));
353274201Sdim  _(VT_RELDISP, NONE, 0);
354274201Sdim  _(VT_RESIZE, READ, struct_vt_sizes_sz);
355274201Sdim  _(VT_RESIZEX, READ, struct_vt_consize_sz);
356274201Sdim  _(VT_SENDSIG, NONE, 0);
357274201Sdim  _(VT_SETMODE, READ, struct_vt_mode_sz);
358274201Sdim  _(VT_WAITACTIVE, NONE, 0);
359274201Sdim#endif
360274201Sdim
361274201Sdim#if SANITIZER_LINUX && !SANITIZER_ANDROID
362274201Sdim  // _(SIOCDEVPLIP, WRITE, struct_ifreq_sz); // the same as EQL_ENSLAVE
363274201Sdim  _(CYGETDEFTHRESH, WRITE, sizeof(int));
364274201Sdim  _(CYGETDEFTIMEOUT, WRITE, sizeof(int));
365274201Sdim  _(CYGETMON, WRITE, struct_cyclades_monitor_sz);
366274201Sdim  _(CYGETTHRESH, WRITE, sizeof(int));
367274201Sdim  _(CYGETTIMEOUT, WRITE, sizeof(int));
368274201Sdim  _(CYSETDEFTHRESH, NONE, 0);
369274201Sdim  _(CYSETDEFTIMEOUT, NONE, 0);
370274201Sdim  _(CYSETTHRESH, NONE, 0);
371274201Sdim  _(CYSETTIMEOUT, NONE, 0);
372274201Sdim  _(EQL_EMANCIPATE, WRITE, struct_ifreq_sz);
373274201Sdim  _(EQL_ENSLAVE, WRITE, struct_ifreq_sz);
374274201Sdim  _(EQL_GETMASTRCFG, WRITE, struct_ifreq_sz);
375274201Sdim  _(EQL_GETSLAVECFG, WRITE, struct_ifreq_sz);
376274201Sdim  _(EQL_SETMASTRCFG, WRITE, struct_ifreq_sz);
377274201Sdim  _(EQL_SETSLAVECFG, WRITE, struct_ifreq_sz);
378274201Sdim  _(EVIOCGKEYCODE_V2, WRITE, struct_input_keymap_entry_sz);
379274201Sdim  _(EVIOCGPROP, WRITE, 0);
380274201Sdim  _(EVIOCSKEYCODE_V2, READ, struct_input_keymap_entry_sz);
381274201Sdim  _(FS_IOC_GETFLAGS, WRITE, sizeof(int));
382274201Sdim  _(FS_IOC_GETVERSION, WRITE, sizeof(int));
383274201Sdim  _(FS_IOC_SETFLAGS, READ, sizeof(int));
384274201Sdim  _(FS_IOC_SETVERSION, READ, sizeof(int));
385274201Sdim  _(GIO_CMAP, WRITE, 48);
386274201Sdim  _(GIO_FONT, WRITE, 8192);
387274201Sdim  _(GIO_SCRNMAP, WRITE, e_tabsz);
388274201Sdim  _(GIO_UNIMAP, WRITE, struct_unimapdesc_sz);
389274201Sdim  _(GIO_UNISCRNMAP, WRITE, sizeof(short) * e_tabsz);
390274201Sdim  _(KDADDIO, NONE, 0);
391274201Sdim  _(KDDELIO, NONE, 0);
392274201Sdim  _(KDDISABIO, NONE, 0);
393274201Sdim  _(KDENABIO, NONE, 0);
394274201Sdim  _(KDGETKEYCODE, WRITE, struct_kbkeycode_sz);
395274201Sdim  _(KDGETLED, WRITE, 1);
396274201Sdim  _(KDGETMODE, WRITE, sizeof(int));
397274201Sdim  _(KDGKBDIACR, WRITE, struct_kbdiacrs_sz);
398274201Sdim  _(KDGKBENT, WRITE, struct_kbentry_sz);
399274201Sdim  _(KDGKBLED, WRITE, sizeof(int));
400274201Sdim  _(KDGKBMETA, WRITE, sizeof(int));
401274201Sdim  _(KDGKBMODE, WRITE, sizeof(int));
402274201Sdim  _(KDGKBSENT, WRITE, struct_kbsentry_sz);
403274201Sdim  _(KDGKBTYPE, WRITE, 1);
404274201Sdim  _(KDMAPDISP, NONE, 0);
405274201Sdim  _(KDMKTONE, NONE, 0);
406274201Sdim  _(KDSETKEYCODE, READ, struct_kbkeycode_sz);
407274201Sdim  _(KDSETLED, NONE, 0);
408274201Sdim  _(KDSETMODE, NONE, 0);
409274201Sdim  _(KDSIGACCEPT, NONE, 0);
410274201Sdim  _(KDSKBDIACR, READ, struct_kbdiacrs_sz);
411274201Sdim  _(KDSKBENT, READ, struct_kbentry_sz);
412274201Sdim  _(KDSKBLED, NONE, 0);
413274201Sdim  _(KDSKBMETA, NONE, 0);
414274201Sdim  _(KDSKBMODE, NONE, 0);
415274201Sdim  _(KDSKBSENT, READ, struct_kbsentry_sz);
416274201Sdim  _(KDUNMAPDISP, NONE, 0);
417274201Sdim  _(KIOCSOUND, NONE, 0);
418274201Sdim  _(LPABORT, NONE, 0);
419274201Sdim  _(LPABORTOPEN, NONE, 0);
420274201Sdim  _(LPCAREFUL, NONE, 0);
421274201Sdim  _(LPCHAR, NONE, 0);
422274201Sdim  _(LPGETIRQ, WRITE, sizeof(int));
423274201Sdim  _(LPGETSTATUS, WRITE, sizeof(int));
424274201Sdim  _(LPRESET, NONE, 0);
425274201Sdim  _(LPSETIRQ, NONE, 0);
426274201Sdim  _(LPTIME, NONE, 0);
427274201Sdim  _(LPWAIT, NONE, 0);
428274201Sdim  _(MTIOCGETCONFIG, WRITE, struct_mtconfiginfo_sz);
429274201Sdim  _(MTIOCSETCONFIG, READ, struct_mtconfiginfo_sz);
430274201Sdim  _(PIO_CMAP, NONE, 0);
431274201Sdim  _(PIO_FONT, READ, 8192);
432274201Sdim  _(PIO_SCRNMAP, READ, e_tabsz);
433274201Sdim  _(PIO_UNIMAP, READ, struct_unimapdesc_sz);
434274201Sdim  _(PIO_UNIMAPCLR, READ, struct_unimapinit_sz);
435274201Sdim  _(PIO_UNISCRNMAP, READ, sizeof(short) * e_tabsz);
436274201Sdim  _(SCSI_IOCTL_PROBE_HOST, READ, sizeof(int));
437274201Sdim  _(SCSI_IOCTL_TAGGED_DISABLE, NONE, 0);
438274201Sdim  _(SCSI_IOCTL_TAGGED_ENABLE, NONE, 0);
439274201Sdim  _(SNDCTL_DSP_GETISPACE, WRITE, struct_audio_buf_info_sz);
440274201Sdim  _(SNDCTL_DSP_GETOSPACE, WRITE, struct_audio_buf_info_sz);
441274201Sdim  _(TIOCGSERIAL, WRITE, struct_serial_struct_sz);
442274201Sdim  _(TIOCSERGETMULTI, WRITE, struct_serial_multiport_struct_sz);
443274201Sdim  _(TIOCSERSETMULTI, READ, struct_serial_multiport_struct_sz);
444274201Sdim  _(TIOCSSERIAL, READ, struct_serial_struct_sz);
445274201Sdim
446274201Sdim  // The following ioctl requests are shared between AX25, IPX, netrom and
447274201Sdim  // mrouted.
448274201Sdim  // _(SIOCAIPXITFCRT, READ, sizeof(char));
449274201Sdim  // _(SIOCAX25GETUID, READ, struct_sockaddr_ax25_sz);
450274201Sdim  // _(SIOCNRGETPARMS, WRITE, struct_nr_parms_struct_sz);
451274201Sdim  // _(SIOCAIPXPRISLT, READ, sizeof(char));
452274201Sdim  // _(SIOCNRSETPARMS, READ, struct_nr_parms_struct_sz);
453274201Sdim  // _(SIOCAX25ADDUID, READ, struct_sockaddr_ax25_sz);
454274201Sdim  // _(SIOCNRDECOBS, NONE, 0);
455274201Sdim  // _(SIOCAX25DELUID, READ, struct_sockaddr_ax25_sz);
456274201Sdim  // _(SIOCIPXCFGDATA, WRITE, struct_ipx_config_data_sz);
457274201Sdim  // _(SIOCAX25NOUID, READ, sizeof(int));
458274201Sdim  // _(SIOCNRRTCTL, READ, sizeof(int));
459274201Sdim  // _(SIOCAX25DIGCTL, READ, sizeof(int));
460274201Sdim  // _(SIOCAX25GETPARMS, WRITE, struct_ax25_parms_struct_sz);
461274201Sdim  // _(SIOCAX25SETPARMS, READ, struct_ax25_parms_struct_sz);
462274201Sdim#endif
463274201Sdim#undef _
464274201Sdim}
465274201Sdim
466274201Sdimstatic bool ioctl_initialized = false;
467274201Sdim
468274201Sdimstruct ioctl_desc_compare {
469274201Sdim  bool operator()(const ioctl_desc& left, const ioctl_desc& right) const {
470274201Sdim    return left.req < right.req;
471274201Sdim  }
472274201Sdim};
473274201Sdim
474274201Sdimstatic void ioctl_init() {
475274201Sdim  ioctl_table_fill();
476274201Sdim  InternalSort(&ioctl_table, ioctl_table_size, ioctl_desc_compare());
477274201Sdim
478274201Sdim  bool bad = false;
479274201Sdim  for (unsigned i = 0; i < ioctl_table_size - 1; ++i) {
480274201Sdim    if (ioctl_table[i].req >= ioctl_table[i + 1].req) {
481274201Sdim      Printf("Duplicate or unsorted ioctl request id %x >= %x (%s vs %s)\n",
482274201Sdim             ioctl_table[i].req, ioctl_table[i + 1].req, ioctl_table[i].name,
483274201Sdim             ioctl_table[i + 1].name);
484274201Sdim      bad = true;
485274201Sdim    }
486274201Sdim  }
487274201Sdim
488274201Sdim  if (bad) Die();
489274201Sdim
490274201Sdim  ioctl_initialized = true;
491274201Sdim}
492274201Sdim
493274201Sdim// Handle the most evil ioctls that encode argument value as part of request id.
494274201Sdimstatic unsigned ioctl_request_fixup(unsigned req) {
495274201Sdim#if SANITIZER_LINUX
496276789Sdim  // Strip size and event number.
497276789Sdim  const unsigned kEviocgbitMask =
498276789Sdim      (IOC_SIZEMASK << IOC_SIZESHIFT) | EVIOC_EV_MAX;
499276789Sdim  if ((req & ~kEviocgbitMask) == IOCTL_EVIOCGBIT)
500274201Sdim    return IOCTL_EVIOCGBIT;
501276789Sdim  // Strip absolute axis number.
502276789Sdim  if ((req & ~EVIOC_ABS_MAX) == IOCTL_EVIOCGABS)
503274201Sdim    return IOCTL_EVIOCGABS;
504276789Sdim  if ((req & ~EVIOC_ABS_MAX) == IOCTL_EVIOCSABS)
505274201Sdim    return IOCTL_EVIOCSABS;
506274201Sdim#endif
507274201Sdim  return req;
508274201Sdim}
509274201Sdim
510274201Sdimstatic const ioctl_desc *ioctl_table_lookup(unsigned req) {
511274201Sdim  int left = 0;
512274201Sdim  int right = ioctl_table_size;
513274201Sdim  while (left < right) {
514274201Sdim    int mid = (left + right) / 2;
515274201Sdim    if (ioctl_table[mid].req < req)
516274201Sdim      left = mid + 1;
517274201Sdim    else
518274201Sdim      right = mid;
519274201Sdim  }
520274201Sdim  if (left == right && ioctl_table[left].req == req)
521274201Sdim    return ioctl_table + left;
522274201Sdim  else
523296417Sdim    return nullptr;
524274201Sdim}
525274201Sdim
526276789Sdimstatic bool ioctl_decode(unsigned req, ioctl_desc *desc) {
527276789Sdim  CHECK(desc);
528276789Sdim  desc->req = req;
529276789Sdim  desc->name = "<DECODED_IOCTL>";
530276789Sdim  desc->size = IOC_SIZE(req);
531276789Sdim  // Sanity check.
532276789Sdim  if (desc->size > 0xFFFF) return false;
533276789Sdim  unsigned dir = IOC_DIR(req);
534276789Sdim  switch (dir) {
535276789Sdim    case IOC_NONE:
536276789Sdim      desc->type = ioctl_desc::NONE;
537276789Sdim      break;
538276789Sdim    case IOC_READ | IOC_WRITE:
539276789Sdim      desc->type = ioctl_desc::READWRITE;
540276789Sdim      break;
541276789Sdim    case IOC_READ:
542276789Sdim      desc->type = ioctl_desc::WRITE;
543276789Sdim      break;
544276789Sdim    case IOC_WRITE:
545276789Sdim      desc->type = ioctl_desc::READ;
546276789Sdim      break;
547276789Sdim    default:
548276789Sdim      return false;
549276789Sdim  }
550276789Sdim  // Size can be 0 iff type is NONE.
551276789Sdim  if ((desc->type == IOC_NONE) != (desc->size == 0)) return false;
552276789Sdim  // Sanity check.
553276789Sdim  if (IOC_TYPE(req) == 0) return false;
554276789Sdim  return true;
555276789Sdim}
556276789Sdim
557274201Sdimstatic const ioctl_desc *ioctl_lookup(unsigned req) {
558274201Sdim  req = ioctl_request_fixup(req);
559274201Sdim  const ioctl_desc *desc = ioctl_table_lookup(req);
560274201Sdim  if (desc) return desc;
561274201Sdim
562274201Sdim  // Try stripping access size from the request id.
563276789Sdim  desc = ioctl_table_lookup(req & ~(IOC_SIZEMASK << IOC_SIZESHIFT));
564274201Sdim  // Sanity check: requests that encode access size are either read or write and
565274201Sdim  // have size of 0 in the table.
566274201Sdim  if (desc && desc->size == 0 &&
567276789Sdim      (desc->type == ioctl_desc::READWRITE || desc->type == ioctl_desc::WRITE ||
568276789Sdim       desc->type == ioctl_desc::READ))
569274201Sdim    return desc;
570296417Sdim  return nullptr;
571274201Sdim}
572274201Sdim
573274201Sdimstatic void ioctl_common_pre(void *ctx, const ioctl_desc *desc, int d,
574274201Sdim                             unsigned request, void *arg) {
575276789Sdim  if (desc->type == ioctl_desc::READ || desc->type == ioctl_desc::READWRITE) {
576274201Sdim    unsigned size = desc->size ? desc->size : IOC_SIZE(request);
577274201Sdim    COMMON_INTERCEPTOR_READ_RANGE(ctx, arg, size);
578274201Sdim  }
579274201Sdim  if (desc->type != ioctl_desc::CUSTOM)
580274201Sdim    return;
581288943Sdim  if (request == IOCTL_SIOCGIFCONF) {
582288943Sdim    struct __sanitizer_ifconf *ifc = (__sanitizer_ifconf *)arg;
583288943Sdim    COMMON_INTERCEPTOR_READ_RANGE(ctx, &ifc->ifc_len, sizeof(ifc->ifc_len));
584274201Sdim  }
585274201Sdim}
586274201Sdim
587274201Sdimstatic void ioctl_common_post(void *ctx, const ioctl_desc *desc, int res, int d,
588274201Sdim                              unsigned request, void *arg) {
589276789Sdim  if (desc->type == ioctl_desc::WRITE || desc->type == ioctl_desc::READWRITE) {
590274201Sdim    // FIXME: add verbose output
591274201Sdim    unsigned size = desc->size ? desc->size : IOC_SIZE(request);
592274201Sdim    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, arg, size);
593274201Sdim  }
594274201Sdim  if (desc->type != ioctl_desc::CUSTOM)
595274201Sdim    return;
596288943Sdim  if (request == IOCTL_SIOCGIFCONF) {
597288943Sdim    struct __sanitizer_ifconf *ifc = (__sanitizer_ifconf *)arg;
598288943Sdim    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ifc->ifc_ifcu.ifcu_req, ifc->ifc_len);
599274201Sdim  }
600274201Sdim}
601