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